tboot-1.10.5/.hg_archival.txt0000644000000000000000000000017314210363175014144 0ustar 00000000000000repo: cedd93279188334eb41d248d5eb70a41a2bc70ca node: 9c406d761d2ebb51ef7e762a7ed37a0664c65370 branch: default tag: v1.10.5 tboot-1.10.5/.hgignore0000644000000000000000000000155014210363175012661 0ustar 00000000000000.*\.a$ .*\.cmi$ .*\.cmo$ .*\.d$ .*\.o$ .*\.o.*$ .*\.opic$ .*\.pyc$ .*\.so$ .*\.ko$ .*\.so\..*$ .*\.tar\.bz2$ .*\.tar\.gz$ .*~$ \#*\#$ .*\.flc$ .*\.orig$ .*\.rej$ .*/a\.out$ .*/Modules\.symvers$ .*/cscope\..*$ ^cscope.*$ ^[^/]*\.bz2$ ^\.config$ ^\.pc ^TAGS$ ^tags$ ^build-.*$ ^dist/.*$ ^tboot/common/tboot.lds$ ^tboot/tboot$ ^tboot/tboot-syms$ ^tboot/tboot.gz$ ^tboot/tboot.strip$ ^deprecated/lcptools/tpmnv_defindex$ ^deprecated/lcptools/tpmnv_getcap$ ^deprecated/lcptools/tpmnv_lock$ ^deprecated/lcptools/tpmnv_relindex$ ^deprecated/lcptools/lcp_readpol$ ^deprecated/lcptools/lcp_writepol$ ^deprecated/lcptools/trousers_dep$ ^lcptools-v2/lcp2_crtpol$ ^lcptools-v2/lcp2_crtpolelt$ ^lcptools-v2/lcp2_crtpollist$ ^lcptools-v2/lcp2_mlehash$ ^lcptools-v2/trousers_dep$ ^tb_polgen/tb_polgen$ ^utils/txt-acminfo$ ^utils/txt-stat$ ^utils/txt-parse_err$ ^cov-int/.*$ ^doxygen/.*$ tboot-1.10.5/.hgtags0000644000000000000000000000324414210363175012336 0ustar 00000000000000dc19897ffffaca8f90aa3234c4eb85e12cfdedf8 v1.7.2-rc1 b911c1cdd9f294d8be5e716c5b3f55bccd977fbe v1.7.2 0000000000000000000000000000000000000000 v1.7.2 bd086f9ac6abcc4403a4fd32ce2604882025bc2c v1.7.2 221ec0974a31576ce197aa9ce793925b1cca0cfc v1.7.3-rc1 feeb4cc736710d1b6abbb6561a31737f19d10021 v1.7.3 794e9c2ef61a9a8911b9b58b2f3f3724bf3873be v1.7.4 794e9c2ef61a9a8911b9b58b2f3f3724bf3873be v1.7.4 5dabe616dbdcb6a138eaf1c00ce8c980993fc545 v1.7.4 f9bc5388f99f88d69d41fcf42acac18add9b9c98 v1.8.0 113d81b60c72510698d45324dd5c1004b1244a6a v1.8.1 9c2ee0f2d4c3554f73747a123c6fac7eeb81c5d1 v1.8.2 fa1a2d6f4812f2bec1272d5b037d92c0fe5a9228 v1.8.3 fa1a2d6f4812f2bec1272d5b037d92c0fe5a9228 v1.8.3 6a1500686f57d92ff6de0391624587ee805e7497 v1.8.3 9d8ee7ff40107fde7512b0a9196c568152ce1c72 v1.9.4 698548a9b9fe6201361d19099100f8eb59fad4f6 v1.9.5 61c17659bb8670e466c3bac8913459848f5f36d5 v1.9.6 11613463d703e203785b2e4dc9447d76530266c4 v1.9.7 11613463d703e203785b2e4dc9447d76530266c4 v1.9.7 fa126d410df0916f0bab32a882349eb401597d5f v1.9.7 dbc7b1d289f848c3d88a9d4694d67fd409f48039 v1.9.8 df8ce4ffea7cbe13a40b77d13e97a438bb99efd6 v1.9.9 9998b2fb83fd0dbef3bb84681f6b2d7d7ddb8398 v1.9.10 0f58b7162557672769d40f77f1f87bb85ee064b9 v1.9.11 0f58b7162557672769d40f77f1f87bb85ee064b9 v1.9.11 0000000000000000000000000000000000000000 v1.9.11 0000000000000000000000000000000000000000 v1.9.11 3eb9f4780f0a70460fd1a29c87f75d90c3c6b5b7 v1.9.11 931ccde2b4287cfc054e74c6d5ea2a94dcb4e5d8 v1.9.12 ffaf4680f4ba58a10ee8b1d77426921ae70c98ee v1.10.0 4cfc8a26e6373619296ec93d6a82c9cbdd164732 v1.10.1 4ae5658592ca01bb1a400a9edccbc73092b6c5f3 v1.10.2 513125987ff7aab93451b87da3fd504eeb9cfd69 v1.10.3 89db8ce6884c7763fd1e0bbf9d940cba9f33ee2b v1.10.4 tboot-1.10.5/CHANGELOG0000644000000000000000000006442614210363175012303 0ustar 0000000000000020220304: v1.10.5 Fixed mlehash.c to bring back functionality and make it GCC12 compliant Reverted change for replacing EFI memory to bring back Tboot in-memory logs 20220224: v1.10.4 Fix hash printing for SHA384, SHA512 and SM3 Touch ups for GCC12 Set GDT to map CS and DS to 4GB before jumping to Linux make efi_memmap_reserve handle gaps like e820_protect_region Ensure that growth of Multiboot tags does not go beyond original area Replace EFI memory map in Multiboot2 info Fix endianness of pcr_info->pcr_selection.size_of_select Don't ignore locality in PCR file Fix composite hashing algorithm for PCONF elements to match lcptools-1 20211210: v1.10.3 Add UNI-VGA license information Remove poly1305 object files on clean Support higher resolution monitors Use SHA256 as default hashing algorithm in lcp2_mlehash and tb_polgen Add OpenSSL 3.0.0 support in lcptools-v2 Increase number of supported CPUs to 1024 to accomodate for larger units 20210614: v1.10.2 Fix ACM chipset/processor list validation Check for client/server match when selecting SINIT Fix issues when building with GCC11 Default to D/A mapping when TPM1.2 and CBnT platform 20210330: v1.10.1 Indicate to SINIT that CBnT is supported by TBOOT lcptools: Fix issues from static code analysis 20201113: v1.10.0 Rename TXT related tools to have 'txt-' prefix Clarify license issues Fix issues reported by Coverity Scan Ensure txt-acminfo does not print false information if msr is not loaded Fix issue with multiboot(1) booting - infinite loop during boot Fix issue with TPM1.2 - invalid default policy Unmask NMI# after returning from SINIT Update GRUB scripts to use multiboot2 only Enable VGA logging for EFI platforms Add warning when using SHA1 as hashing algorithm Add Doxygen documentation Replace VMAC with Poly1305 Validate TPM NV index attributes Move old lcptool to deprecated folder and exclude from build TrouSerS is not longer required to build lcptools-v2: meet requirements from MLE DG rev16 lcptools-v2: Implement SM2 signing and SM2 signature verification lcptools-v2: Set aux_hash_alg_mask to 0 when policy version != 0x300 20200429: v1.9.12 Release localities in S3 flow for CRB interface Config.mk, safestringlib/makefile : allow tool overrides safestringlib: fix warnings with GCC 6.4.0 Strip executable file before generating tboot.gz Add support for EFI memory map parse/modification Add SHA384 and SHA512 digest algorithms lcptools-v2: add pconf2 policy element support tb_polgen: Add SHA384 and SHA512 support Disable GCC9 address-of-packed-member warning Fix warnings after "Avoid unsafe functions" scan Use SHA256 as default hashing algorithm Known issues: - TBOOT hangs when booted with multiboot(1), use only multiboot2 as a workaround 20191125: v1.9.11 tb_polgen: Add support for SHA256 Configure IOMMU before executing GETSEC[SENTER] SINIT ACM can have padding, handle that when checking size 20190410: v1.9.10 lcp-gen2: update with latest version (wxWidgets wildcard bugfix) Print latest tag in logs Add support for 64bit framebuffer address 20181130: v1.9.9 tools: fix some dereference-NULL issues reported by klocwork tools: replace banned mem/str fns with corresponding ones in safestringlib Add safestringlib code to support replacement of banned mem/str fns lcptools: remove tools supporting platforms before 2008 tboot: update string/memory fn name to differentiate from c lib Fix a harmless overflow caused by wrong loop limits 20181011: v1.9.8 Skip tboot launch error index read/write when ignore prev err option is true s3-fix: fix a stack overflow caused by enlarged tb_hash_t union S3 fix: revert the mis-changed type casting in changeset 522:8e881a07c059 S3-fix: Adding option save_vtd=true to opt-in the vtd table restore 20180830: v1.9.7 Fix a lot of issues in tools reported by klocwork scan. Fix a lot of issues in tboot module reported by klocwork scan. Remove a redundant tboot option Fix indent in heap.c Fix 4 issues along with extpol=agile option Mitigations for tpm interposer attacks Add an option in tboot to force SINIT to use the legacy TPM2 log format. Add support for appending to a TPM2 TCG style event log. Ensure tboot log is available even when measured launch is skipped. Add centos7 instructions for Use in EFI boot mode. Fix memory leak and invalid reads and writes issues. Fix TPM 1.2 locality selection issue. Fix a null pointer dereference bug when Intel TXT is disabled. Optimize tboot docs installation. Fix security vulnerabilities rooted in tpm_if structure and g_tpm variable. The size field of the MB2 tag is the size of the tag header + the size Fix openssl-1.0.2 double frees Make policy element stm_elt use unique type name lcptools-v2 utilities fixes port to openssl-1.1.0 Reset debug PCR16 to zero. Fix a logical error in function bool evtlog_append(...). 20170711: v1.9.6 GCC7 fix, adds generic FALLTHROUGH notations to avoid warnings appearing on GCC7 Ensure Tboot never overwrites modules in the process of moving them. Add support to x2APIC, which uses 32 bit APIC ID. Fix S3 secrets sealing/unsealing failures Support OpenSSL 1.1.0+ for ECDSA signature verification. Support OpenSSL 1.1.0+ for RSA key manipulation. Adds additional checks to prevent the kernel image from being overwritten. Added TCG TPM event log support. Pass through the EFI memory map that's provided by grub2. Fix a null pointer dereference bug when Intel TXT is disabled in BIOS. Adjust KERNEL_CMDLINE_OFFSET from 0x9000 to 0x8D00. Bounds checking on the kernel_cmdline string. 20161216: v1.9.5 Add 2nd generation of LCP creation tool source codes for TPM 2.0 platforms. Add user guide for 2nd generation LCP creation tool Provide workaround for Intel PTT(Platform Trust Technology) & Linux PTT driver. Add new fields in Linux kernel header struct to accommodate Linux kernel new capabilities. Fix a pointer dereference regression in the tboot native Linux loader which manifests itself as a system reset. Fix the issue of overwriting tboot when the loaded elf kernel is located below tboot. Add support to release TPM localities when tboot exits to linux kernel. Fix the evtlog dump function for tpm2 case. Initiaize kernel header comdline buffer before copying kernel cmdline arguments to the buffer to avoid random data at end of the original cmdline contents. Move tpm_detect() to an earlier stage so as to get tpm interface initialized before checking TXT platform capabilities. 20160518: v1.9.4 Added TPM 2.0 CRB support Increased BSP and AP stacks to avoid stack overflow Added an ACPI_RSDP structure g_rsdp in tboot to avoid potential memory overwritten issue on TPM 2.0 UEFI platforms Added support to both Intel TPM nv index set and TCG TPM nv index set grub2: tboot doesn't skip first argument any more grub2: sanitize whitespace in command lines grub2: Allow addition of policy data in grub.cfg grub2 support: allow the user to customize the command line Mitigated S3 resume delay by adjusting LZ_MAX_OFFSET to 5000 in lz.c. Added SGX TPM nv index support Add 64 bit ELF object support Gentoo Hardened, which uses the GRSecurity and PaX patch sets Disable -fstack-check in CFLAG for compatibility with Gentoo Linux. Enhanced tboot compatiblity running on non-Intel TXT platform with a fix of is_launched() LCP documentation improvements 20150506: v1.8.3 Added verified lanuch control policy user guide Fixed a bug about var MTRR settings to follow the rule that each VAR MTRR base must be a multiple of that MTRR's size. Access tpm sts reg with 3-byte width in v1.2 case and 4-byte width in v2.0 case Bugfix: lcp2_mlehash get wrong hash if the cmdline string length > 7 Optimized tboot log processing flow to avoid log buffer overflow by adopting lz Compress/Uncompress algorithms Added SGX support for Skylake platform tpm2: use the primary object in NULL Hierarchy instead of Platform Hierachy for seal/unseal usage Fixed a bug for lcp2_mlehash tool Fixed system hang issue casued by TXT disable, TPM disable or SINIT ACM not correctly provided in EFI booting mode Fixed bug for wrong assumption on the way how GRUB2 load modules Fixed MB2 tags mess issue caused by moving shorter module cmdline to head Fixed compile issue when debug=y 20140728: v1.8.2 Security Fix: TBOOT Argument Measurement Vulnerability for GRUB2 + ELF Kernels fix werror in 32 bit build environment 20140516: v1.8.1 Fix build error "may be used uninitialized" Reset eventlog when S3 Make new Infenion TPM 2.0 module work Update tboot version to 1.8.1 in grub title Fix grub cfg file generation scripts for SLES12 Fix seal failure issue tpm2 lcptools Restore local apic base for AP Fix typo in hash_alg_to_string() Change to create primary object only once Add prepare_tpm call in S3 path to ensure locality 0 was released before senter Fix possible dead loop in print_bios_data when bios_data version==4 Fix possible null pointer dereference in loader.c Fix possible null pointer dereference in tpm_12.c and tpm_20.c Avoid buffer overrun when append tpm12 eventlog Fix possible NULL pointer dereference Fix one event log issue caused by wrong append and print operation Fix error "unsupported hash alg" for agile extend policy Fix warning "ACM info_table version mismatch" Update the tpm family detection with a general way Fix a lcp tools issue caused by redefining TB_HALG_SHA1 from 0 to 4 Assign g_tpm a value for no tpm case to avoid NULL checks Fix crash when TPM is missing Fix infinite loop in determine_multiboot_type() Fix typo in tpm20_init() and remove unused variable Allow the to-be-measured nv to be protected by AUTHWRITE Check cpu vendor id to avoid unexpected behavior in non-intel cpu Change to detect TPM family only once Fix some typos caused by copy-paste 20140130: v1.8.0 Update README for TPM2 support tpm2 support Adding sha256 algorithm implementation Update README for TPM NV measuring Update README for EFI support Fix typo in tboot/Makefile Increase the supported maximum number of cpus from 256 to 512 Extend tboot policy supporting measuring TPM NV EFI support via multiboot2 changes Fix typo in common/hash.c Fix verification for extended data elements in txt heap 20130705: v1.7.4 Fix possible empty submenu block in generated grub.cfg Add a call_racm=check option for easy RACM launch result check Fix type check for revocation ACM. 20121228: v1.7.3 Update README with updated code repository url. Fix grub2 scripts to be compatible with more distros. Update README for RACM launch support Add a new option "call_racm=true|false" for revocation acm(RACM) launch Fix potential buffer overrun & memory leak in crtpconf.c Fix a potential buffer overrun in lcptools/lock.c Print cmdline in multi-lines Optional print TXT.ERRORCODE under level error or info Fix side effects of tboot log level macros in tools Update readme for the new detail log level Classify all logs into different log levels Add detail log level and the macros defined for log level Fix acmod_error_t type to correctly align all bits in 4bytes 20120929: v1.7.2 Add Makefile for docs to install man pages. Add man pages for tools Add grub-mkconfig helper scripts for tboot case in GRUB2 Fix for deb build in ubuntu Fix S3 issue brought by c/s 308 Fix a S4 hang issue and a potential shutdown reset issue Fix build with new zlib 1.2.7. Initialize event log when S3 Update README to change upstream repo url from bughost.org to sf.net. 20120427: v1.7.1 Fix cmdline size in tb_polgen Add description for option min_ram in README. new tboot cmdline option "min_ram=0xXXXXXX" Update test-patches/tpm-test.patch to fit in latest code. 20120115: v1.7.0 Print version number while changeset info unavailable Document DA changes in README Add event log for PCR extends in tboot Follow details / authorities PCR mapping style in tboot Support details / authorities PCR mapping Support TPM event log fix build issue for txt-stat in 64 bit environment. update README for mwait AP wakeup mechanism tboot: provide a new AP wakeup way for OS/VMM - mwait then memory write Original txt-stat.c doesn't display TXT heap info by default. Add command line options to display help info and optionally enable displaying heap info. Fix a shutdown issue on heavily throttled large server Adjust mle_hdr.{mle|cmdline}_{start|end}_off according to CS285,286 changes to give lcp_mlehash correct info to produce hash value. Fix boot issue caused by including mle page table into tboot memory Fix for possible overwritting to mle page table by GRUB2 Add PAGE_UP() fn that rounds things up/donw to a page. Update get_mbi_mem_end() with a accurate, safer calculating way ACPI fix and sanity check Add some sanity check before using mods_count in a count-down loop TPM: add waiting on expect==0 before issue tpmGo txt-stat: Don't show heap info by default. Exchange definitions for TBOOT_BASE_ADDR & TBOOT_START Add const qualifier for suibable parms of all possible fns. fix possible mbi overwrite issue for Linux with grub2 enhance print_mbi() to print more mbi info for debug purpose Fix for GRUB2 loading elf image such as Xen. Move apply_policy() call into txt_post_launch() Don't zap s3_key in tboot shared page if sealing failed due to tpm unowned Update the explanation of signed lists to make it clearer. tboot: add a fall back for reboot via keyboard reset vector tboot: revise README to explain how to configure GRUB2 config file for tboot tboot: rewrite acpi reg access fns to refer to bit_width instead of access_width tboot: change reboot mechanism to use keyboard reset vector tboot: handle mis-programmed TXT config regs and TXT heap gracefully tboot: add warning when TPM timeout values are wrong all PM1_CNT accesses should be 16bit. Enlarge NR_CPUS from 64 to 256 Add support for SBIOS policy element type (LCP_SBIOS_ELEMENT) to lcp_crtpolelt Fix processor id list matching between platform and acmod Make lcp_crtpollist support empty lists (i.e. with no elements) print a bit more error reasons in txt-stat Fix segmentation fault in txt-stat on some systems 20110429: v1.5.0 Fix build errors under Fedora 15 Various cleanups to output and checks to make it more readable Removed PAGE_SIZE/PAGE_SHIFT requirements from utils/* Added definitions of PAGE_SIZE and PAGE_SHIFT to acminfo.c Fix display of TXT.ERRORCODE values Added Developer's Certificate of Origin 1.1 to README Add support for TXT heap extended data elements and BiosData version 4 Removed some fields and changed names for some TXT configuration space registers Add support for AC Module chipset info table version 4 (ProcessorIDList) Separate AC Module subtype field from type field in ACM header Fixed error in description of what is extended to PCRs 17, 18, and 19. Fix tboot Makefile to make object files explicit in order to avoid incorrect ordering Removed no_usb command line parameter and SMI disabling Fixed bug with PCONF elements not displaying correctly Support MAXPHYADDR > 36b Reversed and rewrote c/s 225 for wrapping tboot policy in LCP custom element to store tb policy in the LCP PO index. Added the log level support. Clean up build Trigger TB_ERR_S3_INTEGRITY and don't call verify_integrity() if a measured launch is not performed on S3 resume. Then the policy decides whether to continue unmeasured S3 launch or not. verify_integrity() should be called after TXT is launched on S3 resume. Continue to fix the error message "response size incorrect". Add checking whether a given index exists by its public data in TPM NV, because the original "response size incorrect" is not clear to describe the error message. Make default parameter values for command line parameters consistent with the default initialized values. Fixed to support offsetof definition for gcc 3.X and below. Moved utility binaries (lcptools/*, tb_polgen, utils/*) to /usr/sbin to conform to convention for non-critical system utilities Re-licensing tboot/include/printk.h to BSD Fixed a bug in txt-stat. In tboot_log_t, char *buf will occupy 4 bytes on 32bit system and 8 bytes on 64bit. Both sizeof(*log) and offsetof(tboot_log_t, buf) cannot get the accurate position of the log memory, which might cause some characters missing in the log printed by running "txt-stat". Removed end-of-line CRs from README file Moved definitions of tpm_pcrvalue_t and tpm_pcr_composite_t from lcp2.h back to pconf_elt.c, sinc they are only needed by pconf_elt.c Fixed the bug in pconf creation. Pause when transferring to VMM/kernel and SINIT by GETSEC[SENTER]. Again, clean the code and fix to see the first few lines of tboot output and sync-up serial port output with vga output when pause. Fix the compile error for c/s 225 Use LCP_POLELT_TYPE_CUSTOM to wrap tboot policy, so tboot policy is allowed to be stored in the LCP index and be signed, etc. Additionally tboot code unwraps the policy from the PO index. Change to use time-based timeout instead of counter-based timeout for tpm_save_state(). Fixed option values in tb_polgen Fix build error in lcptools on systems that don't support 'ehco -e' Change serial command line option back to original format Removed htobeXX() fns because not supported in older glibc Fix build error (on some systems) in lcptools Fix print_mbi() to have more useful and properly-formatted output Disable legacy USB SMIs by default Fixed bug in creation of LCP_PCONF_ELEMENT Fix build errors with gcc v4.1.2 Add timeout ot comc_setup() and don't re-initialize serial on shutdown Added additional compiler warnings and cleaned up code to build cleanly Merge Fixes support for PCI serial cards Fixed buffer overrun errors in lcptools/ and compilation error on some systems in utils/ Fix build error Improve efficiency of div64() All non-BSD compatible files rmeoved and functionality replaced by BSD compatible code Fix bug where some e820 configurations would case recent USB-related fix code to reserve too much memory Fix S3 resume path to not call copy_e820_table() Remove SINITs and LCP policy data files from module list before modules are verified and measured Fix issue where tboot would appear to hang after SENTER on some BIOSes (due to DMA protecting legacy USB buffers) Fixed build inconsistencies Always extend PCRs on S3 integrity creation/verification Added support for 'vga_delay' command line option Fix bug in TXT.VER.EMIF/FSBIF handling Fixed debug chipset detection Fix for changed defn. of is_acmod() Add support for choosing correct SINIT ACM from multiple loaded modules This patch is to clean up the code by clearing all blank spaces at the end of This patch changes VMAC_NHBYTES from the standard 128 to 4K in order to improve the performance of MACing. This patch adds pae paging support into tboot for tboot to access >4GB memory during S3 MACing. Walkaround for pvops to read public config registers. Explicitly link lcp_mlehash with libz Don't write to tboot's launch error index if it doesn't exist Merge TPM timeout workaround Workaround for TPMs with incorrect timeout values This patch reimplements memory reading by lseek()/read() in order to fix mmap() issue which causes dom0 hangs under pvops. Added dependency to give "friendly" error if trousers is not installed Fix build error Add support for LCP v2, as defined in December 2009 MLE Developers Guide chapt. 3 and Appendix E Moved acminfo and txt-stat from txt-test to (new) utils directory and added parse_err utility Removed trousers sub-project Update for latest TXT data structures and GETSEC[PARAMETERS] type Handle case where BSP does not have APIC ID 0 Support TPMs that return TPM_RETRY for TPM_SaveState command Fix one more '&' to '&&' ocurrence. Fix bug with '&' instead of '&&'. Fixed a timeout bug in 163 Added text that repo chnages are sent to tboot-changelog@lists.sourceforge.net mailing list. Updated README about e820 table memory types used. Updated README with the fact that TXT support is now part of the 2.6.32 kernel. add gzip lib to fix build errors Fixed "Handle page table addr in ECX", some SINITs are not fully ready for this. Fixed overflow check in folder txt-test. Add MSEG verification. Continue to fix build warning on ubuntu 4.3.2 Fix the build warning with gcc 4.3.2 on ubuntu 4.3.2 Check the return values from some functions. Check overflow for uint32_t, and some other types. Before checking bios data, check TXT supported Read real TIMEOUT values from TPM and set timeout Handle page table addr in ECX Fix the potential segmentation fault in find_mle_hdr, Changed mechanism for initializing VMCS controls; changed license to BSD Copy LCP owner policy data (if present) to buffer in os_mle_data Create common fn to determine end addr of tboot; don't set boot_params->tboot_shared_addr if launching Linux w/o TXT Fix locking for AP wakeup and WFS If APIC ID of AP exceeds NR_CPUS, put AP into hlt loop Increase NR_CPUS to allow for discontiguous APIC IDs on some systems Update spinlock.h with latest Xen code Reserved tboot's memory as E820_RESERVED if launching Linux; fix tboot image size Clear key from memory even when seal/unseal fails Fix bug in tpm_write_cmd_fifo() when tracing TPM data Ensure that memory region chosen for initrd is large enough Changed passing of shared page for Linux to use new field in boot_params This is a test. Fix bug with calling verify_modules() on S3 resume patch Added -Wformat-security to Config.mk to catch additional errors and fixed resulting warnings; also fixed some warnings that are generated by gcc v4.4 Fixed bug in tpm_seal() with setting of localityAtCreation and added fallback for tpm_get_random() Remove SINIT and LCP data modules from mbi structure when not doing measured launch Do TPM_SaveState as last TPM command 20090330: Added s3_key and num_in_wfs fields to tboot_shared_t and rev'ed version to 5 Use VMAC as S3 integrity MAC algo Changed tboot load/start addr to 0x800000 (8MB) Fixed support for newer Linux kernels Support TB_SHUTDONW_WFS shutdown type for APs Misc. fixes 20090130: Fixed build issues with newer versions of gcc (e.g. in Fedora 9) Increased CPU/core/thread support to 32 CPUs/cores/threads Simpified tboot build process to be that of standard ELF binary Enhanced logging support (see README) Include tboot command line in its hash; support for including command line in hash added to lcp_mlehash Always extend measurement of module 0 to PCR 18 Added verification of memory layout on launch Set VT-d PMR protections to cover all usable RAM Misc. fixes 20081008: Fixed build error in lcptools/ 20081007: Updated README and doc/* files Fixed support for in-memory serial log Fixes and enhancements to txt-stat Changed policy format (see doc/policy.txt for new command syntax) Added support for launching Linux kernels >= 2.6.20 (Linux kernel patches will be available on LKML) Fixed build errors under gcc v4.3.0+ 20080609: Removed support for Technology Enabling Platform (TEP) Removed support for SINIT AC module versions <16 (i.e. <= 20070910) Updated per changes in May 2008 Intel(R) TXT MLE Developer's Manual: Updated to MLE (header) version 2.0 Updated OsSinitData, SinitMleData structs Updated AC module InfoTable struct Support Capabilities fields Support MONITOR-based RLP wakeup Added acminfo app to parse and display AC module information Updated for v3 of BiosData struct Reduced TPM-related serial output Fixed sealing of hashes for restoring PCRs after S3 resume Misc. fixes and code cleanup 20080523: Updated TrouSerS version to 0.3.1 and to download it from its SF site Fixed several items regarding TPM: call TPM_SaveState in case launching kernel that does not, so that S3 resume will restore SRTM PCRs support for TPMs with an Idle state fixed timeout values per TCG spec enforce that TPM is activated and enabled (or fail launch) misc. fixes Fixed failure paths to apply policy Enhancements to and cleanup of policy support Cap PCRs on exit Added txt-stat app to display TXT config registers and status info S3 fixes Added 'loglvl' command line option to control serial output Handle unordered and overlapping e820 tables Misc. fixes and code cleanup 20071128: Added '-f' command line option to lcptools/tpmnv_getcap to display the TPM_PERMANENT_FLAGS and TPM_STCLEAR_FLAGS contents Revised the docs/policy.txt steps Code and build re-factoring and cleanup (default target is now 'build') Make memory logging build-time optional and disable by default Support >2 cores/threads Move tboot to load and execute at 16MB (this also now protects it from dom0 access since it's memory type can be E820_UNUSABLE now) *** this requires a patch to Xen *** The Xen command line shoudl have 'no-real-mode' removed and 'vtd=1' added (as indicated in the updated docs/tboot-info.txt) setting 'vtd=1' is optional but some systems fail to boot dom0 otherwise *** setting 'vtd=1' will cause S3 resume to fail *** Updated trousers sub-directory to download 0.3.1 version from TrouSerS SourceForge site and build it 20071029: Moved build_tools target into top-level Makefile Put 'tboot=0x1234' (where 1234 is the addr of the tboot_shared data) on VMM/kernel command line, per latest Xen feedback Changed TB_LAUNCH_ERR_IDX to 0x20000002 Made TPM detailed debug output conditional Changes TBOOT_S3_WAKEUP_ADDR to 0x8a000 to ensure no conflicts 20071026: Initial version. tboot-1.10.5/COPYING0000644000000000000000000000326114210363175012112 0ustar 00000000000000Files which do not contain any copyright information are assumed to be copyrighted by Intel Corporation under a BSD-3-clause license. All other files contain their copyright and license at the beginning of the file. BSD-3-Clause license -------------------- 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 Intel Corporation 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 OWNER 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. tboot-1.10.5/Config.mk0000644000000000000000000000405714210363175012621 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # global build settings # # supported targets .PHONY: all build install dist clean distclean mrproper # Default target all : build # debug build debug ?= n # for dist targets ifdef DESTDIR DISTDIR = $(DESTDIR) #else #DISTDIR ?= / endif DESTDIR ?= $(ROOTDIR)/dist dist : DISTDIR=$(DESTDIR) # # tools and flags for components built to run on build (host) # # cc-option: Check if compiler supports first option, else fall back to second. # Usage: cflags-y += $(call cc-option,$(CC),-march=winchip-c6,-march=i586) cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;) CFLAGS_WARN = -Wall -Wformat-security -Werror -Wstrict-prototypes \ -Wextra -Winit-self -Wswitch-default -Wunused-parameter \ -Wwrite-strings \ $(call cc-option,$(CC),-Wlogical-op,) \ -Wno-missing-field-initializers -Wno-address-of-packed-member AS ?= as LD ?= ld CC ?= gcc CPP ?= cpp AR ?= ar RANLIB ?= ranlib NM ?= nm STRIP ?= strip OBJCOPY ?= objcopy OBJDUMP ?= objdump ifeq ($(debug),n) INSTALL_STRIP ?= -s endif INSTALL ?= install INSTALL_DIR = $(INSTALL) -d -m0755 -p INSTALL_DATA = $(INSTALL) -m0644 -p INSTALL_PROG = $(INSTALL) $(INSTALL_STRIP) -m0755 -p # # tools and flags for components built to run on target # TARGET_ARCH ?= $(shell uname -m | sed -e s/i.86/x86_32/ -e s/i86pc/x86_32/) CFLAGS += $(CFLAGS_WARN) -fno-strict-aliasing -std=gnu99 # due to bug in gcc v4.2,3,? CFLAGS += $(call cc-option,$(CC),-Wno-array-bounds,) ifeq ($(debug),y) CFLAGS += -g -DDEBUG else CFLAGS += -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 endif ifeq ($(TARGET_ARCH),x86_64) LIBDIR := lib64 CFLAGS += -m64 else LIBDIR := lib CFLAGS += -m32 -march=i686 endif CFLAGS += -I$(ROOTDIR)/safestringlib/include export CFLAGS # common dummy rule to force execution .PHONY: FORCE FORCE : @: # do nothing tboot-1.10.5/Doxyfile0000644000000000000000000032337314210363175012576 0ustar 00000000000000# Doxyfile 1.8.14 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = TBOOT # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines (in the resulting output). You can put ^^ in the value part of an # alias to insert a newline as if a physical newline was in the original file. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 0. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = NO # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = ./safestringlib ./lcp-gen2 ./cov-int # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via Javascript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have Javascript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: https://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. # The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , />stream xœí{ xTÕÙð9ç.3wÖ;3™É$“äÎd&ëL˜d&{€ Ù $$²’!¢D• !²\@ÁÈR—jQúW'.ŠûuñÓÒjµhmmë'¶jAñµO!7ÿ{î$mÿ¶ßÿ}ÿóôžÞ“sæœsÏöîï{f‚0BH6#ÕÕ6øHyòî‚ba×µ}‘vΛáouݰιе<:~ íÿ\Þ·âÚþòO<‘×â^\±jÃòÈxíïJüSϲÎîŸý6f>B…ðåö@‡Õ©]‡š®ïé¹vÝMû}k¼¼juWg¤=ím„øË×vÞÔÇ“U0þièt^×yí²‰ñ°Šé[½v]¤]¦ïûÖ,ëûÍÆw_‡ñp^Fà£Îõ:’&Ë«¶ ¹éçø{Jùîd]îÿý=ê‰ü_yðë$í¿»/¾oÛq#¾_‹×ã•8„»p3”[¡µ=® z}„80ÆnlÂ*t 'áxlÁ,Ò@ûŒ¹¨Œ<¬”q!úœ(ØB» ¿ˆÞDgÑy$c:i¤£èAÔ„špNÁxúVƒ±Ð:c^†9¿B¿G°·àð¾‡èÉlÒãì¸ï$sÉ%ÖƒTøFbÆ+˜çðEÌc+ö çÐOÐ;LxüCüú“AžB7¡ôÎÆ!æ&‘Èëä„B…ùy¹9ÙÁ@V¦Z†Ï›ž–š’œäq'ºœRB|œ#6Æm³FYÌ&ÑhÐë´A­â9–!ùpØ^Ú4£ò:\.WsÆD;öëí0“$þ§+ŒÌ_äøÆ¤¸o´ã¿ÑN˜jÏ £¨p…»´Œ.<‚*~F–0Ž #º ¶Ì…&&•w÷ºËW†cJ»;:`F™[t†+.ø'Ž¢¬=¢Õ”ºK—i2|hD£…ªj0¶oWÌÄJ…T”ޤÖgøÂfo˜$•ÓÜíꀊ» V‚7–+oŽî¾ú‚i“5K¤†Ã|iX¥ìë\u†Ñ.çˆoth÷q-íðêºÝÝ‹spÆÄ$•÷4R<–ÓÜÑã ³°¸R8 ÇYÞãrSt”÷t@é.ƒYµº…Ò¦í®QGØ Ÿåa“7<FÌî?ë`†Êí+´94´Ý~`~ÓÕo]´lnn¶Ã‡Êݰ ,VÞ[ Øý¾Lèîè¥{övÒs–÷:‡v-Sκ[9ƒ2´¼Óù÷F •w»Ë»;»K"«—†CÊjliRÔ•5OtM €7¬ò¦£¬ÙAvu}S)=˜»³Ì!ûTOÇDt”O¾tÒTÂag—3Œê›Ü04ŸËòÑPW¾Â<®f ³ê®Ì sI¢Û9ô ã÷ùs_ïéœèá“Ä/­V¸+:††*ÜΊ¡Ž¡Îãã›—º¢{h¤ºz¨¯¼v­k‚YÇÇŸÛåWìn‹=¸pO9 ¢¾©Øá25O6ë&›X K«€X€¿Ê‰À2jlr9Q šš€§&Zo„zä“20n>ÐxmGËò§ÐS:Qu¹(wî:BK¡Þ<¿)Òv¢¥Ž'QÈïztÐ7£“o¬ è›Í“o¦¦w¸a—§5¨Ö°:yêÏ(Ú,å=…alû¯—EÞ‡-¥MŒƒ4GjÄÁÐšÆ ’>=í…zªwˆðš;,zÃ\Ó¨cz³S4 ÔkpWÏoir–MqA¤gRÊÀêîΞ¡ Q¢Lª dÄwÌ á -M'D°¤;›ž$˜”v”4xà]Ó '¨V¥—LõÒ–“¶P5eÀ'‰Zyå8Bh³ò–U:”v×qŒ”>õdF]ÇI¤OTúà×ð£ÖÊõòÇ{/­Ò?ª`ìêçIÚÃlBK õ H!´<ˆ§ÇÇÁÁ!¡ñÃ?x¤?üÞ$ „ºÏèÄÜÐ/ñ[{MÒiÈ?ü*äW ÿ;ä— ?vÐ#‚|à Sºï`ªtp¯CúlØ*Ž‘îN—ö'Iû ÆÃ0ÜøŸøž½1ÒÝ{½Òž½. íÅt£Å{µb®ñ¤tÒ’ñ?Ñ ñ1ÜÏ`çŸþDįœ_…¾b¾ÀâEçEâü¤îâ?W|®ö“ù‹¾_§žL•ž|Ê$ùŸ*~ª#Üî{“ûà¬Gz²ÿ,Ýà©ï t£ñ§¡òóiÒë_pJ?0I£_„|ç©ñSÄøÜ]ÝÐî‹oh宸fä…gíºµk×zÿψ@wï®/ùˆ¥§3ü‘»läããþØ]†'¦^½TaÑ©Väïªy×+ýëþb;e•BÅG…xøˆz–',¢ÙúÝÓJ‘•é2¹LIP`õçͺD?T¨4^Gxf%“ ³ãB"~‹ˆ¨ä ?WË‘6Ð߆üç³21ÌgVŽqäá±æ= c2ðN˜ç™È/1z áZÜŽWãÌaÛyeZ6¹H†<®àN˜€úÆßãBܧ(|óòPV9)×TªlëÈ:ÍFÃF›Úq°Ð\e&f•ë`_Î>ƾSÑI ;‘ë`]S.^Üvþ²2ÛpQ°;19%™äd›ófâ`Àm3sb²;‘7‰¶` — •Í©úðè‘s•U%eUUçþî‡U•%ò¦Þ{WmذŠ|tR~«½³«{éRì>ù}œÐµté²î¥ò{'±áƒä òW §Àm°ç¸_ #Ê IÜc<æyo`aã£aˆáÈ£ˆ)fV3 ão»Ïˆg‘,PLÏÁ†É•È…SæA=w9Ê?š3èËÎfq5b–±|n²ÆÔM¿ä§pŸ€È¦ŠûÅ£]¡LÃÍz1˜¢L.}’)[ŸmšmZhZj]gÕ b4jﳨHÜÜ:âúP_GU‰MóŠ#ê›mØfÛ-‰"° ñ·ýâ—p(sAÐïmSÎx>è/ml 9ŒDk—ˆÃî'^{‘½ÊÞʵگ᮱DëÛš)ƽi8'×0ädS«Ü¦\OÐÉZ£x „ÊÅU]Z½ ëçoX¾uãâW9gcë.pþ“oßÓz<…þ²óÚõ/X¾º¦WK3ÿøÖíòöÆÛã(´»;ÜÜÐöûC} ´~ZhµLÀ¡5¼Úibâ4w P[hÌž–ÈžQ©­”Ϙ›µócê§wã^mwLgþ ¸_».ß1sF¡ K™™¾û$![¥×›îb’‡ k¥v‰HYÑ;³¤Â¬ŽaJ"¬œeŽ.8ï÷·ùÁÅæ(K Ü^ˆ{"Pº=)¦`ðZn)Ó°›®nNaØ12Íš€ÙãY… ßè„üUCÊÂO» wø“|Ó³²†ŠêÌ»)Ýç›æNéM^òëIõ8vÏío–×׸%¸†<—Þ×¶òجâÒBž]cqÆÌ.5Û(2X£1[Šgdä‰fݬ¸Ô5#+-k÷’›ÿÍaP¥ƒÄ5Ž_æÚ!:Ö =Zš›¦Â¼Þ¦÷«ªTúfU£~•j¹¾_µ^¯ÕÕé;ô}zFÏó*^Àúƒµ0o€c8ŽQñL­¦]C4*AÇîÒ`l”x?§‚² `'@µ`KADfx»øn;ŠÛÚ°›²¼ ÔGJ®ýUyϘŸœÀÛ_û‘\‹ÉàVËt\ÞObÇ~<ð0ð@:œ×‹úBó´ ùÕu†:CdŠÔEº iS©žeªŠnR7¤¯ToP‹ ±“$ó¯Ñîãcœ‰»¤Ö”'EítJš(Ð ñj”ãlj½çýSÞ÷+äÅÒNÃAÚ-kD½$`.}QÃâOï{ê«yé­?ï)¾Û›èö'åÏlyd¦uUHíž/U´.ÇZ÷ãÙ5•8/WæÎ‰O–B¥ÙÕÑ.«ddæÈïNzÞ3T3n¸çpçQšzCÕ™BP“™J5³òëâêÜ <Ý K³ÖjÖÖ‰kkâÖæ™ãyÿ!§Í{ÐÉ›UE‡ø˜ø›M—ðŠT‡ç|MgyÌ5À SD(ê“ÿšúŒð«ÉyZ|5"¢xkí¤ŠuNcÍü_ܹíÝÚÖŽ–åKqÁÛ•Ç&;n­=c›ûÝ®EûB Ýr””žäYšíëH%Yiq5>W¾´ö•òªy•Õ ±øÂpæú¾›£8ùWz×ÉG§¤ú  ïNl««l‹‹³F5ÓÜïO—â€;>ôwðhn(“Áï"„¡¾&s€ã fP5i%$“ZÒNV“„'` ‘±˜H80iððëX MaÕóÛG좎óŽ-‘ÉÉ1†½“}ìÒ"öi®kü7Ü\îs‡¦n -`Ò¢Ò‚öY³ìs³q»¦ÙÔîhö-Éj,h,îUui—™–Y»×n6¬³®‹éØyâÏÉô…| ¾öœ¥¾5¾uŽ.ÖÇ2ÎC ?d£êZŠqäÙl(G/úwÆø&èX’¼Só‡$ @F`aJNàbSAÔ¼TWŸÍÕFÕ·Í( T˜@Q §,ò ¦±i>§É\ÐF³¢À£XW"¥fNvn^ýð¸"ê4ŽètŽ9z&¶(”OQz"BÁÍ•ŸßyäÜܚʭnéÇs° Gá‚Á‡öË]ë;=ÕR|riM\gù´TiNŸë¯·|ßMÎ…’LJøÑå²éEßjíûÞ,~ú±›Fþãôw{¿SȽLRkZÌ&Sž»¨Ä¥sÛrŽÝ2§*ÓèSV—÷l´DEϤRÒ3þ>h‡O)é•$N÷LO«J¬ôT¦µˆ-ævk{l‹cIá5…ëÈn“±?õæBs”3ÿP´ïP4ïTz8ÈÇD% B|2HIq`g¼‚ÍIÙ¹P4¤lÏRÙ¸¢ò"ÂB‘†\GcJ0&qFGfçréK{å½^õ¿© «;æíÏ-ªÑ/Ú·ºñ¾â†.<v½5¯u±|«?-¾&=e¶KJIOr·çgôÆ3ÌôçåS×Ýx£Y…“ ΔôŒííœ4oÑKwŠ3@hä/·÷ö:ã.gÏœŠö8‡-Z§M£øyŠEl—â Æ‡Œø—„ãÉ©xôZ-ÆXQÏà—O8t4‘EÔ;£™¼ƒw^:Œkàù:ð;‚hÛ ä| ô°õxäÓt|üû¡‚.Ï? u¼=ÞÍ$³ij¿àw»›I3»HӷгžéŒ~K±eµeÀÂZ,±{t¬3#3£#£/ƒÍÈHÞƒ,–Œã9(§6§=‡qnâŸÍ/žo¿ (ª¹M)€ `v½^ îÕ 8“*©¿‚y QÐ~ˆ3íß‘ÿ°lÙêÞeX:ºäÞPéµi¾¸¹y›+çïYTY;}ÆþÊŠ…YŽÔüåù•›ã—vvâÄS#ع¢k•ÕdñGÉ÷ÚKœN_°¨àä¶Ý'sóüéžø»|(Æ'Zm€§Sà~úH‹f‡b…=™|ˆïàû ® óð`na4{°šŠ¶Q´æ©Y5Bz^ÀÏèÄ/ÇÔ|‚+$Q¬ç¤Iìç—^esÆ*ÉmcɳÜëòïäqÈw¡‰?‚TŠâöd’é !*¼GͨÑ=M‚¼?­_[«%„P=£¡»R5è úANnНlùÑXÙ8v›¼…õ²#òåß Â.m„ã}Ò‚P¢ÀÞÍ3æn¬Ö>¨·÷AÄ`†Ñë$}¦>^K•â] (ÞåX@-h¢vÔm 2ï_¾x‘é¹x«™—°ZþÓåâI¸.À>r‡¢Ãîç¿õG# xãÅ/ýGq6‰-öÂ¥ŸâÍäIîõKµkðoÁ:ôÌ ÄJ€mÙâJ:´^-ƒƨ…8¤Mf|¬_ã×iŠ´µB¥¦_;( iïîÕÔFåjš5d€c5qs·YN8-8¢a?[Ìv°},ËÒvèfµˆeT£Ò @Ç È€9xù,xâÜÕ3zÀÛF¡PŒèmpÀ¡ÌÊ„ˆ® \&/ø×à0)]âß’·Èçä¯ ïǧ Æš‡O1Œm Û/;¸×Ǭä ÷+Æßã—ƒç¬Uâª@ —¦JÓöá> ù€VeÝ«b…tX×^ޱ2I XŒ›Ðñ¤â$ìÉó(’wñê¸JD.'2)å×ÌÿU²Æ/—{äaù>¹ãx9> 3ù¹3ÁÛæTÞš(žl«ªÚF>”ÉmøÛ¸=(·9ËNlÚv²pznöôün¹íù¢¢üª½€nÜ. ›ˆ$§˜q¹q=ËÄìU©û^@¶iS!ª‚qÖÖk»$WÈEbTÂ3NñâkÓØSaíóSŽWÁfÄsûº³Îíª˜Õü«o*o&7ÝñoÕ-íòÚ²ŒékÚK®[:àMr1—º_œÕÔ"ª³²ŠŽ·šíœ\b÷8›)§ÒåªáÄ*ä Åbv‚׊¸Öð7XA- !a@`"Òpvì¬âu\‘7®ZöË›e?—ÈŽ\ªeG”Èú1ðÏÀš&”J2©ÝÞ¦œYOI&l6Ýe"&“%dÁꤺSu¿ŠQ ·] ‹ƒ°¾B¶ØF1Ù9°Ó9,Ÿ€4‚·lÙ{×mx qG½ƒ“±…yörûÁá½2"<~A~ˆ_òf:†_ïƒ#~UŠšÈqq£Îä^“zè°pü?ØgÙ­g¢å¡ÙF;狱Wr•qÍ\sÜ5ÜJã5q7$­IëËÐãÏ$ÉkK éy))î#^QÄfË”pæ ÿ¹€?€©R*IMU Æ<Ÿ¢°´QM „¤VÙkš$gŽ¢Ú§X0Zi‚I¦¾ ¥ßIM.¦¾ò¨/·@g•å®N_˜œ³¦ì·¯[ÖSï¾§ùŸ«ã[!ô6ÉqÒǼÕ`š•ãöEEY|C¶™f{ôl<æJàÛf›°Ñ˜öÂ+c,Щ  ¿žÝ‚RÐŽ;“)Šb²!¦œ­Q×51eŽj©UºFºÙiHv‚^ˆ:>~†šOÃññß…¬Ð!†@#dŠX£ïÕ‰ÅìQ<@èôxâïE6yDÏ€‡ñøÓ°'­# ÇnåŸO¥‚j ¶A¯XIoÄLz#Úƒ›rë"žû9å»)Æ‘|~÷ç-ÍKW.iýdóÚï7­EÞ´¥³î:xÿÞ²k=‰Ù¶à‚ ••¿Ùwølõì’@ª|Úœm‹öðCJÖ(ŸU>êú·Œ¿Ç~ÂG! r¢™¡Ô*MUìõ"ãL('ÚŒì÷Dœ°Ÿ³™¢È z.ѱUý¼ @ˆ·ø<%/=z[%¬;‘˜®œ4àUGg?‘‡Ûê=ýeܲïw.»µ ƒêIntßqÇš[²®[_3OǺ;ß­­nðºðo.%’Ñ0rø‘}IpNJ©Ëì6dþºPƒ‡x5A2]SJærs5¥†±…kÕ,p¬ä¯:¢:¢Áw ÊŠŠÂŸÅÅébŽ˜E¤Õ ê.õZ5§V³Ã:› ØÑɎÃÆçã³ pý“¾Ë$¿º"^ ź{RŸš’"ª”½|ùeõ‰§×œ™™ÚÿöVùqy/ÀiØŒ£äLo_Ï65þtpw½_þm–gâlÃå`’//¸~ͪ½`“·ð ÈŽB!ØÍa+Öª GLF½FƒP¬1VŠ%j£Ú¤4¶ëW뉸<@¿(@AA±þâHÄ]Vª™Ü9Aà"Jf‹Ã>××[mò—òð¿úMÝ–§S™k®.^Þì¾(ýô§ZrƒÜÌ~ò ^ã‚Pþ<Û¼ŒyÁ6[[p¥­7¸Iݯ[ïîj­»÷^—˜lÌÚowü^>Nž+pGδ­Žç³Aü©&‡ì<Å&uÈ“¦‚Õ+ù L{оÉû&ß´ÌŸÿÁ]ëßo𕜪îÞä’âf}«óÜ8š7»ä¥e­ûfèq›<,µxî¸cù=·~ëí3óâ¢pL¬7)ÑÙ]aÍ™ 4NÜõJuÅéLÑ å‹¼ *úùûLÜPE˜èª—ìEy¿Úl®,ÉéN¥çl;ºbõÑÌU?Yzìy¿Êlª*ÍXÈÄ]>K²ê×z<.¯ýòY¶ëæÊú®ŽÖžwN%‘¬†5Ð/Mq=@÷×¹ÞøÃõÖŒëáH ÓSþ.— :z¼®Ù:,ˆ®aÆfÜŠN&9ÀPz=¹™tˆþ¶7Ë%Ë/È¿†ô.ljàÍ’ËÝnÓÙ’=?É•’èr6d5“,PÁ/áblÅÑx¦<:öŽwÃ5]ÛRÓãÒSv¬X¼=-Åã¢RyTîæf–¨u,yËH™±ÌYo¬·,3v[6¨â„èý&QgL¸—·iQpðDƒCÔp)Ö‘â ÐU\|þk×tSÈ2OÜÔ˜"‡Ÿ¹ |αžŽmm ß»þçÉ·÷m®ÊòÔ§Þ¹›ÌÚu¶j^]Z’ìãÆ×—ÔË?‘Ï=|?öªA}DÑÝÝŠî¦g- ¥PK>×Ùê¼ÆÙ'ö;UÔŠ›ÔŒcÇ× ù„ª¾êœ.Ó7Ìø_¨cy¸éÑ•?ýB1ãí·ÎQÔï”—»‰fvÅS ÷+–\á<æmv2£üg±®Oþ©xEk ðÚg4jDØQþ(¬S ',“á.œ°x̹çuÿ…°0o;£—'ν¡ŒâîÆp•%ÓÌèÔê(û˜Èv=²¼”ÊõíàíôŽ2Ñ–ðWÚgû×ã Ú Žõn•D:—"<'E&О±©l-ÑŠzÕ­ÆèpD¬zI‹âñX­5êÕ* f0^ ]‚‘Ë7Å=¡—>I§ž:" ¡h$3qÁdn*ܲäç§ï¹´ö|ù b4Ì.‹k5'hŒ¦£?%ú‹ ¸/^”×5¹Ýiv ìû DTÛújf(MÃÇò5–VË*Ë€ªß¢"VN0šök+ŒQ[ÚA5ÕZç• D‰A&µVÎĹ®:W‚<ÜýµÏý;îÕFYæ–OëËÆ=7×Ôžyüjì×'%%&ºjO@sZá$^Â-ýÜõóëÕkµ`èÕ‚VÇÞHÔ ˜1 ¼Kù¾Ò@Ñà4„ >ò=“× BáL¡k»~”%¦ði)ˆú§zL~XÞòÁ{ò&ùî½€‹Ï¾@a%_ŒiÞ?3<ÍæX F`Ö¢ó!£Ÿ8Õ I³š%Upõññc¡d¨Äqm!—£‡K™RÕ<¡/dš¸…ªfa‘Ö uÒK*û>¨0àÐh‘VÃñœZ¥f…ê)wGÃh0áx­Z…ª!ÇÇ_ ™à…jÏcµ–7*¤~ VÑDH> –@ FËôÔùaE–°’ÓÛ#¿òS1½B¢NŽ÷úí££â¨‚¨«GÕ£"-¸QÊH ¶´”(º0’_øRîÆÏË5øásçña¹×Éa’Eò1\5öÅTزhÀ” Ý*VsU\ÓÌ-g8èhÙïâàm'À—«Ž©ˆBr-£âìLãåò™^n#YÏôsëx-¡ð¹›yÊÒq‘/úë D𠵡ԧß.F4·¿¸íj®nU Ž0¶»È#á5cwÉýOÂñûñíäÌŸ1~˜mE,꟦š®ÜEƒ?–‡~{%Ŷ ú¼Ø˜8@oÌ9{*$¨¥“­Œ7XÙ4]²yƒî3*ÀiçŒIRIJJ¥ß‡WÛÛí«íœ=ËqÎãuOØãùBTªÜQÌO žÄð© Y?ŒM°Çgþ0'ÖÇ'9L ³š`X†1þ¸P¨ˆÀÒ+]ªìé×7¦Û[¬‡{­ß3>d}Áø¤UÝÖ F HÃIsöO ö·QÕIµåù6pŠJïQä½Ú×a®ª«\ØMo_§¾N™¸ ³F")Õt™“@âð%¼Ò¥Sòzù#Hëñ.ðu¢ñ®äÏäK ßij[¯Ë-Êë]툙•VÌ©‰Ž¶‘;¯žKׂ){äÕÊ«ñž­xºü¦ÍïZR±¤?ñcG†Á úÜh6(‡ÝGD.t$ƒl! >C/ž"?T¸rùŠ6úÒö"bBHú;©-„ô ú/#F²‚¼ÏÜÀŒ°7¿¦ÿE:éTÒ %í.&ªeªSéCuÊ_I3 TŸf{„1M™æ”k§Az\ûŠ®@·Q÷}¢þýÓ ÇöÎÝÆÃb@¼ëÿ]2uý¦›ÿ•þ•þ•þ•þ•þ™ýÕçį¦éÍý'x²\Z䛿hNí“· iáìÔÖŠšúêªÅ#þ²ä`~¦Õ%66Ô5—T¦Åƒ 0Ïëh‰³üwÿéŸëaÑ RÒïgÐ…Àø8”˜–4"Ò‡æ£EhªEC€¹<´50üÂVTjP=ªFUh1A~T¦ÜdçC¼oE&À´ˆQªCͨU¢4QF£yÈŽb –p ‡"ÅȬünA¤§Bhá²5Ý×uFÞ |âþaˆ¾ñïeÐ…ñ¯uàÉax*““远™·Ðuä,z–f.Œú¸0ÖÀç È»!7B~ò6ȇ wAîaòÑ{/s¯ J¾ⲯdv Ú8™¹tJµ/’ùÓ0ö]su^‡ÒøôØ?’¹ðøgJºÒÌ>ƒš¸aÔÂÕ¡&¦y•úSè(ÀüÍÜ¥~T}#:Jû¹[”ñGé8æÏè(û"jgyO¡¹ JPA\ ŠårPÂÿYu õÿ³fà©û"úìo<8’GÂO<×nœþrDä{«þD?eö3ã½ò"ý£jˆ‘ È <ÿ½÷I endstream endobj 8 0 obj <> endobj 79 0 obj <>stream xœíZ|Å•ŸÙ]­$ëÇ®~Z–,íÊúaÙ²-Û²­Øqðb[‰ÓÆIG Q"ÿJ“`HÒ$6 NÀ ´„Zzü>zeqJÜ+W ¥”„–ƒò£ ´¸%йoW¶IRîZ>½ûã>vôfß¼™™÷æ;oÞJB!¤CCˆD- —„Ê‘|ymµu®oOeÊyw!„Wt^3À·uu€àU(¿³:µfý¡ÇÚv"D<‰âwkÖmZi¯!Ä,èénïz~Ó%ëòaUÌɬ×R‰Ò =ë6Nãà®u}홲ã„è³ëÛ7¦ègˆï@û“ ä¯l_ß©÷œ…,'Õ×?)ûäúÔ†îÔãßÊyÚÃxdmFY0¯7ŸQ‰ŒdòÍ ót×äGèéRMѹð DÁE’5_t\¼á¸S¦kqn‡4çâƒx;¾ ¯Ç«ðt½‹Ø„UCcôvKetÿÐË8Žë¡¯Ò©N'ÐIô!ñ&zøëÑè:…~þˆõ؇fƒì”‡h 𢏷à|ôjÃeÐê<û6zÆÒC&Ìã|߇Ç@ÛÛ‰ßÆ7_!>%‚ Ø‹ÞCŸ„ÿ>ƒAÿEX@ÇÐÓè)"z=J–“÷¡½è›èEòZ Ô¶ÖTÏŠTUV„ËËJC%ÅEÁ‚@¾ßçõä¹yÎåÌuØslÙV‹Ùd4°Œ^§Õd©UJZA‘FEX´5ÄFs”A‡ÛíŽO•í–EÒÇþÁ-"ã=”{QÙyQÙ5SþªˆÌb“§¡Qêx5½-"“ˆÍ"’FÁ¦¯ÀHSE»z=ѵbNCW2 O4zX^lz?45¹ïQMVƒ§¡;«¸fi€ÕmS£¸é,3DS´f”@*]q‘h Š„/*Q¯(ìNãi„ž ÆôYÍØäøžó«<6Í™2éQ)˯…víæG‹ÆGöŒ±¨#ÔvyºÚW€åÚaŽ£ˆôE{Z%;F%Jöð"Ë™$|´‡ñHæˆö$!÷4ÂSŸ+±º!¶Ë=îpІ 8ZÌÝ|ÚAŽDmky©82²‹ïZ;¿Ö-åñx܉z Cè,Ú[ªØBÅE¦ Ð•ì•Æìm—æíåGvwËsÝ#ÏAní…iÿ[­FF¢]žhW{W}¦÷Qh•o¨uyLVLןM5€J®I6ÆÝc7/Ž5Hó´7:2Ë>#INI@®ä¥̃D¾“Ñ☚Β²îYh¤s– wÃS-Ÿ=%*|¬‡ù‰8é™xïBIû”„ö±!‰mò4%GFš<|ÓHr¤}lr¨Ãóž‘Ñææ‘T4 £¶ÄੱÉc»bÓž¸È&{p Ø^B@ÓâXÃmˆO[¦‹ ÀÒÈê€à3oêVF­17†Z‹;ÀN1‰o>s—€Àkî6 çâƒðs7w7±o¯‘»h/nÙ›'`Ù £±ü„0Ñ2A oà–×R¯I3l¯ÁÐÂãj}UëñäñÔq’9†…1µ¡Jª,8¢ÖT½uÚÁýˆý=þÕ«F.ôjݫļâàÐ)öªôTòTê-µfNe±U-O&ŸL=Iþðû9òÀ#߇îC‡ëâÃF.õ0þùFî ç·–r?‚ûø*îÄfîÀ?1èànÞ“ÃÝ´;‡Û³;Èí r#Ûš¹·6sw¹€vínæ®r;†k¸áAþú0ùü0þÎvwÐö¡fîºÁfnhÐÆm,á·UÈÓ¹g›ž­*èšÝÕÜïJv]ÓE³Œ›³Z 9%íærl…Eº9“±+*f ƒú@ãÏ×{}LžGÏ»§wä:u¶»ÎbÍÖMfôZ^«ÎÒhi¥JKR -„–e†B ‡hB ‡H‚Auh!DƒBÀö{=&‘Ê1[Å15*ެVqh–Šk cÑØŒš[ëE†û’z1lS¡Åby°YT·\Åøæ8HEâv«HÝXn…ójùå±1œ#UËÇpcxhø¦›3\<tŠ]ÍKbbÊË%æÎ8 ÂÕ?Ðßßüo®Qµ4z×âúÑw)épkßõ4Žþö]ù ëiÄb¸€Æ~q[´GÜæiœ~pàêÏí¯’œÉ °R±¿MU|î™ùÁ.$$—§D4lE¸™Ð…$ =÷«ç䬬Ômp|ahõÉ}*Ý0Ò.¿"ôû§ƒ†…•Z’¤tzý’2ÇVgQ9TœZKm¤Týµ$&Y[Ã`³LóŒÀ¬Â-LN2ƒ8Åh‚š0 ŒZ‘‰w±ãeØä6¹#åU‘KpÄÝÔg]µ¸úÑôS³¢7…*ñ‚ôi\Ž)Òô¡Ñœ½°îÓh7nÅï‘í擬¢°[Y‹Åd÷³!›×QKW±•–JG3]o©wÄlWè›uƒ¶ÁœÍöì:ëBkŸuP5hU0Œæv“’àA"÷vœ G­à„ïÄN½ a#zž)µI&×É„êF«äÊÔºˆÕÊá! N³«C‰p0”Jêë&¡DYi¢Gª¼ Re…ß“G+=¦*o¸œ²˜ ¥+ÝÔÓŸöU߇½ÝwÜ2°ºç—üüù¸pøŒÆ_Xs–~÷ÞECE ù5“¿¡ ¹í:*™pŽ r{KN‹]©ÐŒÖfИ\›OÒyL%¶*M)¶Ôå, š4-Lœ]jêe:m}9ƒtJ{•n@¿Œ’«ÓönVc5åq$)épdïE&‡ƒÔJ®ƒChµÞ³ÐC˜·’GòØ3 Iyc5ìhIáºä 5N(xd¨0Fdm³IO öä!ƒÙ†õ “ ºï¥žÛ;¸_~âVõÆŠV=>øzúõ»üa]`YñÆÈe[¸[^Á]Û·Ý\7'}`u2}(ý»Ãwõµ¥ï0†Y‹áÉ?ŽÂÛ§]%,¬Ã¥Ê…XP¶*.× (”ŒŽÓ¥t¤:+ëº ²µ2²çÉØdg z-€U«ÓÖ¤N[ªt„šº•&³È[3À=W^ŠØ:^ÚD,®)lò˜Ü¤‡ “ígÎùðµç=Ò «ÈbUúOgëàt4Mþš:Cí@ZTŽî=ŠŠÀ–W¨µ™3Z s¥5æ°­Ì>_ÓdoC«4‹óû4ù×ðWy¯ÊO™r‘VWî*w¹v––™KKËÂÕeõ¥áŠp_Ðè"~¿µ´øXSª èVôAnn¡i¡ûýy Ùrõý&+¬MÔ%$%¤]8‘`?.7€B Ñéà.}IP)õµµŠÚÚ²R”by‰,™SÊOž¿²¢ê¯ÑÌÃ{­$ÝdsòÙs„¥‹*7Uò’³:–íݶe_zÓ×ïˆÿ¢Ê]Y‡U;°êJZL"Œ*«ÅÚR_*óÏz‰1Ûvç¶á£‘Š í0Ì­®5ã,60²×,ØÎQ€÷ù`÷¨í€÷¯ ‡WÇF8^£èÇ&ßL¤FV£Úhm0.%ÛÔ­–¥¶v²Û¦qIÀ-†Ö¬Ã"Dz.ŠeÍ´¬Ëe?€¬.Ë`†ñœ½ƒ>>êD8jØÁ  ¯"ÏŸ_êgmB6mù Ùĺþgšç-îïYý­yvÙ‚ðìÛÿüÓÁ=Í /Xw·«ºvöá«`²}U_IQú¹¹ÑÙºeiEú¹P¼:ŠN¾©x‰6#+ò£[…žyú¯ø–0­¹ ßÔ:ßb‹f³¾ß¼Ù¥µdûIa¼“°š š_m­çì'*‰(‘ ®&D~ ¿ægpL@x×Gl#†@D˜æwdiíZB{<ߊìŒ,áÙ¯Î`d¢®³'2ê_%Á}Ãé)¸+Øq¸ÊPBÝ‘Ïð`0Hv0‘²>ÃŒâ¥ôÁô~GÅÂÒâesîþÑšå±÷w¬¸á²¾ï8WzÛFJƒå+“eëËhóŸß»Ú]i5›Oþè.œ³ní_>~íÜ<}ö‚úÙG–v¯(rI6ižüµ‚§vÂç£Aa®O«a"y<¬'e±X¢®Õ"¶ÅÕ®êÑ&Ù•²hÔ ڱݞEßob‘—õ¶x“Þ”Wáõò²¬^¯U§v’ÃVÙ¥“·Z Ø‚PáÖL»´ Cµá3·6lbB†žA¿‰÷ÎAÚî\|ÈGI²cEßüŸ§ßL?½:¹›ïýtÒa=ûÄ=^óâW kß!þÕèb¶n¼âŸ~ãvŒÚW^ùì· ´†¾úú–²ôë%!I{€I"¤s~¥ 0jNÝ¢NªSjuç×iLÏ…ÝwÒœKÕd½’È&|2 ÚˆBI¨ÔªBù­>z&hšd‚³8!¹ÙŸÙ]ãçÆp4O$Ê`qÕ˜t›ˆýé³éý˜Â¿¬Ko¯£:?½“êÄ£éÿ æ£2ÀN ¢gŽ"nòŒp½¶Ÿ²¾œ|Saïóóù`•¯*Øèk öæoÎgü,³Óàt)ÍÙæ|ó ™2›‘ÓÁs¹¹;.³ÓéR¨T;3.šÊ‡pÃé"ѱb¶¸®xUqª˜*ªvÕû•Ψ³Í9àT8‹Š‹jœG‹´·°¶Û<¬‹Qœ(ׂA1öíŒf’—ÛÅ&ƧÜ®› åñql“7!i.a±ìÂL3k{!ÝÊ Ìå\eP«LïÛ®³‹ó;›Æ€ÕXç, ®Æd›õ:¯]Ówеódç¾;ȵÜeùç|DYM¯»¦Êç;{š(+Ûàš ä=Mun™·¸3ÙÞq ÊØUÑ vÍA7…#ã ¼7Dlc“/ ‹ Ð(0·Ñ©¬”-•£l…)3bL,»Ó`4 F?…)ƒs0ptöjc½ßPiˆÚ …Áî°×ŽÚµ·e³F°«î"KíOLíôqÉ`6ÙbeÒQð9Æ™6ˆ¢Y¥~ ½oHÏÖÇ‚©¦# ? ú÷¹òÀd·«Éš_ó_Z+i.«{ zþ䝨ÏäA>Áb;Ȱղ=îc}صC}ÜË~ §Ô™ $-iY)†€‰¦ñʹ…|ýl¿—Ì•¾ÓâþδMþ­„wœ—N}±D\ éwäÕä™L¢j§Ò;Š„â!)Ñ,ýme®ò¾/Ó—éËôeú2}™þ‘$}“,ÿz†9ó;¶ÑÀþÅ‹–]Öf.Z:7Ö´ÀÒÒøEÿ%ñÿü¢P½œKß>¡÷ ““c)‡2…¤ïÝýh1Z„–¡ËPX¯-EsQ 5¡È‚ZP£ÜÒ(ÿ>/ðöŽÚº7tµ_)ÿ úÄß@Š¿{6ýÍå}ôþä<Ý Ïñ8ú‡I!¢"ÿ0ý]óyD­œüäÿ’1d’ˆzÍWDQE j>Ÿ@ÇÀù¤ºßÚí§ˆü¨“gÈ{ÑÔõ\ô{è__8C£âÃÇV1µ!Gfñþå©MjéþXéf]ú»éeº»UúRËø€ë/‰¶ endstream endobj 10 0 obj <> endobj 80 0 obj <>stream xœí| XGÞwUuõ5÷ 3Ãp8È0 ‚N‹  ðÅ#¨Ïx%˜Ã#n¢&Ù5÷}ífßlˆ£ »1Ç7ÙæØ#Ù܉›d£1Yãf•i¾ªšÄÄÝw¿÷ý¾ç{¿çÙiº©®é®®ú×ïÖ¿@€lhl˜(ì3k€šç-í쉷é€oÎ[³Ê3ùÞqˆTü‰œß¼ gáÒ²©Gó@«Èùé…KÖ-ˆ]/þ€ú‹æwvýöó[î ½‘T–."Ö ù5ðrž¹h骵±ëgÏ m¼½dÙ¼ÎØùtÂÀÒε=üwÜGäú]¤ÒsIçÒùñþ}@)=ËV®Š·Ñï{VÌïY7ÿƒäú>ÒÞÇBº`ãOòGñFáÞ¤ÍÁ?~¨®U»ÔVîÇÀMîÙ Áað H|úÁ³ìÿ°/áŸ+ÀÁƒà·àmðÕPÝÍàNðsÐwÞu»Xíýàgà`/x‹¿eÕн»OùQ)øª½^/ùÆz‡®öÕc€Ï„íÛ; nšëó˜|Û«¯ßÞSÓáé-}Ô?ù£Ô¾ ×¶ö™:ÁÑdd´¦µ„S½fÒJýt_ýÔ¶OÍöŽx»ñšQ±³Ç¨zÌ·M}LÛ¦·µ$ öl›Ñ²A4¾£ªõ±Lò]ËA «E´–VÒ=õôz’Øõ©6±o1«`çó@Àê¤Dó X)Q‡HŽÕ)¬Ž~©Ðø-Ã{MvÚw"k$­: ]Áà­gßÔÞHkÎûì§5Üe`.ÁbÀ“g˜@€  ~pÈ(xÌ<¤¤ïÉ+.5íñìQö4îéÙ³iÏÝ{úö¼¶çƒ=šC{NîAdÊ•žÇ“’KÝÕÐØìnF MíMhÙ x׌Gg ©Ó“ð´é<}šOª›†'Ô•á‰uŸ–ìu¡r\.ÆcÂcðذ»pUxGv…ìáP1.vá`¨‡Jfà’P:~­äƒ’“%ÜÁ{÷eÕ–ü`ï>“ü?¡è÷ÉÆÒ}ÎZ¼fï–½¤['÷îeWœQ÷Ê™¥{mµøšmVܳ¤g-2ÞþþH¹Ã‘RªÜîH-UnJ"¥ÝI©¥[6[ÝÆ«›;Œ;»ÜW»w¸wvlÚ¼iÛÎëwmÞµu×6£r¥l*5®p¯@ÊrYWj\ =G ç>üÕaäùµòkæB0×4)ww"ã,Xh3ã[öÛÊq¾ÍŠólvì¶¥c¯g<öØ*ñoœ5Ø™:§:+±ÓVŒíä:+é®ÅæÄf²÷Ø b7¾ÔhÈw꟫wëž­wkÕ»e²óýõnüËz7w°Þž¬wÃýõnðD½û¹gó݇žÎwÿRiî÷ºŸ<èu?±ßë~ö¹çõOzFßÿË_é>ù”nÿt¦þMýH9¸é 2îïoØß»÷Hq)>½ÿÕýƒû%\†uzDD‡¨‘‡ààæë®sõí& ïÛäj= zÂì°îhí“ê§Ç‹ÀO?+W­\é¿À§«éjuö ¾ê•ôÄ@O „ù 5}FZ6úªý°ÏV³¨ÏFJ?hdeâã_ÿ2ö v«/ôLÚ—UäH¾ˆ²… äŸí a@÷ÀËï¾Ì#‹¼f¯9‹ ¹êÌ&œ¥ÿ)P.{\íâŒD"ÛA³2^†²˜SÄ\.—o€µ\-ß ¶Ãvq\&öµh­Ð+ZDuë1”Š(ÿu„¨MF,“£os˜N÷ûƒHe„Ã#‹`ú²‘Ùd) ÚAÝfIr8’8ã§=ÿücŸN½1\Y_7¶òÖ)j×KðXH¶^ÒÔ=Ý»AýÃý?W?Ù´á…ÚÏÕ.tœõ³[)8ÁjçìÖl˜Íe[³í¡Â)Ö‰öF®ÑÚÁuX×5¨‡ë±®±Ù-ëVh cˆ±öÀà©}´Ã´ i§µn 3Q¸!ÉtÚÿý¾›è •––•ZB%(';;'tXÐqÒñ)·UŒ­›4&|ãT2T©¾¡z^ÒÔ¼°aLûùý0wCïÓuš—TéùCh ^Nzn»¹Á ÍŠl*“¨Üi!…Yh?C;ð-æ»´]† h¿R»Ò ƒ‚Q£5Hf :¡7b„5F 4ZÝVÌzÅM’¨k ³f2 óZAŸ+÷è . O*/D,ååì@Œ‘-Iå` 8²(ýþ³¬>+ŸSËx.Èe%ñx¹¢î®àÕ›ÆÁËÔ«ÆÁná .VÔ«¹K/yK½.úÝ%¯¾zÉ[p¡zË›—¼›™(Ll„”l'̇~å¨Ôª¶¢.büšÓ!Ä5c¢ï‘“(Ò‘0*P"ËÐgEaõØ ¿€®èr´“¶y ÉÉèiÓ£Ø`•‘¨,#ßøvÐÎà"2ˆDŽ“¼!/'Gw¡4òqzo”¾dýñìGÍP…ðÀàgІÎr†!‚ˆÿ8“{½>s~ùÕWäj8ø‘ú7›ÌJ•,:`ê@5l† á¥p Ô@ â¤7û´ ˆ>l=Ùzˆ r³£ÁGЋ‚í»~±š\®üïä¿Zà[•ŒRX®-ÑUX*’KÒk`¶ZWo©O®N×Ùëdä­ã4F‚Ìý:á&/ J`Ã&EkªVKJÉô+pg–1Ë…Ruô,Õ+ +½R0QL :z­ps&A´Ÿ`:ÿOÆLGMaíõP¦ôz,°´4T’M íË ì)ØmžÁâR¼ó¬úzêog  uSÿîKIÉô­kŸ³!3#Å‘é]×5g#ú\]¦^7Âíð:¸Aíx|ê;·ÞüÁES.º¨aÒ‰·¿>ý¢i‘É€2ï•üï€lSBüAÐq®JF³ÛŒxä6B£Qg`ƒ1èu:¡ÉàAan×ÃqœÎdBMDa~ hé9 G ⢃äÒé]œ 'LÍ™ôzi \ !, +øý”AÂÑâp0@gž Æì Ö.- š½¸ràmXª¾Þ•5"„oƒE7sǶÙm)SÆy–Ìõ=d×ó'|¨Lmtw¸Ï fg7gš+øQú!ì §—»ëùZ}¡ÁÕ^çnç"8ÂÏ’›Íí)sR#ií®öôn®K˜ožk_–ÞƒV™{½i½éYd4Ÿí£F§aZF“±P ¤£`TѨdEÈ= Jn$yLv9˜øu`J%M ½Áá -9ž;3Œî Dy‹×tšP‚mŽ[ÊIŽÉ9Á1 B*ñ(,(&¨ü R¥NáAÿ¼øúÓÅoÌ:´ã–kf½9_3ñø²O!öçç\\¿ø“yœ÷hÛ¾Ö'ßé]u•Rõºoô»¿lº±jìÚº‹=ƒÊB  ǀʭ–8µö@ž6;WY© ÙFf”&iklã3Æša+ߪm tkº+×j×V…6T:KFWF£ }a¡¹æMrË#‘QïÖ#½Þ ïS#ð¾c\íÀ tw´ƒê‡§7Ú䃛”1É)ù¥1RÈ<ÆQ/U›Û¤yÝÒzIçr9ë¨%ª Ë;)KHGF›ÐDc˜$h<žtüRAGàrи tà.&\6/ð¸dÀ¾w ÜH¾ÍC™¹œ‚Œ ðxàÊ‘(U‰øñE0eöÚ½æ¬ðæÉUµ/\µþ£‹ ÓþÔ=qsIAa(Pò“Ù-÷Up›¢ãümÞuû'7¶À?.úÕ¸ õÁÌ7Jêr‹ýk¦t{²ÝÉ:4ø¨º ã¼’²_ÄuÕCüqÊÀO”Q‚Þ¡/Ï Ž –ÕeU_Ö›õžFï|ïê‘'—Wç²Z“&¹8# Åå,X|^`‘‰¶:qNm1l6ÀÒËHin/7–»ËQÀ+SuG/–oEí/ƃ„ )}È,Se)'T QÅ((Y²Q¨ÄRVšIi`÷Q²1Añ‚Úì!õ­?^²¯¦9ÒiŽƒyš´å¿ö÷-n¿~rKëKeá=cšn˜‚иò‹Ã×??þXý°züthyæ0,¾ty¯Fÿ´1Uýë§Á/4æÉë"ë =¶Ü|GžûÎ'BylÝJøî'[hPŠe¨A™°Ö£´Ž°ÐCÌ bp“xIFÉ-m@ÂFjP`jÕˆ[¨½ŽšË åÇ·" 'ÆÑYø'Ñ9¿C/ôqgñ7g |Æ£Ä^Y?ø¾ÿ+H¹  JA6aX=!jÖx!3Qð% trÖÐR¡¿ÄÌ(É) VÛÇeTçÔí³RÚRÛÜ32Úý­í#gg”uHs s-sS:|9k k, ¶X\úYöƒ”íÐ0çšhB¡Z°B«4ú:EàñXnˆ·5Y)ÓðÁÉ;…|Þ/„p¹Pƒk‰†kºð*ükÑÈ%ˆÍ’ „qqÃ0(Œ=Œ0áȰRM´Rw†<²Žz4ô©‡b^ ßÂnþ&îì¹!ÅÃÏà ú6Š ‹dEF˜‡@£e@aÆœ7êéâÎQu^þ¦³sð½tç wGû玲;àçÙ#­ÿü^Ò$Ñêß1»RHDÆô´4I¨‘,k$´•<ÉFn’5ÜVâ#Ûx^Ø(¬W¢Q¨¾Ö(TbiM†ÓȃëyÈKÄ%ÆÇë@&(U  tOOàùJÃûùR~ ßÄÏç7ð"qm‰æ#†'P•n‘Ê0uM &)݈&:t(öO"ÒŽ†>"^çåˆÔ³BÈÏyã†èÆ~ƒÒ¡´Q=«žw©üѵèh+?å'ð_¾Liæ¡^l˜*ÛìYöRûxÛ,©EÓb˜eš•ÛÁuÚzÐcÍêp8K,(??»DÐ8Àr¢¢!ÕÒ‚pÁ²Þc×Ù¨êÒ¥Qpéùc D†PÉ6Ýi׳„˜®Î¼€R:O•ù e­µcv6ß«þmnÇ’EsÛ¡þþµ_Ý`ÜðÍöåO¬™Ò4~ÂS‹vžYjX’œŸdMÕÙ³ž=3º:Œ®ûËÂ9uSê?Ý}ÇG'Mœ;—Ì÷2ß{È|€ ô+¾rKåb´H%—T"Jk4Ú†Î!˜>0øÑbÞÇxæÀàû⪙x Ô}«ÜFwÀ­'ÙD½Àf`mÞŽInQ¢÷‹TÕÓûEÚÅ )|½¶C ûæ–¤3÷3æpDåã‘›Æ$à#À.Æç¤ a%&_ø=ݸàìËê6¸êm[o~øÕõëZoòÉoµ.[†þü’ºVx4\Ö®>ÿ»GOÖ眽*¿|âgÔÖ#4ÂwiÁ®'äL¨­›ÉlPò!ÄiBPÂ@‚X©7ê¡ Û 5LŒ²QÃĨabÔ¤ð95-°QÃ%ºs£ŽSØDb‚‰š°Ë™Ê 9¶ã;üÜ[_sFºóGûÔE}ÑßÇûßKú/ƒÛö¾Ò®ÛiGaHâD p ZjB|Sq²ùëÒµñYóÿ¥ ü 1_Æ'P3l(~2–Sþbf³±0©Ä†AŒpÜ5¢­Ñu‡¹'x¯:»/$güù1/áÏLð¢R!BY .ÁjðB†:8Î0Õ0_˜¯gXeX•fÌ)>èóé8“)©D‡\%œf 3L²É{`PU¬´ãÞ%3d›âÈ>@ö'?@ö6R8«ø˜s½:Û˜­d#§]¶Ð»eÆâ²Ž^%/ÊŠK†€ê?î’qbx Ìä„Åëã8ß›….ez¦™V”–1I}ïzõý­¿Pß[°°Þ—ôBù‹{MyÍ£ËΨïÂ"(t<]«.GÓ/5½££úžƒóácêþ’|‘Ó§>­žPßWŸÎN‡KÃ_ÁðüÑ.Ä‚ˆ6nÉ$!Iâ5ÄÊä%ÙˆuˆÍ'?£eú8±ŽÅ0¤©”Lv­…QÌÈÈee¤ZKXBÑ7ê9‰³}ò:kŠOÀ‰‚Ïšâ(â¸bÚ-08ñ?à ÿ¹3® W/÷Ç¢sTAr ò‡£)‡£?FŒæðG£P-¡Ç5Dñ½Åè1_ñɸXà4\1”ôK5’¶McãxÔ 1O“;0øà —À )¨¬£tMf?‹"-êß©bS”ìÇXŒ$ZLî ›"äµS»â­è¾çžC“Ÿ{îf|ÏÍ7ŸmóëÒ¬Þ8L$  1-h‰‚ýoI—/âÒE.S‰±Ìb{L¨Ð`Öši‡ÑgüÑ3ïÇ1sšôIë”YÍ8 âK5ËP·ŒïÐô¢®—ïÑh›äfM›–ëâVq«‰Z× N@˜X¡]ÃÌ Œ‡«ñ L>¢Væ ‘$-¡4]ªÒ3ádé Ä)Sbþ_ÌBepcqàdM%3¨ébP3 nC£˜ KÌgä1ÃŒU4ýï˱/rìD\Žé‡úÞÃOÍIå ðQëƒxûJp7F‘VRÜÓ…a¤•X.”íW€È MâQ‰¡—?}X»Fàup´òÜÀMÜÅg¢Ä@yŽ×Cü(*Ç¡_Qt¢[,kÄ©b§¸\×Бà†v¡D¨¦ ‹a‡Ð {­bµÁ&Š{‰^X ©5ô©Ä ÏĆhe\þ}vÿH©Æî1&Ïfôg2Î¥?QŠ!vbÔG,x†¬˜Q'¨‡¨ÙÅ8A}œ >)|èÔÇõÈ÷¨e‚þ”È+–£—€1öõmtìADWäKÎü–?zVÁ‡ˆ ´rðCþmþ$H>ð+%L¨¦µ$$!E—b™ gòÓÅvm‹¾ÅÜnžd²ÓHy2ŒÌ†´F^gG©%vä-‘5Éd|¬¯Év.1TR8–%ÅI¥„IŠ•YÆ,HƒDá,.5Ýnd*ÅÈÂÔFnÙ7ÆE±h< ÇG%¦Rܘä°Øc†Ðù¶¤Õb%X øôYóZgŸ½çu°­­³cv äo½{p¢:ðáÇjJï½E>»K}ïÀõÝÎù Í›=÷C﹋.Žv X¡þZ}O}Gý ,1ï&¸47ø“R4Ú6ÆUo«w5fçÅ” šD$Šrr‰†“%£×íEf»'¥àáûNÑ2t%"='Ú糄öýBai°Ìkô†½(E´ÉLÊ ZËC°’¬ä¬ä¬äDs¤ð)›*y‰ç|mr*?<ž0P"q“™é,R8GÔbbñü⬠‘µ2FW¶|ÀTë£É‡èºô‘—Z¬ß3äoVUƒúùaxÏÖ}µSgÝ»£³°Ä¿¦ñó#s®YèGÑ>þ¨¯0xÛ¥÷ü± Þ§ÌËp%E_ñæ/¥t ñð± ‹ A .ä ÒnU57ÐR2u;:ØÑÎ s„ˆ¾r_ªdsçI¹É™îÌ@¹Tje ¹Kó'I5¦:k{RNu~ jJmr7.NY:ß½Àߨàèq÷xVå¯*ÜbñÉŠÁT&ÑQ‘fg.v ^oV ÎoÒ›kw2लBGië4Û×Ic£ÇöéIÅÈxeU±±¸§ÉÝ#Kñèp<43:“ÊiÌÞbž™»È¼0wyMî5æ-¹7™oÉÕЙ›$ÂÇ™4’ƒ‡Ö#rA0j¨fž‹9<šZ×øÖî{ÔÁ͆å0÷Ê/wΫtîá§aå_ï€Â|C“ú—ëïz¦còå´ 6óá ¥¶²â»9 ¶¯œ7ÇisÚò_ºï©¯* ¾¨m¿zQ¤;Ík/Øb;ø‹I¬TR  'e·Ü s`DÌÞ±qZÑ0µ1«§a‹/-îîûâˆýæˆd >±lpŠ(“OXô”™klaÀ‹OD¿<ý’ôÄ{æ}ÞÛG{¶‡hŽ<Ò3ø­’ê³ø’ÇpcäÉÜdùRë¥IRšž³“‰Lµ¹‡ÙÑß%dÝŠ™éSf§Ä£›¤oŠ‹]¨¦S×gÚMœiÎhÓüSlX:¶P§2Ãu¬õahSº„ðÔ±X-iL[&…Åô¥cKUáÊó–Èl[pX Žœòy§Nyåšk_›8uâaoNÁMÝ‹wæx£æ{¿nœ»àbC‡kYáÍz[kCI¹cŠÌŠ™Í©! ¦¥%‡=xä8I%£ ºÌ9!& P"üŠ-Ĭcä.--,CÑš˜ºaKæqÇ™Zuq½Ã2cæ× 1ŸÛ.ËB"Œs}Èr‡Â!nU`ô^f+éé-#$zˈT-Å^³X˜D+Ñë´,,¦eæ‹–y2ZmXËœB-SsÚÍ%Ãâ71·îØÐ9]jŠ2#2/d+ݱ[s¢Æ ñòBñz6]«+Í,»`þgâñtºDçz*¥)7°~ÚM¯/¿¦ß_˜ŸÛ3fÒþNMÙkó×<ª„«žjþ¼zjתKçÝ©yŒ%É}ä¶Þ; =’K™‘œdÊÉzÚ˜™qÃÕE¦ÍšÔÙÔÑ9…`à ÁÀ.‚Y+ð@‹’W‚BÆ {‘§ÕëíŠg¦e¡¥WÚ¦3ÈBR•ë`º"h´’-6•B“-‘¿eKž¿u2a;œR´l ‰ñ}l²·šb‘ÇfnW†;#œ ©².Ÿd®D/—™ :ʠ̤ NþùÆÄ‰„ qZÑ2³B w2ã‚™¿ÚÏŒ‹mÞó=q2[CnTŒÉÈÄQ“¿ü<ûB¤‘9:;–ØjªhŽ­´ïj?ñáí;jt}ý {–þôÙ«oœöÓÚÆ•u·?†Ê®ý`rCCav‰`‹¾9nºúšzìÈ«GE7e¦±\‹ÿÌý_ ¼àqe²Ñ×àC~˜aÈwd&†!ÃhG(¹6hª ŽqÉ­°Ép1œoXW¬&“-¬Ã^¯3ÌÉF‹YùXÚÔCú^‚Ðï)#}¯ó%1T'¥Ê ï²ÄÌ8@fæ»ÌHF|Íï¥äÍC«þxiøbP„­Åm/¶-K5ãþ:çgíë^¬­k„…ë88EÓüÄÌ»>~ùš@^­]3¡°xbmíŸn„8ª4çèøÚß¿öâÓ“í3Áæ‚Íñql"%«ÒY”6ÊÓà¬J«õ´‹„“lÈÌ'3`(¥Wñ³íÈ}LÖd(qxžV|Lä0ƒ˜†Y·ùŒ|š¸Ð9¡2YcŒ%©1:ÞÃi<‘e¿¤¦JÉ´%‰Æëý´5‰µ&± Ä®”Xz–Ä,I´%i³÷¼ÑðÐ0Cfq1H@1LÈ͇/™©Ô`bÂäÌÃŽÇ÷Oí[xä/SkªïlÙVßß?yíÄ;û¶ín¼õ„‹` 4ïxï¢ÉY9ð“3ƒèŠ çŸ^|áÕ‰4.Ò=x wà ™øôG”œlì×á }eúx\¯¯OoÓ7:ºõIkõëÓ °Òí6¦±ÓìâÏbYTZ­6&õ2yïe@L¡TÖ³’x†ݪ wz©ÃörnȈ™ûS-ŒŒF6 煑;· z³eó·Nˆã]*‰ƒ1÷Ñϼu–öé=·i'”óÄ¢J{\ØâŽßŒ--ÙÙ¼âÏ#5퇗ª_¨G ÿÔGß>oÜ}Ó^J]xËÈ¢¢Y/ç–ÂBh'­R¿ûkþïÝsuÌÂä,B:¡Ù ÊB'C–“…7$[¹m5Ol ¶­a¬dæõ ëݲQ6ÌébІ©ÆrZ† -d*Æi4ƒ¢7•£mÙÀî1 I7Ãú$E(Ó† mÇ@×|⥴-Ã5)Ã1U\\ñžpEúÙÊ.ÑMqîµÇV·|¡ QPgœEãîÊ^·NW÷ö÷ö~*‹2ÒÈ :nK¾^Ç&ï<1Í$ŸÆÃ1Ïë3ŸË\L˜ ;nï·$§Ì©ŸòÓ)ýý-ýóÿÚ8ekv~ÞäŠ_ãàåºio¿L%ñ£Ä,¸Š‡åÌܧXa5"ä)Cœ@<ø^Ê70‚0Zu`60̨€™$Á1—Ê YÖ)ìèeñ¥÷˘q‚ÄWœáácÓÂV/c¡ÑmÒÐp#ŸÄ(ð‰Ÿyëa¶‰”àèkW½ù¦®¿ŸO~îLŽ‘ >«¶";I 8ªø4|††ã›ÂkµFEÔ7$Á¤^ ÔÀGYŽDàË‘è#,‡“?öZ@‡&©'¦°¨g ³cR¨¹Ã†˜Â‚¾),]—•P\)}ÆœBs3­´é‘¶›ÂÓéN¹!uøäFŠ‹C°|\šAvœ;ÂÆmû~Ò*]+EvB‰#?ͽª@“Ö^XÛâpè?‡PÂhž?bÒíզ忿.ŸÊ]}'µŸ!Üö(á6-8£Tç¢?ÀwdN†F½º[_ú"­¢¡½­‡ô¥è$—Jò>¤Õp ñ^„—´¨CÓCÓu™’Íeô½¢GÇf›c(á0s<Ü9}§‡¯g³Â±¯ð8Ž¿ÅB‘¤Àx…¿F÷C^¡KµÄŠ-v…ẏ­ÿ6¢aØZîõÁ³?úª¬ïïGîãÑ¿ÃÏW©?lNˆÐ\fB²KÙ;+—)9B‰âû†¸L‰Y¾Œ“ãK¬Î^abŒpþP7´ðwûãZ²¡Aj³Â6|ül@ÇâoJ±i.íïgÑ@*1Å$¢õüðˆRÏeryÖLk^µ§:û‰|qÌr»Ò¤¤ªÜ ìâ¡)MR ¡»°¨P)l,ì)äÿqç ©"L¢.dd yPН¢Á|-HçÛÌÆSÄ.J‹é&F! 0øÙ`˜ñ;MYÚ´øûkì™FöL#{¦Ñib´ Ï1±çó×cî¸)›^mbšÓD%>mÞ”ý¤p–Á/}”Éídq²Ç8Ùcœì1NgZbRÒ†¢Âiìâ´ðÒ³“6dã¤ihi±P@¬ è“Ò:Ý&Å´ÉÄ™C‘£MçŸÓµ†s—ÄÅ7¼UxVF‹Í–Ø[ÃÅ8qÆÍß“êö˜BŽÉv1©_oOjžÚpg‡cÅ)·Q1ÿè¼wå¬è_|àQ´±vK®¿ aLÒ˜ôhmœ´9×ï§¢G6ÖMëhêhzÿHè^‚$Ìû¾îåÿ‹º7i˜î-ˆ'­šô@gø{Š–®Áå24žS¹LÙÆï?V¹ •çéÚo )áÿ®ÊýÏ4®ý_иŒìDáRÏçC¼œP\ ’ˆvVJL%¶ G½¡ÚTm«wHưŒíaN£Kd!è¤×Ñ%F2]jЧé@"îñAŒ‹â/°|;aÕœHøå§3ʘX$ŘâN §,KÁ[µ0Š[•-©‚ƒ½<{‘„¨ójB¥ÐÖéÛpäÈÖßéwä¸9ùŸä€œ (Fà°U÷¡lqjc.W?ûËqõs˜tü/0ùÙ‡oºågß¼ûçh„ú•ú<¬„f²QŸS¿úãoüñõ?þžF”Ô.¼‹P”zíJV1*·{Æ£:{•§Ù²Ðr¹´1M“ˆ&ñéŠ ku¶MIá4Cq<š'ækç‚¥±D.Kb *áRõô? +éþÕ°ÒÐÕP|).þ¥øÒLÿ$Â4ÞïG˜.šXµ·kæuuýýõOu¿øá³ÛwN½¿¾qeÝ}¨rÛ‡Mšš«ð_nR_U¿|ñÈ„òèÖLç›Ìëbþ QñWpcœEi£=“¹zç„´IAá‘'+ uéU¼l¶Åb$ÿ²¤ùW#)g”ÖX”ö?¤°4dI`‘Ëâ'ÚŠ$ý³(Ê÷TÀ÷Ã(ÐgþÏüªþ™ÿÑõÂñéÕU{æµý¨–8R­pßÃ×Ü8í~µ 9ë눙bØõn}]cnNÑÀÓh­/íÝgŸcb\‚s+ˆlýŠ èMÄ#ö—‘Èõñ#/KlE<$Uru€M±õØNd„ÙpE/‘!TtÊ „ÊCFLÎ „Ò䑨J‚œIá)k±<ORø{,¨·Íza+¢’(@šïɈôeÇ­Ðä7”μ·¾¿¿çç­# ¸]yʘ?ãÈmõ¼HGÉà§ÜïñZ„Ó•™’Sí(%5[ÎÏ,–+3«äÉ™søˆcº·90£x¿ÄÑáé Ì/¶­ç{Í«<ërWù·ÃmúÍέ¹?†·¦j!9§s›2ˆ¡˜ÈÈÈ‹(ÌØEíXNö(¸ü”yŒryŒfy©!&““Y,)™%á%3•CùÓ3ÝÀ¶Å©YÜ$x“E¦A‹ßCéeñŒ[\ö ‰œï"ç;%‡ázG| ¢=ÔâE&¶E¶” :Ùtn)a‹ç–X„ß?´Îã e‘{ˇE[áyþF¨$g(Í!䡸kR,Õ!ÉÁý>úÎÆW'hZßîÚxmvö’Ü+B7n(=ê‘Å]/Wkj_™·p‡?NÉþ«&N„U·<_á{c|CcsUFF²œlȹ钚õE²‘¾ß„ê.ªñùºdMzÝ$2×c¿@QþN ö(U:ÞÉûyNkÇêµ>55)ÌÉ ®^2€k]’ÞÄÐjbdbV¶‰M“É©‘Dì©çffI,àç…¼Å!x‹i,4ÄÚ I÷1,&±ÜÇmiçÇ»bø˜Nǽ·`0öÊa,pMýµ Í µ{ÏeQ4tÙÈŸïéíí‡W«¥dÇ”†]Æ`9ðšv'§>}§ÊµÌóçf¥Êõb&áyLUlZ!E\/rˆ·Ë¼¹Š×@éÂAéÓ¦'WL˜þÀZCq1úEÂŒ8­‡G 1y³ÔþqlDJ,ÕJCfwp™\ ..¸à.téq Xr™ž¢º¢‡Óí®t™ãŒ2bzžŒâxàx B“ñ—ë"ç˃‘he€ ñ8%2 Žš—-d‘#7¬,ú`"Ù7ÒlÔ2â ,ȲQÇB±SåÕ[ÉÆÃ³pÙήRëÔÉVŸ€¥d{âÐûêã÷>GÍY_®X>Ï“æuOý¤wl›Ë‚v¿•6EîèW«Y Õ°ÿJ8O½ƒ»ÑäÎè¬ë¼";š9ÊbÖ¨/Y“R*c¿oS‰/CHVtpMK1ònžþ2Îðä|Ù@÷ ª¤ïwç>å,Ö'‚i£db$жÙ+ëÊØK&2eDZËÇk1{õ„ÔÒß²áy$ÍŒ~L =•ô§ŽÈƒbú‰Ê%ŽîŽ-ê×'¿¢îSˆE‡ßMžþtüé&M賒ɃˆnŠõÁC;E«PòÐs91þ\@„G r¡gÓŸ"óeåžV¿ÞòÀýô Øè“cO‡tìp {úˆ Œ\ÏžE9˜>‰6Œb3m´e»úõ):Bù»ÉÿrÖR€¸&äfç÷ºLšáH3A2Ûb¿ST®~½=Þ7šÜê¾à¶¼²uÃmð~ø*šŠöpÍXƒoæ³øÃ„ïˆ+Å[Ä·Ä·GǶ+É6 ïOh¦iNk/צ›Î¤{]¹!ÝpÈpȸÒt‘é6óHóu«åÇÖ$²M!ÛN²=`}Àö}ý[ÇÃIÕI¯$÷¥,KyӹЩ¦Ö¥]âÊq½–¾ÛÝà~Åó¼·Î{6cfÆ×¾M¾÷2=ÿ×¶·ÿn§2Oe³VdÝ”õ«oÿÞþ½ý{û÷öÿ~Ô&ˆý"+Õ¥ô§$d'ÖàFMŸX=³Öf±§ZSë¦55N®ožÐÒÚÖ°Ý<Ò8«fö¤ÜýeÙ¥e#3¦˜’“\U)Ž4}‘VWxÜS>VÙ»/§"otº?ôX~å~Uøúƒ'ÙSúœœ28HŽYú8ýÎQ`:˜ªÁLPK¨gv ¬ì—›§‚:0 4F@9â+O- ´°˜ÁH`³@ ˜M<“\°ŸØê4þ" ‚Ä“˜¦H&V¼ Tà Œ»^ŠA<< Œ Ø öPòÀhü DÌ|êe’ZȼÒ_íèOy4Ï_ÑÕy û¡m2¸ ðÿ2¤óOO‚“ƒçUÀÄephG¯ºs÷‚ÇÉ~#ïÑ}n$ç·ÿQîÞÁIÝ5¼:Èÿ{â×L!ûS±zp+Ùד}9w/l#÷£»p-øvøÎ¯N¶ï+…|p„7‚#øpD(!ç8ÂÍ×$v¼ŠÔÿŠ\3@þO+ñäZ²ó»È¾lÁ'ˆYÿØCÛ?³ù   º“gßNwÞ1¥;~,Âà öƒ‹Éÿ%øyÐMÆ^M˼ DÅàQôÌàs¸r×Íî¿„ËcÉw‘kDZ5“ÿ•´ŒK@äÿ·Àé®ÿ©;ÁÔ-tçþcð÷`7Ê<îfœþÏ?”Ð%¶Çú}²ÝXù-H1Í×WçÑÿô·Kƒ·ª­Ú%z¥Ìø’|þé‰Ò endstream endobj 85 0 obj <>stream GPL Ghostscript 8.54 PDF Writer \376\377\000L\000i\000n\000u\000x\000 \000L\000C\000P\000 \000T\000o\000o\000l\000s\000 \000U\000s\000e\000r\000 \000M\000a\000n\000u\000a\000l\376\377\000J\000o\000s\000e\000p\000h\000 \000C\000i\000h\000u\000l\000a\000,\000 \000I\000n\000t\000e\000l\000 \000C\000o\000r\000p\000. endstream endobj 2 0 obj <>endobj xref 0 86 0000000000 65535 f 0000053472 00000 n 0000088649 00000 n 0000053298 00000 n 0000050996 00000 n 0000000015 00000 n 0000002042 00000 n 0000055341 00000 n 0000066215 00000 n 0000055743 00000 n 0000072007 00000 n 0000054449 00000 n 0000056612 00000 n 0000053537 00000 n 0000051138 00000 n 0000002062 00000 n 0000007080 00000 n 0000053587 00000 n 0000051282 00000 n 0000007101 00000 n 0000009748 00000 n 0000055676 00000 n 0000053626 00000 n 0000051426 00000 n 0000009769 00000 n 0000012496 00000 n 0000055119 00000 n 0000055196 00000 n 0000053676 00000 n 0000051570 00000 n 0000012517 00000 n 0000015524 00000 n 0000055049 00000 n 0000053728 00000 n 0000051714 00000 n 0000015545 00000 n 0000019027 00000 n 0000053800 00000 n 0000051858 00000 n 0000019048 00000 n 0000021848 00000 n 0000053861 00000 n 0000052002 00000 n 0000021869 00000 n 0000024992 00000 n 0000053911 00000 n 0000052146 00000 n 0000025013 00000 n 0000027645 00000 n 0000053972 00000 n 0000052290 00000 n 0000027666 00000 n 0000030901 00000 n 0000054033 00000 n 0000052434 00000 n 0000030922 00000 n 0000033654 00000 n 0000054094 00000 n 0000052578 00000 n 0000033675 00000 n 0000037629 00000 n 0000054155 00000 n 0000052722 00000 n 0000037650 00000 n 0000040466 00000 n 0000054216 00000 n 0000052866 00000 n 0000040487 00000 n 0000044152 00000 n 0000054266 00000 n 0000053010 00000 n 0000044173 00000 n 0000047808 00000 n 0000054327 00000 n 0000053154 00000 n 0000047829 00000 n 0000050975 00000 n 0000054388 00000 n 0000056815 00000 n 0000066416 00000 n 0000072211 00000 n 0000054795 00000 n 0000055277 00000 n 0000055553 00000 n 0000056196 00000 n 0000086995 00000 n trailer << /Size 86 /Root 1 0 R /Info 2 0 R /ID [<7D2931E5B8A694E02DA571C9AA15FE9A><7D2931E5B8A694E02DA571C9AA15FE9A>] >> startxref 89227 %%EOF tboot-1.10.5/deprecated/lcptools/Makefile0000644000000000000000000000333214210363175016455 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # lcptools makefile # ROOTDIR ?= $(CURDIR)/../.. include $(ROOTDIR)/Config.mk TPMNV_TARGETS := \ tpmnv_defindex \ tpmnv_relindex \ tpmnv_lock \ tpmnv_getcap LCP_TARGETS := \ lcp_writepol \ lcp_readpol tpmnv : $(TPMNV_TARGETS) $(LCP_TARGETS) # # universal rules # build : tpmnv dist : install install : @set -e; for i in $(TPMNV_TARGETS) $(LCP_TARGETS);\ do \ $(MAKE) DISTDIR=$(DISTDIR) INST_TARGET=$(DISTDIR)/usr/sbin/$$i do_install; \ done .PHONY: do_install do_install : $(INST_TARGET) $(INST_TARGET) : $(notdir $(INST_TARGET)) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $^ clean : rm -f *~ *.a *.so *.o *.rpm $(DEP_FILES) $(TPMNV_TARGETS) $(LCP_TARGETS) trousers_dep mrproper : clean distclean : clean # # trousers # trousers_dep: @printf "#include \n" | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(LIBS) - -Wl,--defsym=main=0 -o $@ >/dev/null 2>&1 || (echo trousers-devel package is not installed && false) # # dependencies # LDFLAGS += -L. # LCP v1 and tpmnv_* UTIL_OBJS := lcptools.o lcputils.o LIBS += -lcrypto -ltspi -lz $(TPMNV_TARGETS) : tpmnv_% : %.o $(UTIL_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(ROOTDIR)/safestringlib/libsafestring.a -o $@ $(LCP_TARGETS) : lcp_% : %.o $(UTIL_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(ROOTDIR)/safestringlib/libsafestring.a -o $@ # # implicit rules # HDRS := $(wildcard $(ROOTDIR)/include/*.h) $(wildcard $(CURDIR)/*.h) BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile %.o : %.c $(HDRS) $(BUILD_DEPS) trousers_dep $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.10.5/deprecated/lcptools/defindex.c0000644000000000000000000002756514210363175016765 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * defindex.c * * Command: tpmnv_defindex. * * This command can define the index in TPM NV Storage. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp2.h" #include "lcptools.h" #include "lcputils.h" static uint32_t index_value = 0; static uint32_t per_value = 0xffff; static uint32_t data_size = 0; static char *auth_value = NULL; static uint32_t auth_length = 0; static uint8_t r_loc_arg = 0; static uint8_t w_loc_arg = 0; static char *password = NULL; static uint32_t password_len = 0; static int help_input = 0; static const char *short_option = "hi:s:p:"; static struct option longopts[] = { {"pv", 1, 0, 'v'}, {"av", 1, 0, 'a'}, {"wl", 1, 0, 'w'}, {"rl", 1, 0, 'r'}, {0, 0, 0, 0}}; static const char *usage_string = "tpmnv_defindex -i index [-s size] " "[-pv permission_value] " "[-p passwd] [-av authentication_value] " "[-wl write_locality] [-rl read_locality] [-h]"; static const char * option_strings[] = { "-i index value: uint32/string.\n"\ "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n"\ "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n"\ "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-pv permission value: uint32.\n"\ "\tOptional for indices INDEX_LCP_DEF, INDEX_LCP_OWN, INDEX_AUX.\n"\ "\tDefault value for indices: INDEX_LCP_DEF:0x00002000;\n"\ "\tINDEX_LCP_OWN:0x00000002; INDEX_AUX:0x0; Othr:0x0\n", "-s data size: UNIT32. \n"\ "\tOptional for indices INDEX_LCP_DEF, INDEX_LCP_OWN and INDEX_AUX.\n"\ "\tDefault value for indices:\n"\ "\tINDEX_LCP_DEF and INDEX_LCP_OWN:54; INDEX_AUX:64. Unit is byte\n", "-av auth value: string. Auth value for defined index.\n", "-p password: string. \n", "-rl read locality value: uint8. There are 5 localities:0~4.\n"\ "\tFor example, locality value is 0x18 if locality 3 or 4. \n", "-wl write locality value: uint8. The same as read locality value.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char* argv[]) { int c; uint32_t temp = 0; while ((c = getopt_long_only(argc,(char ** const)argv, short_option, longopts, NULL)) != -1) switch (c) { case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 's': if ( strtonum(optarg, &data_size) ) return LCP_E_INVALID_PARAMETER; break; case 'p': password = optarg; password_len = strnlen_s(password, 4096); break; case 'h': help_input = 1; break; case 'v': if ( strtonum(optarg, &per_value) ) return LCP_E_INVALID_PARAMETER; break; case 'a': auth_value = optarg; auth_length = strnlen_s(auth_value, 4096); break; case 'w': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if (temp > 0x1f || temp < 1) return LCP_E_INVALID_PARAMETER; w_loc_arg = temp; break; case 'r': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if ( temp > 0x1f || temp < 1 ) return LCP_E_INVALID_PARAMETER; r_loc_arg = temp; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char* argv[]) { in_nv_definespace_t in_defspace; uint32_t per_authwrite = 0; uint32_t per_authread = 0; /* * Currently assume pcr selection size is 3. */ uint16_t pcr_size = 3; /* * PCR short info size is 2+3+1+20 = 26. */ unsigned char rd_pcrcom[26] = {0}; unsigned char *pdata; unsigned char wrt_pcrcom[26] = {0}; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Check whether parameter of index value has been input. */ if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto _error_end; } in_defspace.index = index_value; /* * Check whether parameter of permission value has been input. */ if ( per_value == 0xffff ) { switch (in_defspace.index) { case INDEX_LCP_DEF: in_defspace.permission = PERMISSION_DEF; log_info("Haven't input permission value, "\ "use default value 0x%x\n", in_defspace.permission); break; case INDEX_LCP_OWN: in_defspace.permission = PERMISSION_OWN; log_info("Haven't input permission value, "\ "use default value 0x%x\n", in_defspace.permission); break; case INDEX_AUX: in_defspace.permission = PERMISSION_AUX; log_info("Haven't input permission value, "\ "use default value 0x%x\n", in_defspace.permission); break; default: ret_value = LCP_E_NO_PER_VALUE; goto _error_end; } } else in_defspace.permission = per_value; /* * Check whether parameter of datasize has been input. */ if ( data_size == 0 ) { switch (in_defspace.index) { case INDEX_LCP_DEF: in_defspace.size = DATASIZE_POL; log_info("Haven't input data size, "\ "use default value %d\n",\ in_defspace.size); break; case INDEX_LCP_OWN: in_defspace.size = DATASIZE_POL; log_info("Haven't input data size, "\ "use default value %d\n",\ in_defspace.size); break; case INDEX_AUX: in_defspace.size = DATASIZE_AUX; log_info("Haven't input data size, "\ "use default value %d\n",\ in_defspace.size); break; default : ret_value = LCP_E_NO_DATASIZE; goto _error_end; } } else in_defspace.size = data_size; /* * Check whether authentication value has been input. */ if ( auth_value == NULL ) { /* * Check the permission value, * if it needs authorization to read or write, * the authentication value should be inputted. */ per_authwrite = (in_defspace.permission & 0x4) >> 2; per_authread = (in_defspace.permission & 0x40000) >> 18; if ( per_authwrite || per_authread ) { ret_value = LCP_E_NO_AUTH; goto _error_end; } } /* * Check whether read locality value has been input. * If user hasn't input, set as default value: 0x1f. */ if ( r_loc_arg != 0 && r_loc_arg <= 0x1f ) { in_defspace.r_loc = r_loc_arg; } else if ( r_loc_arg == 0 ) { in_defspace.r_loc = LOCALITY_DEFAULT; } else { ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } /* * Check whether write locality value has been input. * If user hasn't input, set as default value: 0x1f. */ if ( w_loc_arg != 0 ) { in_defspace.w_loc = w_loc_arg; if ( (in_defspace.index == INDEX_AUX) && (in_defspace.w_loc != WR_LOCALITY_AUX) ) { ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } } else { if ( in_defspace.index == INDEX_AUX ) in_defspace.w_loc = WR_LOCALITY_AUX; else in_defspace.w_loc = LOCALITY_DEFAULT; } /* build the pcr_short_info for read_pcrcomposite*/ pdata = rd_pcrcom; lcp_loaddata_uint16(pcr_size, &pdata, 1); pdata += pcr_size; lcp_loaddata_byte((unsigned char)in_defspace.r_loc, &pdata); /* build the pcr_short_info for write_pcrcomposite*/ pdata = wrt_pcrcom; lcp_loaddata_uint16(pcr_size, &pdata, 1); pdata += pcr_size; lcp_loaddata_byte((unsigned char)in_defspace.w_loc, &pdata); ret_value = lcp_define_index(&in_defspace, auth_value, auth_length, password, password_len, rd_pcrcom, wrt_pcrcom); if ( ret_value == LCP_SUCCESS ) { log_info("\nSuccessfully defined index 0x%08x "\ "as permission 0x%x, data size is %d \n", in_defspace.index, in_defspace.permission, in_defspace.size); return ret_value; } _error_end: /* * Error when execute. */ log_error("\nCommand DefIndex failed:\n"); print_error(ret_value); return ret_value; } tboot-1.10.5/deprecated/lcptools/getcap.c0000644000000000000000000003356214210363175016434 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * getcap.c * * Command: tpmnv_getcap. * * This command can get basic information from TPM like the the PCR number, * the indices have been defined and the public data associated with the * specified index. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define BUFFER_SIZE 1024 static unsigned int index_value = 0; static int help_input = 0; static int perm_flags = 0; static char *password = NULL; static uint32_t passwd_length = 0; static const char *short_option = "hi:f:"; static const char *usage_string = "tpmnv_getcap [-i index] [-f password] [-h]"; static const char * option_strings[] ={ "-i index value: uint32/string. To get the public data of this index.\n"\ "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n"\ "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n"\ "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-f password: string displays TPM_PERMANENT_FLAGS.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'f': perm_flags = 1; password = optarg; passwd_length = strnlen_s(password, 4096); break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } /* print the message return by getcap command */ static void print_nv_caps_msg(int datasize, const unsigned char *data, const char *msg) { uint16_t i = 0; uint32_t ibyte; for (i = 0; i < datasize; i++) { if ( (i % 32) == 0 ) { if ( datasize > 32 ) { log_info("\n\t"); } log_info("%s", msg); } else if ( (i % 4) == 0 ) { log_info(" %s", msg); } ibyte = *(data + i); ibyte &= 0x000000ff; log_info("%02x", ibyte); } log_info("\n"); } typedef struct { uint32_t disable : 1; uint32_t ownership : 1; uint32_t deactivated : 1; uint32_t readPubek : 1; uint32_t disableOwnerClear : 1; uint32_t allowMaintenance : 1; uint32_t physicalPresenceLifetimeLock : 1; uint32_t physicalPresenceHWEnable : 1; uint32_t physicalPresenceCMDEnable : 1; uint32_t CEKPUsed : 1; uint32_t TPMpost : 1; uint32_t TPMpostLock : 1; uint32_t FIPS : 1; uint32_t Operator : 1; uint32_t enableRevokeEK : 1; uint32_t nvLocked : 1; uint32_t readSRKPub : 1; uint32_t tpmEstablished : 1; uint32_t maintenanceDone : 1; } tpm_perm_flags_t; typedef struct { uint32_t deactivated : 1; uint32_t disableForceClear : 1; uint32_t physicalPresence : 1; uint32_t physicalPresenceLock : 1; uint32_t bGlobalLock : 1; } tpm_stclear_flags_t; static lcp_result_t display_flags(void) { uint32_t subcap = 0; unsigned char buffer[BUFFER_SIZE], *pbuf; uint32_t datasize = 0; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; tpm_perm_flags_t perm_flags; tpm_stclear_flags_t stclear_flags; subcap = TPM_CAP_FLAG_PERMANENT; result = lcp_get_tpmcap_auth(password, passwd_length, TSS_TPMCAP_FLAG, 4, (unsigned char *)&subcap, &datasize, buffer); if ( result != LCP_SUCCESS ) { log_error("Error getting TPM_PERMANENT_FLAGS.\n"); return result; } else if ( datasize != 2*sizeof(uint32_t) ) { log_error("Error getting TPM_PERMANENT_FLAGS.\n"); return LCP_E_GETCAP_REP_ERROR; } pbuf = buffer; lcp_unloaddata_uint32((uint32_t *)&perm_flags, &pbuf, 1); lcp_unloaddata_uint32((uint32_t *)&stclear_flags, &pbuf, 1); log_info("TPM_PERMANENT_FLAGS:\n"); log_info("\t disable: %s\n", bool_to_str(perm_flags.disable)); log_info("\t ownership: %s\n", bool_to_str(perm_flags.ownership)); log_info("\t deactivated: %s\n", bool_to_str(perm_flags.deactivated)); log_info("\t readPubek: %s\n", bool_to_str(perm_flags.readPubek)); log_info("\t disableOwnerClear: %s\n", bool_to_str(perm_flags.disableOwnerClear)); log_info("\t allowMaintenance: %s\n", bool_to_str(perm_flags.allowMaintenance)); log_info("\t physicalPresenceLifetimeLock: %s\n", bool_to_str(perm_flags.physicalPresenceLifetimeLock)); log_info("\t physicalPresenceHWEnable: %s\n", bool_to_str(perm_flags.physicalPresenceHWEnable)); log_info("\t physicalPresenceCMDEnable: %s\n", bool_to_str(perm_flags.physicalPresenceCMDEnable)); log_info("\t CEKPUsed: %s\n", bool_to_str(perm_flags.CEKPUsed)); log_info("\t TPMpost: %s\n", bool_to_str(perm_flags.TPMpost)); log_info("\t TPMpostLock: %s\n", bool_to_str(perm_flags.TPMpostLock)); log_info("\t FIPS: %s\n", bool_to_str(perm_flags.FIPS)); log_info("\t Operator: %s\n", bool_to_str(perm_flags.Operator)); log_info("\t enableRevokeEK: %s\n", bool_to_str(perm_flags.enableRevokeEK)); log_info("\t nvLocked: %s\n", bool_to_str(perm_flags.nvLocked)); log_info("\t readSRKPub: %s\n", bool_to_str(perm_flags.readSRKPub)); log_info("\t tpmEstablished: %s\n", bool_to_str(perm_flags.tpmEstablished)); log_info("\t maintenanceDone: %s\n", bool_to_str(perm_flags.maintenanceDone)); log_info("\nTPM_STCLEAR_FLAGS:\n"); log_info("\t deactivated: %s\n", bool_to_str(stclear_flags.deactivated)); log_info("\t disableForceClear: %s\n", bool_to_str(stclear_flags.disableForceClear)); log_info("\t physicalPresence: %s\n", bool_to_str(stclear_flags.physicalPresence)); log_info("\t physicalPresenceLock: %s\n", bool_to_str(stclear_flags.physicalPresenceLock)); log_info("\t bGlobalLock: %s\n", bool_to_str(stclear_flags.bGlobalLock)); return LCP_SUCCESS; } /* function: get_pubdata * * get public data of the index * public data format is: * { * 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; * } */ static lcp_result_t get_pubdata(uint32_t index) { uint32_t index_retrieve = 0; uint16_t pcrread_sizeofselect = 0; uint16_t pcrwrite_sizeofselect = 0; uint32_t permission; uint32_t datasize = 0; unsigned char buffer[BUFFER_SIZE]; unsigned char *pbuffer; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; ret_value = lcp_get_tpmcap(TSS_TPMCAP_NV_INDEX, 4, (unsigned char *)&index, &datasize, buffer); if ( ret_value != LCP_SUCCESS ) return ret_value; if ( datasize != 0 ) { /* start to parse public data of the index */ pbuffer = buffer + sizeof(TPM_STRUCTURE_TAG); /* get the index value */ lcp_unloaddata_uint32(&index_retrieve, &pbuffer, 1); /* * If the index retrieved correctly, * print the public data to the screen. */ if ( index_retrieve == index ) { log_info("\nThe public data value of index 0x%08x is: \n", index); /* print the public data to the screen */ print_nv_caps_msg(datasize, buffer, ""); /* parse pcrInfoRead */ lcp_unloaddata_uint16(&pcrread_sizeofselect, &pbuffer, 1); pbuffer += pcrread_sizeofselect; log_info("\n\tRead locality: "); print_locality(*pbuffer); log_info(".\n"); /* move the pbuffer to the start of pcrInfoWrite */ pbuffer += pcrread_sizeofselect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); /* parse pcrInfoWrite */ lcp_unloaddata_uint16(&pcrwrite_sizeofselect, &pbuffer, 1); pbuffer += pcrwrite_sizeofselect; log_info("\n\tWrite locality: "); print_locality(*pbuffer); log_info(".\n"); /* move the pointer and get permission value */ pbuffer += pcrwrite_sizeofselect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH) + sizeof(TPM_STRUCTURE_TAG); lcp_unloaddata_uint32(&permission, &pbuffer, 1); log_info("\n\tPermission value is 0x%x:\n", permission); print_permissions(permission, "\t\t"); /* move the pointer and get data size */ pbuffer += sizeof(unsigned char) + sizeof(unsigned char) + sizeof(unsigned char); lcp_unloaddata_uint32(&datasize, &pbuffer, 1); log_info("\n\tData size is %d.\n", datasize); } else return LCP_E_NV_AREA_NOT_EXIST; } else return LCP_E_NV_AREA_NOT_EXIST; return LCP_SUCCESS; } /* get the pcr number and nv index list of the TPM device */ static lcp_result_t get_common(void) { uint16_t tmplen = 0; unsigned char buffer[BUFFER_SIZE]; uint32_t datasize = 0; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; /* * Get the NV list. */ result = lcp_get_tpmcap(TSS_TPMCAP_NV_LIST, 0, NULL, &datasize, buffer); if ( result != LCP_SUCCESS ) { log_error("Error get NV index list. \n"); return result; } if ( datasize != 0 ) { tmplen = datasize/4; log_info("\n%d indices have been defined\n", tmplen); log_info("list of indices for defined NV storage areas:\n"); print_nv_caps_msg(datasize, buffer, "0x"); } else log_info("No index has been defined. \n"); return LCP_SUCCESS; } int main (int argc, char *argv[]) { lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( perm_flags ) { if ( password == NULL ) { ret_value = LCP_E_AUTH_FAIL; log_error("No password input! Password is needed to " "display flags.\n"); goto _error_end; } ret_value = display_flags(); if ( ret_value != LCP_SUCCESS ) goto _error_end; return LCP_SUCCESS; } if ( index_value != 0 ) { if ( (ret_value = get_pubdata(index_value)) != LCP_SUCCESS ) goto _error_end; } else if ( (ret_value = get_common()) != LCP_SUCCESS ) goto _error_end; return LCP_SUCCESS; _error_end: /* * Error when execute. */ log_error("\nCommand TpmCap failed:\n"); print_error(ret_value); return ret_value; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/deprecated/lcptools/lcptools.c0000644000000000000000000010276014210363175017025 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * lcptools.c * * This file implements all key functions used by LCP tools commands. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define MAX_POLICY_LIST_SIZE 1024 /* Define the index * parameters: * p_in_defspace: contain the attributes of the index, * for example, datasize, permission * auth: password for the index with AUTHREAD/AUTHWRITE * auth_length: the length of auth password * passwd: the owner password * passwd_length: the length of the passwd * pcr_info_read: the pcr_short_info for pcrInfoRead * pcr_info_write: the pcr_short_info for pcrInfoWrite */ lcp_result_t lcp_define_index(in_nv_definespace_t *p_in_defspace, const char *auth, uint32_t auth_length, const char *passwd, uint32_t passwd_length, const unsigned char *pcr_info_read, const unsigned char *pcr_info_write) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_HPOLICY hpolobj = NULL_HOBJECT; TSS_HPCRS hwrtpcrcomp = NULL_HPCRS; TSS_HPCRS hrdpcrcomp = NULL_HPCRS; TSS_HPOLICY hpolicy = NULL_HPOLICY; TSS_HTPM htpm = NULL_HTPM; TSS_RESULT result; uint16_t pcr_size = 0; unsigned char *pdata; unsigned char rd_locality = 0; unsigned char wrt_locality = 0; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); if ( passwd != NULL ) { result = set_tpm_secret(hcontext, &htpm, &hpolicy, passwd, passwd_length); CHECK_TSS_RETURN_VALUE("set_tpm_secret", result, ret); } /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * if the nv object need authentication */ if ( auth != NULL ) { result = set_nv_secret(hcontext, hnvstore, &hpolobj, auth, auth_length); CHECK_TSS_RETURN_VALUE("set_nv_secret", result, ret); } /* * Set the index to be defined. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, p_in_defspace->index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 index", result, ret); /* * Set the permission for the index. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_PERMISSIONS, 0, p_in_defspace->permission); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 permission", result, ret); /* * Set the data size to be defined. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_DATASIZE, 0, p_in_defspace->size); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 data size", result, ret); /* * Define the space according to the parameters: index, * permission and datasize. * If the index is INDEX_AUX, the third parameter of * Tspi_NV_DefineSpace should be set. */ if ( p_in_defspace->index == INDEX_AUX ) { /* * Set PCR composite object. */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, 3,&hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set LocalityAtRelease inside the PCR composite object. * Locality Write for INDEX_AUX should be 3 or 4. */ result = Tspi_PcrComposite_SetPcrLocality(hwrtpcrcomp, WR_LOCALITY_AUX); CHECK_TSS_RETURN_VALUE("Tspi_PcrComposite_SetPcrLocality", result, ret); result = Tspi_NV_DefineSpace(hnvstore, 0, hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_NV_DefineSpace failed", result, ret); } else { /* * Set the locality number. */ if ( pcr_info_read ) { /* parse the pcr_info_read which is pcr_short_info format */ pdata = (unsigned char *)pcr_info_read; lcp_unloaddata_uint16(&pcr_size, &pdata, 1); pdata += pcr_size; lcp_unloaddata_byte(&rd_locality, &pdata); if ( rd_locality == 0 || rd_locality > 0x1f ) { log_error("Wrong read locality number!\n"); ret = LCP_E_TPM_BAD_LOCALITY; goto exit; } /* * Set PCR composite object. */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, 3, &hrdpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set LocalityAtRelease inside the PCR composite object. * Locality Write for INDEX_AUX should be 3 or 4. */ result = Tspi_PcrComposite_SetPcrLocality(hrdpcrcomp, rd_locality); CHECK_TSS_RETURN_VALUE("Tspi_PcrComposite_SetPcrLocality", result, ret); } if ( pcr_info_write != NULL ) { /* parse the pcr_info_write which is pcr_short_info format */ pdata = (unsigned char *)pcr_info_write; lcp_unloaddata_uint16(&pcr_size, &pdata, 1); pdata += pcr_size; lcp_unloaddata_byte(&wrt_locality, &pdata); if ( wrt_locality == 0 || wrt_locality > 0x1f ) { log_error("Wrong read locality number!\n"); ret = LCP_E_TPM_BAD_LOCALITY; goto exit; } /* * Set PCR composite object. */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, 3, &hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set LocalityAtRelease inside the PCR composite object. * Locality Write for INDEX_AUX should be 3 or 4. */ result = Tspi_PcrComposite_SetPcrLocality(hwrtpcrcomp, wrt_locality); CHECK_TSS_RETURN_VALUE("Tspi_PcrComposite_SetPcrLocality", result, ret); } result = Tspi_NV_DefineSpace(hnvstore, hrdpcrcomp, hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_NV_DefineSpace failed", result, ret); } ret = convert_error(result); exit: /* * Close context for the operation. */ close_tss_context(hcontext); return ret; } /* Release the index * Parameters: * index: the index to be release * passwd: the owner password * passwd_length: the length of the passwd */ lcp_result_t lcp_release_index(uint32_t index, const char *passwd, uint32_t passwd_length) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_HPOLICY hpolicy = NULL_HPOLICY; TSS_HTPM htpm = NULL_HTPM; TSS_RESULT result; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); if ( passwd != NULL ) { result = set_tpm_secret(hcontext, &htpm, &hpolicy, passwd, passwd_length); CHECK_TSS_RETURN_VALUE("set_tpm_secret", result, ret); } /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set the index to be released. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 for setting NV index", result, ret); /* * Release the space according to the parameters: index and datasize. */ result = Tspi_NV_ReleaseSpace(hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_NV_ReleaseSpace for deleting NV index", result, ret); ret = convert_error(result); exit: /* * Close context for the operation. */ close_tss_context(hcontext); return ret; } /* Read the content from the specified index * Parameters: * index: the index to be release * password: the owner password or the auth password of the index * passwd_length: the length of the passwd * read_offset: the offset to read * read_length: the length to read * data_length: the length of the data * data: the data read from the index */ lcp_result_t lcp_read_index(uint32_t index, const char *password, uint32_t pass_length, uint32_t read_offset, uint32_t read_length, uint32_t *data_length, unsigned char *data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_HTPM htpm = NULL_HOBJECT; TSS_RESULT result; TSS_HPOLICY hnvpol; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uint32_t retlen; unsigned char *presult = NULL; unsigned char *policydata = NULL; uint32_t pwd_length = pass_length; uint32_t read_space = 0; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject for nv object", result, ret); /* * Set the index to read */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 for setting NV index", result, ret); if ( password != NULL ) { result = set_nv_secret(hcontext, hnvstore, &hnvpol, password, pwd_length); CHECK_TSS_RETURN_VALUE("set_nv_secret", result, ret); } /* * Data length to read. */ read_space = read_length; if ( (read_length == 0)&&(read_offset == 0) ) { result = Tspi_Context_GetTpmObject(hcontext, &htpm); CHECK_TSS_RETURN_VALUE("Tspi_Context_GetTpmObject", result, ret); result = Tspi_TPM_GetCapability(htpm, TSS_TPMCAP_NV_INDEX, 4, (unsigned char *)&index, &retlen, &presult); CHECK_TSS_RETURN_VALUE("Tspi_TPM_GetCapability", result, ret); presult += retlen - 4; if ( retlen != 0 ) lcp_unloaddata_uint32(&read_space, &presult, 1); else { ret = LCP_E_TPM_BADINDEX; goto exit; } } if ( data == NULL || read_space > *data_length ) { log_info("Data size to read is %d.\n", read_space); log_info("Not enough memory allocated for output data! "\ "Max size allocated is %d.\n", *data_length); ret = LCP_E_INVALID_PARAMETER; goto exit; } /* * Read policy data from NV store. */ log_debug("begin to call the tss Tspi_NV_ReadValue\n"); result = Tspi_NV_ReadValue(hnvstore, read_offset, &read_space, &policydata); /* * Print error massage. */ if ( result != TSS_SUCCESS ) { ret = convert_error(result); goto exit; } ret = LCP_SUCCESS; memcpy_s(data, *data_length, policydata, read_space); *data_length = read_space; exit: close_tss_context(hcontext); return ret; } /* Write the data into the specified index * Parameters: * index: the index to be release * password: the owner password or the auth password of the index * passwd_length: the length of the passwd * write_offset: the offset to write * length: the length of the data * data: the data to write */ lcp_result_t lcp_write_index(uint32_t index, const char *password, uint32_t passwd_length, uint32_t write_offset, uint32_t length, const unsigned char *data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_RESULT result; TSS_HPOLICY hnvpol; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uint32_t pwd_length = passwd_length; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set the index to write */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 for setting NV index", result, ret); if ( password != NULL ) { result = set_nv_secret(hcontext, hnvstore, &hnvpol, password, pwd_length); CHECK_TSS_RETURN_VALUE("set_nv_secret", result, ret); } /* * Write data value to the NV store area. */ result = Tspi_NV_WriteValue(hnvstore, write_offset, length, (unsigned char *)data); /* * Print error massage. */ if ( result != TSS_SUCCESS ) { ret = convert_error(result); goto exit; } ret = LCP_SUCCESS; exit: close_tss_context(hcontext); return ret; } /* create the platform configuration * parameters: * num_indices: the count of the pcr_number * indices: the array of the pcr_numbers * pcr_len: the length of the pcr_hash_value * pcr_hash_val: the array of the pcr_values * locality: the locality value for the pcr_short_info * datalen: the length of produced pconf data * data: the produced pconf data */ lcp_result_t lcp_create_pconf(uint32_t num_indices, uint32_t *indices, uint32_t pcr_len, const unsigned char *pcr_hash_val, unsigned char locality, uint32_t *datalen, unsigned char **data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HPCRS hpcrs = NULL_HPCRS; TSS_HTPM htpm = NULL_HOBJECT; TPM_PCR_SELECTION pselect; TSS_RESULT result = TSS_SUCCESS; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uint32_t idx; unsigned char *pcrval = NULL; uint32_t pcrlen; unsigned char hpcrhash[SHA1_HASH_LEN]; uint32_t hashlen = SHA1_HASH_LEN; uint64_t offset = 0; unsigned char *pdata; unsigned char *pcr_info = NULL; uint32_t pcr_info_size = 0; uint32_t size, index; unsigned char mask; unsigned char *pcr_read = NULL; uint32_t pcr_hash_size = 0; if ( (num_indices == 0) || (indices == NULL) ) return LCP_E_INVALID_PARAMETER; /* calculate the sizeofselect for the pconf*/ ret = calc_sizeofselect(num_indices, indices, &pselect); if ( ret != LCP_SUCCESS ) goto free_memory; /* decide whether need to read the pcr_value from the TPM */ if ( pcr_hash_val != NULL ) { /* use the pcr values from the input */ if ( pcr_len != num_indices * SHA1_HASH_LEN ) { log_error("Hash value length is not correct!\n"); ret = LCP_E_INVALID_PARAMETER; return ret; } if ( Trspi_Hash(TSS_HASH_SHA1, pcr_len, (unsigned char *)pcr_hash_val, hpcrhash) != TSS_SUCCESS ) { log_error("Calculate Hash value for Policy Data error!\n"); ret = LCP_E_HASH_ERROR; return ret; } } else { /* get the pcr value from the tpm*/ result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); /* * Get the TPM object. */ result = Tspi_Context_GetTpmObject(hcontext, &htpm); CHECK_TSS_RETURN_VALUE("Tspi_Context_GetTpmObject", result, ret); /* * Create PCR Composite object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO_SHORT,&hpcrs); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* malloc the data buffer for the pcr value*/ pcr_hash_size = num_indices * SHA1_HASH_LEN; pcr_read = (unsigned char *)malloc(pcr_hash_size); if ( pcr_read == NULL ) { log_error("Out of memory!\n"); ret = LCP_E_OUTOFMEMORY; return ret; } /* read the pcr value for each pcr_number in the pselect */ pdata = pcr_read; for (size = 0; size < pselect.sizeOfSelect; size++) { for (index = 0, mask = 1; index < 8; index++, mask = mask << 1) { if ( pselect.pcrSelect[size] & mask ) { idx = index + (size << 3); /* * Read the PCR value. */ if ( (result = Tspi_TPM_PcrRead(htpm, idx, &pcrlen, &pcrval)) != TSS_SUCCESS ) { log_error("Read PCR value error! PCR Index = %d\n", idx); log_error("TSS API returns error.\n"); ret = LCP_E_TSS_ERROR; goto exit; } /* * Load the PCR value read from TPM. */ lcp_loaddata(SHA1_HASH_LEN, &pdata, pcrval); } } } if ( Trspi_Hash(TSS_HASH_SHA1, pcr_hash_size, pcr_read, hpcrhash) != TSS_SUCCESS ) { log_error("Calculate Hash value for Policy Data error!\n"); ret = LCP_E_HASH_ERROR; return ret; } } /* * Caculate return length and allocate memory. */ pcr_info_size = sizeof(pselect.sizeOfSelect) + pselect.sizeOfSelect + 1 + hashlen; if ( (pcr_info = calloc(1, pcr_info_size)) == NULL ) { log_error("Out of memory!\n"); ret = LCP_E_OUTOFMEMORY; goto exit; } /* *Create the PCR_INFO_SHORT structure. */ offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, pcr_info, &pselect); Trspi_LoadBlob_BYTE(&offset, locality, pcr_info); Trspi_LoadBlob(&offset, hashlen, pcr_info, hpcrhash); *data = pcr_info; *datalen = pcr_info_size; /* * Execute successfully. */ log_info("Successfully Created PConf data!\n"); if ( pcr_read != NULL ) free(pcr_read); return LCP_SUCCESS; exit: close_tss_context(hcontext); free_memory: if ( ret != LCP_SUCCESS ) { if ( pcr_info != NULL ) free(pcr_info); } if ( pselect.pcrSelect != NULL ) free(pselect.pcrSelect); if ( pcr_read != NULL ) free(pcr_read); return ret; } /* Create the policy list for the policy data * the list format is : * { * uint16_t listtype; * uint8_t list_version; * uint8_t listsize; * union { * LCP_HASH HashList[listsize]; * TPM_PCR_INFO_SHORT PCRInfoList[listsize]; * } * Parameters: * src: the input of the data, type, version * data_length: the length of produced policy list * data: the produced policy list * big_endian: create the big or little endian policy list */ lcp_result_t lcp_create_policy_list(pdlist_src_t src, uint32_t *data_length, unsigned char *data, uint8_t big_endian) { uint8_t ver = src.list_version; uint8_t hashlen = SHA1_HASH_LEN; uint8_t listsize = 0; uint32_t read_offset = 0; unsigned char *pdata = data; unsigned char *pread_data; uint16_t select; uint16_t pcr_length; uint16_t list_type; uint32_t len = sizeof(src.type) + sizeof(src.list_version) + sizeof(listsize) + src.listdata_length; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; if ( data == NULL ) { log_error("Pass in NULL pointer when creating LCP Policy List!\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } if ( *data_length < len ) { log_error("the data have no enough space\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } switch (src.type) { case LCP_POLDESC_MLE_UNSIGNED: list_type = LCP_POLDESC_MLE_UNSIGNED; /* * allow the 1 more data length in the file */ if ( (src.listdata_length % hashlen > 1) ||(src.listdata_length / hashlen > 255) ) { log_error("the policy list data is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } listsize = src.listdata_length / hashlen; lcp_loaddata_uint16(list_type, &pdata, big_endian); lcp_loaddata_byte(ver, &pdata); lcp_loaddata_byte(listsize, &pdata); lcp_loaddata(listsize*hashlen, &pdata, src.listdata); *data_length = len - (src.listdata_length % hashlen); break; case LCP_POLDESC_PCONF_UNSIGNED: list_type = LCP_POLDESC_PCONF_UNSIGNED; lcp_loaddata_uint16(list_type, &pdata, big_endian); lcp_loaddata_byte(ver, &pdata); pdata += 1; /* * we will write the list size value * after parse data finished, just skip 1 byte now. * Parse the pconf list first */ pread_data = (unsigned char *)src.listdata; read_offset = 0; listsize =0; for ( ; read_offset < src.listdata_length - 1; listsize++) { /* * we need to read at least 2 byte to get the sizeof select */ lcp_unloaddata_uint16(&select, &pread_data, 1); log_debug("the select of list [%d] is %d\n", listsize, select); pcr_length = select + sizeof(select) + sizeof(TPM_LOCALITY_SELECTION) + SHA1_HASH_LEN; /* check whether the data input is long enough */ if ( (pcr_length + (size_t)(pread_data - src.listdata) -2) > src.listdata_length ) { log_error("the policy list data is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } /* load the data into the policy list */ lcp_loaddata_uint16(select, &pdata, big_endian); lcp_loaddata(pcr_length - 2, &pdata, pread_data); pread_data += pcr_length - 2; read_offset = (uint32_t)(pread_data - src.listdata); /* check whether the data input is too long*/ if ( (listsize == 255) && ((src.listdata_length - read_offset) > 1) ){ log_error("the policy list data is too big\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } } /* * check whether the input is correct, allow 1 more char */ if ( src.listdata_length - read_offset > 1 ) { log_error("the policy list data is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } /* * reset the offset value after parsing data finished. */ pdata = data + 3; lcp_loaddata_byte(listsize, &pdata); *data_length = len - (src.listdata_length - read_offset); break; default: log_error("the policy list type is not supported\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } return LCP_SUCCESS; } /* Create the unsigned lcp policy data in little endian format * Parameters: * version: the policy data version * list_number: the count of the policy list * listdata: the plicylist array * data_length: the length of produced policy data * data: the produced policy data */ lcp_result_t lcp_create_unsigned_poldata(uint8_t version, uint8_t list_number, pdlist_src_t *listdata, uint32_t *data_length, unsigned char *data) { unsigned char policylist[MAX_POLICY_LIST_SIZE]; uint32_t policy_list_len = MAX_POLICY_LIST_SIZE; uint32_t i = 0; unsigned char *pdata = data; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uuid_t uuid = LCP_POLICY_DATA_UUID; if ( *data_length < (sizeof(uuid_t) + sizeof(version) + sizeof(list_number)) ) { log_error("the policy data buf is not enough\n"); ret = LCP_E_INVALID_PARAMETER; return ret; } /* begin to produce the header of the policy data */ lcp_loaddata_uint32(uuid.data1, &pdata, 0); lcp_loaddata_uint16(uuid.data2, &pdata, 0); lcp_loaddata_uint16(uuid.data3, &pdata, 0); lcp_loaddata_uint16(uuid.data4, &pdata, 0); lcp_loaddata(6, &pdata, uuid.data5); lcp_loaddata_byte(version, &pdata); lcp_loaddata_byte(list_number, &pdata); for (i = 0; i < list_number; i++ ) { log_debug("create the policy list %d\n", i); policy_list_len = MAX_POLICY_LIST_SIZE; if ( lcp_create_policy_list(*(listdata+i), &policy_list_len, policylist, 0) ) { ret = LCP_E_CREATE_POLLIST; return ret; } /* check whether the return buffer is enough */ if ( ((pdata -data) + policy_list_len) > *data_length ) { log_error("the policy data buf is not enough\n"); ret = LCP_E_INVALID_PARAMETER; return ret; } lcp_loaddata(policy_list_len, &pdata, policylist); } *data_length = (uint32_t)(pdata -data); return LCP_SUCCESS; } /* Create the lcp policy in big endian format * Parameters: * policy: the input infoes for policy, for example, the version, type... * length: the length of the policy data or the mle hash value * policy_dataorhash: the policy data or the mle hash value * data_length: the length of the produced policy * data: the length of the produced policy */ lcp_result_t lcp_create_policy(lcp_policy_t *policy, uint32_t length, const unsigned char *policy_dataorhash, uint32_t *data_length, unsigned char *data) { unsigned char polhash[SHA1_HASH_LEN] = { 0 }; uint32_t policy_length = DATASIZE_POL; unsigned char hashval[SHA1_HASH_LEN]; uint32_t hash_len = SHA1_HASH_LEN; unsigned char *pdata = data; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; if ( policy->policy_type == LCP_POLTYPE_SIGNED ) { log_error("signed policy is not support\n"); result = LCP_E_INVALID_PARAMETER; return result; } if ( *data_length < policy_length ) { log_error("the data buf is not enough\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } lcp_loaddata_byte(policy->version, &pdata); lcp_loaddata_byte(policy->hash_alg, &pdata); lcp_loaddata_byte(policy->policy_type, &pdata); lcp_loaddata_byte(policy->sinit_revocation_counter, &pdata); lcp_loaddata_uint32(policy->policy_control, &pdata, 1); lcp_loaddata_uint16(policy->reserved[0], &pdata, 1); lcp_loaddata_uint16(policy->reserved[1], &pdata, 1); lcp_loaddata_uint16(policy->reserved[2], &pdata, 1); if ( policy->policy_type == LCP_POLTYPE_UNSIGNED ) { if ( Trspi_Hash(TSS_HASH_SHA1, length, (unsigned char *)policy_dataorhash, hashval) != TSS_SUCCESS ) { log_error("Calculate Hash value for Policy Data error!\n"); result = LCP_E_HASH_ERROR; return result; } lcp_loaddata(hash_len, &pdata, hashval); } else if ( policy->policy_type == LCP_POLTYPE_HASHONLY ) { if ( length != (policy_length - (DATASIZE_POL - SHA1_HASH_LEN)) ) { log_error("the hash length is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } lcp_loaddata(length, &pdata, (unsigned char *)policy_dataorhash); } else { lcp_loaddata(SHA1_HASH_LEN, &pdata, polhash); } *data_length = policy_length; return LCP_SUCCESS; } /* get the tpm capibilities * Parameters: * caparea: the capability to get * subcaplen: the length of the sub capablity value * subcap: the sub capolibity to get * outlen: the length of return value * resp_data: the response data */ lcp_result_t lcp_get_tpmcap(uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *resp_data) { return lcp_get_tpmcap_auth(NULL, 0, caparea, subcaplen, subcap, outlen, resp_data); } /* get the tpm capibilities * Parameters: * password: ownerauth * psswd_length: length of ownerauth * caparea: the capability to get * subcaplen: the length of the sub capablity value * subcap: the sub capolibity to get * outlen: the length of return value * resp_data: the response data */ lcp_result_t lcp_get_tpmcap_auth(const char *password, uint32_t passwd_length, uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *resp_data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HTPM htpm = NULL_HTPM; TSS_HPOLICY hpolicy = NULL_HPOLICY; TSS_RESULT result; uint32_t i = 0; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; unsigned char *resp; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); if ( password != NULL ) { result = set_tpm_secret(hcontext, &htpm, &hpolicy, password, passwd_length); CHECK_TSS_RETURN_VALUE("set_tpm_secret", result, ret); } else { /* * Get the TPM object. */ result = Tspi_Context_GetTpmObject(hcontext, &htpm); CHECK_TSS_RETURN_VALUE("Tspi_Context_GetTpmObject", result, ret); } result = Tspi_TPM_GetCapability(htpm, caparea, subcaplen, (unsigned char *)subcap, outlen, &resp); CHECK_TSS_RETURN_VALUE("Tspi_TPM_GetCapability", result, ret); log_debug("The response data is:\n" ); for (i = 0; i < *outlen; i++) { log_debug("%02x ", resp[i]); if ( i%16 == 15 ) log_debug("\n"); } log_debug("\n"); memcpy_s(resp_data,*outlen, resp, *outlen); ret = LCP_SUCCESS; exit: close_tss_context(hcontext); return ret; } tboot-1.10.5/deprecated/lcptools/lcptools.h0000644000000000000000000001711214210363175017026 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LCPTOOLS_H__ #define __LCPTOOLS_H__ #define NULL_HCONTEXT 0 #define NULL_HOBJECT 0 #define NULL_HNVSTORE 0 #define NULL_HPCRS NULL_HOBJECT #define NULL_HPOLICY NULL_HOBJECT #define NULL_HTPM NULL_HOBJECT /* * Define the return value of the commands. */ typedef uint16_t lcp_result_t; #define LCP_SUCCESS 0 /* The command execute successful */ #define LCP_E_INVALID_PARAMETER 1 /* The input parameter not match the requirement */ #define LCP_E_NO_INDEXVALUE 2 /* Haven't input index value */ #define LCP_E_NO_DATASIZE 3 /* Haven't input data size value */ #define LCP_E_TSS_ERROR 4 /* TSS API revoke failed */ #define LCP_E_NV_AREA_EXIST 5 /* NV area reference have been defined, can't be defined again */ #define LCP_E_TPM_BADINDEX 6 /* Index value is invalid */ #define LCP_E_TPM_BAD_DATASIZE 7 /* The data size is invalid */ #define LCP_E_TPM_MAXNVWRITES 8 /* Exceed the max write time of NV */ #define LCP_E_NO_AUTH 9 /* Haven't input authentication value */ #define LCP_E_NV_AREA_NOT_EXIST 10 /* NV area reference haven't been defined before, can't be released */ #define LCP_E_TPM_AREA_LOCKED 11 /* The NV area is locked and not writeable */ #define LCP_E_GETCAP_REP_ERROR 12 /* Get capability returns incorrect response */ #define LCP_E_NO_PER_VALUE 13 /* Haven't input permission value */ #define LCP_E_INVALID_HANDLER 14 /* Invalid handler is returned */ #define LCP_E_AUTH_CONFLICT 15 /* Authentication method conflict */ #define LCP_E_AUTH_FAIL 16 /* Authentication failed */ #define LCP_E_OWNER_SET 17 /* TSS return error */ #define LCP_E_TPM_WRONGPCRVALUE 18 /* TSS return error */ #define LCP_E_INVALID_STRUCTURE 19 /* TSS return error */ #define LCP_E_NOWRITE 20 /* TSS return error */ #define LCP_E_TPM_BAD_LOCALITY 21 /* TSS return error */ #define LCP_E_TPM_BAD_PRESENCE 22 /* TSS return error */ #define LCP_E_TPM_DISABLED_CMD 23 /* TSS return error */ #define LCP_E_TPM_NOSPACE 24 /* TSS return error */ #define LCP_E_TPM_NOT_FULLWRITE 25 /* TSS return error */ #define LCP_E_NO_SUCH_PARAMETER 26 /* Can't find such kind of parameter */ #define LCP_E_CREATE_POLLIST 27 /* Create Polict List error */ #define LCP_E_OUTOFMEMORY 28 /* Failed memory assign */ #define LCP_E_HASH_ERROR 29 /* Failed when hash */ #define LCP_E_NO_INPUTPARA 30 /* No parameter has been input */ #define LCP_E_COMD_INTERNAL_ERR 31 /* Other err when run the command */ #define SHA1_HASH_LEN 20 #define SHA256_HASH_LEN 32 typedef struct { uint32_t index; uint32_t permission; uint32_t size; uint8_t r_loc; uint8_t w_loc; } in_nv_definespace_t; typedef struct { uint8_t algorithm; uint8_t list_version; uint16_t type; uint32_t listdata_length; unsigned char *listdata; } pdlist_src_t; lcp_result_t lcp_define_index(in_nv_definespace_t *p_in_defspace, const char *auth, uint32_t auth_length, const char *passwd, uint32_t passwd_length, const unsigned char *read_srtm, const unsigned char *write_srtm); lcp_result_t lcp_release_index(uint32_t index_value, const char *passwd, uint32_t passwd_length); lcp_result_t lcp_read_index(uint32_t index_value, const char* password, uint32_t pass_length, uint32_t read_offset, uint32_t read_length, uint32_t* datalength, unsigned char* data); lcp_result_t lcp_write_index(uint32_t index_value, const char* password, uint32_t passwd_length, uint32_t write_offset, uint32_t fleng, const unsigned char* policydata); lcp_result_t lcp_create_pconf(uint32_t num_indices, uint32_t* indices, uint32_t pcr_len, const unsigned char* pcr_hash_val, unsigned char locality, uint32_t* dataLen, unsigned char** srtmdata); lcp_result_t lcp_create_policy_list(pdlist_src_t policylist_src, uint32_t* policy_list_length, unsigned char* policy_list, uint8_t big_endian); lcp_result_t lcp_create_unsigned_poldata(uint8_t policydata_version, uint8_t list_number, pdlist_src_t * listdata, uint32_t* data_length, unsigned char* data); lcp_result_t lcp_create_policy(lcp_policy_t *policy, uint32_t length, const unsigned char* policy_dataorhash, uint32_t* data_length, unsigned char* data); lcp_result_t lcp_get_tpmcap(uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *respdata); lcp_result_t lcp_get_tpmcap_auth(const char *password, uint32_t passwd_length, uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *respdata); #endif tboot-1.10.5/deprecated/lcptools/lcputils.c0000644000000000000000000004346214210363175017030 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * lcputils.c * * This file implements all common functions used by the commands * and key functions. * */ #include #include #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static const char *ret_info[] = { NULL, /* 0-LCP_SUCCESS, Each command will has its own success message.*/ "Incorrect parameter input.", /* 1-LCP_E_INVALID_PARAMETER */ "Please input the index value", /* 2-LCP_E_NO_INDEXVALUE */ "Please input the data size to be defined", /* 3-LCP_E_NO_DATASIZE */ "TSS API failed", /* 4-LCP_E_TSS_ERROR */ "Index has already been defined.", /* 5-LCP_E_NV_AREA_EXIST */ "The index is incorrect or wrong "\ "permission value.", /* 6-LCP_E_TPM_BADINDEX */ "The size of the data parameter is bad or "\ "inconsistent with the referenced key.",/* 7-LCP_E_TPM_BAD_DATASIZE */ "The maximum number of NV writes without an owner has been reached.", /* 8-LCP_E_TPM_MAXNVWRITES */ "Please input authentication value.", /* 9-LCP_E_NO_AUTH */ "Index does not exist.", /* 10-LCP_E_NV_AREA_NOT_EXIST*/ "TPM_AREA_LOCKED. The index has been locked.", /* 11-LCP_E_TPM_AREA_LOCKED */ "Incorrect response when getting capability.", /* 12-LCP_E_GETCAP_REP_ERROR */ "Please input the permission value for the index to be defined!", /* 13-LCP_E_NO_PER_VALUE */ "Invalid handler is returned.", /* 14-LCP_E_INVALID_HANDLER */ "Authentication method conflict.", /* 15-LCP_E_AUTH_CONFLICT */ "Authentication failed. Password or authencation value not match", /* 16-LCP_E_AUTH_FAIL */ "TPM owner set error!", /* 17-LCP_E_OWNER_SET */ "Wrong PCR value!", /* 18-LCP_E_TPM_WRONGPCRVALUE*/ "Invalid structure!", /* 19-LCP_E_INVALID_STRUCTURE*/ "TPM No Write error!", /* 20-LCP_E_NOWRITE */ "Bad locality error!", /* 21-LCP_E_TPM_BAD_LOCALITY */ "Bad presence error!", /* 22-LCP_E_TPM_BAD_PRESENCE */ "TPM disabled command error!", /* 23-LCP_E_TPM_DISABLED_CMD */ "TPM no space error!", /* 24-LCP_E_TPM_NOSPACE */ "TPM not full write error!", /* 25-LCP_E_TPM_NOT_FULLWRITE*/ "Incorrect parameter input.", /* 26-LCP_E_NO_SUCH_PARAMETER*/ "Creat policy_list error", /* 27-LCP_E_CREATE_POLLIST */ "Failed assign memory!", /* 28-LCP_E_OUTOFMEMORY */ "Hash failed!", /* 29-LCP_E_HASH_ERROR */ "Haven't input any parameter, please use -h for help", /* 30-LCP_E_NO_INPUTPARA */ "Internal error when executing the command",/* 31-LCP_E_COMD_INTERNAL_ERR*/ NULL }; /* * Parse the input param and return the corresponding option value * If the parameter is not correct, it will return -1 */ uint32_t parse_input_option(param_option_t *table, const char *arg) { param_option_t *p = table; uint32_t ret_value = -1; while (p && p->param){ if ( strcasecmp(arg, p->param) == 0 ) { ret_value = p->option; break; } p++; } return ret_value; } /* * Convert the string input into number. * This function can support both decimalist and hex */ int strtonum(const char *in_para, unsigned int *num_out) { int ret_value = -1; char* endptr; uint64_t test_value; if( in_para == NULL || num_out == NULL ) return -1; errno = 0; *num_out = (unsigned int)strtoul(in_para, &endptr, 0); if ( (*endptr == '\0') && (*in_para != '\0') && (errno == 0) ){ test_value = (uint64_t)strtoull(in_para, &endptr, 0); if ( test_value == (uint64_t)(*num_out) ) ret_value = 0; } return ret_value; } const char * bool_to_str(int b) { return b ? "TRUE" : "FALSE"; } void print_help(const char *usage_str, const char * option_string[]) { uint16_t i = 0; if ( usage_str == NULL || option_string == NULL ) return; printf("\nUsage: %s\n", usage_str); for (; option_string[i] != 0; i++) printf("%s", option_string[i]); } void print_error(lcp_result_t ret_value) { log_error("\t%s\n", ret_info[ret_value]); } /* * Convert TSS error codes to our defined error codes. */ lcp_result_t convert_error(TSS_RESULT result) { lcp_result_t ret; switch (result & 0xfff) { case TSS_SUCCESS: ret = LCP_SUCCESS; break; case TSS_E_INVALID_HANDLE: ret = LCP_E_INVALID_HANDLER; break; case TSS_E_NV_AREA_EXIST: ret = LCP_E_NV_AREA_EXIST; break; case TSS_E_NV_AREA_NOT_EXIST: ret = LCP_E_NV_AREA_NOT_EXIST; break; case TSS_E_BAD_PARAMETER: ret = LCP_E_INVALID_PARAMETER; break; case TSS_E_INTERNAL_ERROR: ret = LCP_E_COMD_INTERNAL_ERR; break; case TPM_E_BADINDEX: ret = LCP_E_TPM_BADINDEX; break; case TPM_E_AUTH_CONFLICT: ret = LCP_E_AUTH_CONFLICT; break; case TPM_E_AUTHFAIL: ret = LCP_E_AUTH_FAIL; break; case TPM_E_OWNER_SET: ret = LCP_E_OWNER_SET; break; case TPM_E_BAD_DATASIZE: ret = LCP_E_TPM_BAD_DATASIZE; break; case TPM_E_MAXNVWRITES: ret = LCP_E_TPM_MAXNVWRITES; break; case TPM_E_INVALID_STRUCTURE: ret = LCP_E_INVALID_STRUCTURE; break; case TPM_E_PER_NOWRITE: ret = LCP_E_NOWRITE; break; case TPM_E_AREA_LOCKED: ret = LCP_E_TPM_AREA_LOCKED; break; case TPM_E_BAD_LOCALITY: ret = LCP_E_TPM_BAD_LOCALITY; break; case TPM_E_BAD_PRESENCE: ret = LCP_E_TPM_BAD_PRESENCE; break; case TPM_E_DISABLED_CMD: ret = LCP_E_TPM_DISABLED_CMD; break; case TPM_E_NOSPACE: ret = LCP_E_TPM_NOSPACE; break; case TPM_E_NOT_FULLWRITE: ret = LCP_E_TPM_NOT_FULLWRITE; break; case TPM_E_WRONGPCRVAL: ret = LCP_E_TPM_WRONGPCRVALUE; break; default: ret = LCP_E_TSS_ERROR; } return ret; } void print_hexmsg(const char *header_msg, int datalength, const unsigned char *data) { int i; log_info("%s", header_msg); for (i = 0; i < datalength; i++) { log_info("%02x ", *(data + i)); if ( i % 16 == 15 ) log_info("\n"); } log_info("\n"); } /* split the input string in the format: num1,num2,...,numN * into the numeric array = {num1, num2, ... , numN} */ void str_split(char *str_in, uint32_t ints[], unsigned int *nr_ints) { unsigned int nr = 0; char *str = NULL; while ( true ) { str = strsep(&str_in, ","); if ( str == NULL || nr == *nr_ints ) break; ints[nr++] = strtoul(str, NULL, 0); } if ( nr == *nr_ints && str != NULL ) log_error("Error: too many items in list\n"); *nr_ints = nr; } uint16_t lcp_decode_uint16(const unsigned char *in, uint8_t big_endian) { uint16_t temp = 0; if ( in == NULL ) return 0; if ( big_endian ) { temp = (in[1] & 0xFF); temp |= (in[0] << 8); } else { temp = (in[0] & 0xFF); temp |= (in[1] << 8); } return temp; } void lcp_uint32toarray(uint32_t i, unsigned char *out, uint8_t big_endian) { if ( out == NULL ) return; if ( big_endian ) { out[0] = (unsigned char) ((i >> 24) & 0xFF); out[1] = (unsigned char) ((i >> 16) & 0xFF); out[2] = (unsigned char) ((i >> 8) & 0xFF); out[3] = (unsigned char) (i & 0xFF); } else { out[3] = (unsigned char) ((i >> 24) & 0xFF); out[2] = (unsigned char) ((i >> 16) & 0xFF); out[1] = (unsigned char) ((i >> 8) & 0xFF); out[0] = (unsigned char) (i & 0xFF); } } void lcp_uint16toarray(uint16_t i, unsigned char *out, uint8_t big_endian) { if ( out == NULL ) return; if ( big_endian ) { out[0] = (unsigned char) ((i >> 8) & 0xFF); out[1] = (unsigned char) (i & 0xFF); } else { out[1] = (unsigned char) ((i >> 8) & 0xFF); out[0] = (unsigned char) (i & 0xFF); } } uint32_t lcp_decode_uint32(const unsigned char *y, uint8_t big_endian) { uint32_t x = 0; if ( y == NULL ) return 0; if ( big_endian ) { x = y[0]; x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[3] & 0xFF)); } else { x = y[3]; x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[0] & 0xFF)); } return x; } void lcp_loaddata_uint32(uint32_t in, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL ) return; if ( *blob != NULL ) lcp_uint32toarray(in, *blob, big_endian); *blob += sizeof(in); } void lcp_loaddata_uint16(uint16_t in, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL ) return; if ( *blob != NULL ) lcp_uint16toarray(in, *blob, big_endian); *blob += sizeof(in); } void lcp_unloaddata_uint32(uint32_t *out, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL || out == NULL ) return; *out = lcp_decode_uint32(*blob, big_endian); *blob += sizeof(*out); } void lcp_unloaddata_uint16(uint16_t *out, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL || out == NULL ) return; *out = lcp_decode_uint16(*blob, big_endian); *blob += sizeof(*out); } void lcp_loaddata_byte(unsigned char data, unsigned char **blob) { if ( blob == NULL ) return; if ( *blob != NULL ) **blob = data; (*blob)++; } void lcp_unloaddata_byte(unsigned char *dataout, unsigned char **blob) { if ( blob == NULL || dataout == NULL ) return; *dataout = **blob; (*blob)++; } void lcp_loaddata(uint32_t size, unsigned char **container, unsigned char *object) { if ( container == NULL || object == NULL ) return; if ( *container ) memcpy_s(*container, size, object, size); (*container) += size; } void lcp_unloaddata(uint32_t size, unsigned char **container, unsigned char *object) { if ( *container == NULL || object == NULL ) return; memcpy_s(object, size, *container, size); (*container) += size; } /* init the context in the TSS */ TSS_RESULT init_tss_context(TSS_HCONTEXT *hcontext) { TSS_RESULT result; result = Tspi_Context_Create(hcontext); if ( (result) != TSS_SUCCESS ) return result; result = Tspi_Context_Connect(*hcontext, NULL); return result; } /* close the TSS context */ void close_tss_context(TSS_HCONTEXT hcontext) { if ( hcontext != NULL_HCONTEXT ) { Tspi_Context_FreeMemory(hcontext, NULL); Tspi_Context_Close(hcontext); } } /* Set the password to the tpm object of the tss context */ TSS_RESULT set_tpm_secret(TSS_HCONTEXT hcontext, TSS_HTPM *htpm, TSS_HPOLICY *hpolicy, const char *passwd, uint32_t passwd_length) { TSS_RESULT result; /* * Get TPM object */ result = Tspi_Context_GetTpmObject(hcontext, htpm); if ( result != TSS_SUCCESS ) return result; result = Tspi_GetPolicyObject(*htpm, TSS_POLICY_USAGE, hpolicy); if ( result != TSS_SUCCESS ) return result; /* * Set password */ result = Tspi_Policy_SetSecret(*hpolicy, TSS_SECRET_MODE_PLAIN, passwd_length, (unsigned char *)passwd); return result; } /* Create the NV policy object and assign it to the NV object */ TSS_RESULT set_nv_secret(TSS_HCONTEXT hcontext, TSS_HNVSTORE hnvstore, TSS_HPOLICY *hpolobj, const char *auth, uint32_t auth_len) { TSS_RESULT result; /* * Create policy object for the NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, hpolobj); if ( result != TSS_SUCCESS ) return result; /* * Set password */ result = Tspi_Policy_SetSecret(*hpolobj, TSS_SECRET_MODE_PLAIN, auth_len, (unsigned char *)auth); if ( result != TSS_SUCCESS ) return result; /* * Set password */ result = Tspi_Policy_AssignToObject(*hpolobj, hnvstore); return result; } /* calculate the size of select for the pcr selection */ lcp_result_t calc_sizeofselect(uint32_t num_indices, uint32_t *indices, TPM_PCR_SELECTION *pselect) { uint32_t i; uint32_t idx; uint16_t bytes_to_hold; lcp_result_t ret; idx = indices[0]; bytes_to_hold = (idx / 8) + 1; log_debug("bytes to hold is %d.\n", bytes_to_hold); /* * Create selection index first. */ if ( (pselect->pcrSelect = malloc(bytes_to_hold)) == NULL ) { ret = LCP_E_OUTOFMEMORY; return ret; } pselect->sizeOfSelect = bytes_to_hold; memset_s(pselect->pcrSelect, bytes_to_hold, 0); /* * set the bit in the selection structure */ pselect->pcrSelect[idx / 8] |= (1 << (idx % 8)); for (i = 1; i < num_indices; i++) { idx = indices[i]; bytes_to_hold = (idx / 8) + 1; log_debug("bytes to hold is %d.\n", bytes_to_hold); log_debug("size of select is %d.\n", pselect->sizeOfSelect); if ( pselect->sizeOfSelect < bytes_to_hold ) { if ( (pselect->pcrSelect = realloc(pselect->pcrSelect, bytes_to_hold)) == NULL ) { ret = LCP_E_OUTOFMEMORY; return ret; } /* * set the newly allocated bytes to 0 */ memset_s(&pselect->pcrSelect[pselect->sizeOfSelect], bytes_to_hold - pselect->sizeOfSelect, 0); pselect->sizeOfSelect = bytes_to_hold; } pselect->pcrSelect[idx / 8] |= (1 << (idx % 8)); } return LCP_SUCCESS; } void print_locality(unsigned char loc) { char s[32] = ""; if ( loc & ~0x1f ) snprintf_s_i(s, sizeof(s), "unknown (%x)", loc); else { if ( !(loc & 0x1f) ) strcat_s(s, sizeof(s), "--, "); if ( loc & TPM_LOC_ZERO ) strcat_s(s, sizeof(s), "0, "); if ( loc & TPM_LOC_ONE ) strcat_s(s, sizeof(s), "1, "); if ( loc & TPM_LOC_TWO ) strcat_s(s, sizeof(s), "2, "); if ( loc & TPM_LOC_THREE ) strcat_s(s, sizeof(s), "3, "); if ( loc & TPM_LOC_FOUR ) strcat_s(s, sizeof(s), "4, "); /* remove trailing ", " */ s[strnlen_s(s, sizeof(s)) - 2] = '\0'; } log_info("%s", s); } void print_permissions(UINT32 perms, const char *prefix) { if ( perms == 0 ) log_info("%s --\n", prefix); if ( perms & TPM_NV_PER_READ_STCLEAR ) log_info("%s TPM_NV_PER_READ_STCLEAR\n", prefix); if ( perms & TPM_NV_PER_AUTHREAD ) log_info("%s TPM_NV_PER_AUTHREAD\n", prefix); if ( perms & TPM_NV_PER_OWNERREAD ) log_info("%s TPM_NV_PER_OWNERREAD\n", prefix); if ( perms & TPM_NV_PER_PPREAD ) log_info("%s TPM_NV_PER_PPREAD\n", prefix); if ( perms & TPM_NV_PER_GLOBALLOCK ) log_info("%s TPM_NV_PER_GLOBALLOCK\n", prefix); if ( perms & TPM_NV_PER_WRITE_STCLEAR ) log_info("%s TPM_NV_PER_WRITE_STCLEAR\n", prefix); if ( perms & TPM_NV_PER_WRITEDEFINE ) log_info("%s TPM_NV_PER_WRITEDEFINE\n", prefix); if ( perms & TPM_NV_PER_WRITEALL ) log_info("%s TPM_NV_PER_WRITEALL\n", prefix); if ( perms & TPM_NV_PER_AUTHWRITE ) log_info("%s TPM_NV_PER_AUTHWRITE\n", prefix); if ( perms & TPM_NV_PER_OWNERWRITE ) log_info("%s TPM_NV_PER_OWNERWRITE\n", prefix); if ( perms & TPM_NV_PER_PPWRITE ) log_info("%s TPM_NV_PER_PPWRITE\n", prefix); } tboot-1.10.5/deprecated/lcptools/lcputils.h0000644000000000000000000001210614210363175017024 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LCPUTILS_H__ #define __LCPUTILS_H__ /* * Log message functions */ #define log_message(dest, fmt, ...) fprintf(dest, fmt, ## __VA_ARGS__) /* * Error logging */ #define log_error(fmt, ...) log_message(stderr, fmt, ##__VA_ARGS__) /* * Info Logging */ #define log_info(fmt, ...) log_message(stdout, fmt, ##__VA_ARGS__) #define LCP_DEBUG 1 #ifdef LCP_DEBUG #define log_debug(fmt, ...) log_message(stdout, fmt, ##__VA_ARGS__) #else #define log_debug(fmt, ...) #endif #define CHECK_TSS_RETURN_VALUE(api_name, result, ret) \ do { if ((result) != TSS_SUCCESS) { \ log_error("%s failed: %s (0x08%x)\n", (api_name), \ Trspi_Error_String((result)), \ (result)); \ (ret) = LCP_E_TSS_ERROR; \ goto exit; \ } \ }while (0) typedef struct { const char *param; uint32_t option; } param_option_t; uint32_t parse_input_option(param_option_t *table, const char *arg); int strtonum(const char *in_para, unsigned int *num_out); const char *bool_to_str(int b); void print_help(const char *usage_str, const char *option_string[]); void print_error(lcp_result_t ret_value); lcp_result_t convert_error(TSS_RESULT result); void print_hexmsg(const char *header_msg, int datalength, const unsigned char *data); uint16_t lcp_decode_uint16(const unsigned char *in, uint8_t big_endian); void lcp_uint32toarray(uint32_t i, unsigned char *out, uint8_t big_endian); void lcp_uint16toarray(uint16_t i, unsigned char *out, uint8_t big_endian); uint32_t lcp_decode_uint32(const unsigned char *y, uint8_t big_endian); void lcp_loaddata_uint32(uint32_t in, unsigned char **blob, uint8_t big_endian); void lcp_loaddata_uint16(uint16_t in, unsigned char **blob, uint8_t big_endian); void lcp_unloaddata_uint32(uint32_t * out, unsigned char **blob, uint8_t big_endian); void lcp_unloaddata_uint16(uint16_t *out, unsigned char **blob, uint8_t big_endian); void lcp_loaddata_byte(unsigned char data, unsigned char **blob); void lcp_unloaddata_byte(unsigned char *dataout, unsigned char **blob); void lcp_loaddata(uint32_t size, unsigned char **container, unsigned char *object); void lcp_unloaddata(uint32_t size, unsigned char **container, unsigned char *object); TSS_RESULT init_tss_context(TSS_HCONTEXT *hcontext); void close_tss_context(TSS_HCONTEXT hcontext); TSS_RESULT set_tpm_secret(TSS_HCONTEXT hcontext, TSS_HTPM *htpm, TSS_HPOLICY *hpolicy, const char *passwd, uint32_t passwd_length); TSS_RESULT set_nv_secret(TSS_HCONTEXT hcontext, TSS_HNVSTORE hnvstore, TSS_HPOLICY *hpolobj, const char *auth, uint32_t auth_len); lcp_result_t calc_sizeofselect(uint32_t num_indices, uint32_t *indices, TPM_PCR_SELECTION *pselect); void print_locality(unsigned char loc); void print_permissions(UINT32 perms, const char *prefix); void str_split(char *str_in, uint32_t ints[], unsigned int *number); #endif tboot-1.10.5/deprecated/lcptools/lock.c0000644000000000000000000001033714210363175016114 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * nvlock.c * * Command: tpmnv_lock. * * This command can lock the TPM NV Storage. * */ #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static int force = 0; static int help_input = 0; static const char *short_option = "hf"; static const char *usage_string = "tpmnv_lock [-f] [-h]"; static const char * option_strings[] ={ "-f force to lock.\n", "-h help. Will print out this help message.\n" ,0 }; /* function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'f': force = 1; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char *argv[]) { char c; in_nv_definespace_t in_defspace; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if (help_input) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Check whether force to lock. */ if ( force == 0 ) { /* * If haven't input force to lock, reminder to confirm * whether lock or not. */ do { log_info("Really want to lock TPM NV? (Y/N) "); c = getchar() | ' '; } while ( (c != 'n') && (c != 'y') ); if ( c == 'n') { ret_value = LCP_SUCCESS; return ret_value; } } /* * Set index as TPM_NV_INDEX_LOCK, datasize as 0 to lock TPM NV */ in_defspace.index = TPM_NV_INDEX_LOCK; in_defspace.permission = 0; in_defspace.size = 0; ret_value = lcp_define_index(&in_defspace, NULL, 0, NULL, 0, NULL, NULL); if ( ret_value == LCP_SUCCESS ) { /* * Execute successfully. */ log_info("Successfully locked TPM NV!\n"); return ret_value; } _error_end: /* * Error when execute. */ log_error("\nCommand NvLock failed:\n"); print_error(ret_value); return ret_value; } tboot-1.10.5/deprecated/lcptools/readpol.c0000644000000000000000000002053614210363175016614 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * readpol.c * Command: lcp_readpol. * This command can read LCP policy from TPM NV Storage. */ #include #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define BUFFER_SIZE 1024 static uint32_t index_value = 0; static char* file = NULL; static uint32_t size = 0; static char *password = NULL; static uint32_t passwd_length = 0; static int help_input = 0; static const char *short_option = "hi:f:s:p:"; static const char *usage_string = "lcp_readpol -i index_value " "[-s read_size] [-f output_file] [-p passwd] [-h]"; static const char *option_strings[] = { "-i index value: uint32/string.\n" "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n" "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n" "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-f file_name: string. Name of file to store the policy data in. \n", "-s size to read: uint32. Value size to read from NV store.\n", "-p password: string. \n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'f': file = optarg; break; case 'p': password = optarg; passwd_length = strnlen_s(password, 4096); break; case 's': if ( strtonum(optarg, &size) ) return LCP_E_INVALID_PARAMETER; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } static void print_hash(lcp_hash_t *hash) { unsigned int i; for ( i = 0; i < sizeof(hash->sha1)/sizeof(hash->sha1[0]); i++ ) log_info("%02x ", hash->sha1[i]); log_info("\n"); } static void print_policy(unsigned char* pol_buf, uint32_t buf_len) { lcp_policy_t pol; unsigned char *pdata = pol_buf; static const char *pol_types[] = {"LCP_POLTYPE_HASHONLY", "LCP_POLTYPE_UNSIGNED", "LCP_POLTYPE_SIGNED", "LCP_POLTYPE_ANY", "LCP_POLTYPE_FORCEOWNERPOLICY"}; if ( buf_len < (offsetof(lcp_policy_t, policy_hash) + sizeof(pol.policy_hash.sha1) + 1) ) { log_error("policy buffer is too small\n"); return; } lcp_unloaddata_byte(&pol.version, &pdata); lcp_unloaddata_byte(&pol.hash_alg, &pdata); lcp_unloaddata_byte(&pol.policy_type, &pdata); lcp_unloaddata_byte(&pol.sinit_revocation_counter, &pdata); lcp_unloaddata_uint32(&pol.policy_control, &pdata, 1); lcp_unloaddata_uint16(&pol.reserved[0], &pdata, 1); lcp_unloaddata_uint16(&pol.reserved[1], &pdata, 1); lcp_unloaddata_uint16(&pol.reserved[2], &pdata, 1); lcp_unloaddata(sizeof(pol.policy_hash.sha1), &pdata, (unsigned char *)&pol.policy_hash); log_info("version: %d\n", (int)pol.version); log_info("hash_alg: %d\n", (int)pol.hash_alg); log_info("policy_type: %d", (int)pol.policy_type); if ( pol.policy_type < sizeof(pol_types)/sizeof(pol_types[0]) ) log_info(" - %s\n", pol_types[pol.policy_type]); else log_info(" - unknown\n"); log_info("sinit_revocation_counter: %d\n", (int)pol.sinit_revocation_counter); log_info("policy_control: %x\n", pol.policy_control); log_info("policy_hash: "); print_hash(&pol.policy_hash); } int main (int argc, char *argv[]) { FILE *p_file = NULL; unsigned char policy_data[BUFFER_SIZE]; uint32_t data_length = BUFFER_SIZE; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto exit; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Check whether parameter of index value has been input. */ if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto exit; } if ( size == 0 ) log_info("No size has been specified. Will read all index data.\n"); /* * Read NV data from TPM NV store. */ ret_value = lcp_read_index(index_value, password, passwd_length, 0, size, &data_length, policy_data); if ( ret_value ) goto exit; if ( file != NULL ) { /* * Write policy data into file. */ p_file = fopen(file, "wb"); if ( !p_file ) { log_error("Open file %s error!\n", file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } if ( data_length != fwrite(policy_data, 1, data_length, p_file) ) { log_error("Write policy data into file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } } else { print_hexmsg("the policy is:\n", data_length, policy_data); print_policy(policy_data, data_length); } exit: if ( p_file != NULL ) fclose(p_file); if ( ret_value != LCP_SUCCESS ) { log_error("\nCommand ReadPol failed:\n"); print_error(ret_value); } else log_info("Successfully read value from index: 0x%08x.\n", index_value); return ret_value; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/deprecated/lcptools/relindex.c0000644000000000000000000001231714210363175016776 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * relindex.c * * Command: tpmnv_relindex. * * This command can release the index defined in TPM NV Storage. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static uint32_t index_value = 0; static char *password = NULL; static uint32_t passwd_length = 0; static int help_input = 0; static const char *short_option = " hi:p:"; static const char *usage_string = "tpmnv_relindex -i index -p passwd [-h]"; static const char * option_strings[] ={ "-i index value: uint32/string.\n"\ "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n"\ "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n"\ "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-p password: string. \n", "-h help. Will print out this help message.\n", 0 }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc,(char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'p': password = optarg; passwd_length = strnlen_s(password, 4096); break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char *argv[]) { lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse the parameters input to decide * what parameters will be passed to TSS API. */ ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto _error_end; } if ( password == NULL ) { ret_value = LCP_E_AUTH_FAIL; log_error("No password input! Password is needed to release index.\n"); goto _error_end; } ret_value = lcp_release_index(index_value, password, passwd_length); if ( ret_value == LCP_SUCCESS ) { /* * Execute successfully. */ log_info("Successfully released index 0x%08x \n", index_value); return ret_value; } _error_end: /* * Error when execute. */ log_error("\nCommand RelIndex failed:\n"); print_error(ret_value); return ret_value; } tboot-1.10.5/deprecated/lcptools/writepol.c0000644000000000000000000001626614210363175017040 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER 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. */ /* * writepol.c * Command: lcp_writepol. * This command can write LCP policy into TPM NV Storage. */ #include #include #include #include #include #include #include #define PRINT printf #include "../../include/uuid.h" #include "../../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static uint32_t index_value = 0; static char *file_arg=NULL; static uint32_t fLeng; static unsigned char *policy_data = NULL; static char *password = NULL; static uint32_t passwd_length = 0; static int help_input = 0; static unsigned char empty_pol_data[] = {0}; static const char *short_option = "ehi:f:p:"; static const char *usage_string = "lcp_writepol -i index_value " "[-f policy_file] [-e] [-p passwd] [-h]"; static const char *option_strings[] = { "-i index value: uint32/string.\n" "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n" "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n" "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-f file_name: string. File name of the policy data is stored. \n", "-p password: string. \n", "-e write 0 length data to the index.\n" "\tIt will be used for some special index.\n" "\tFor example, the index with permission WRITEDEFINE.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'f': file_arg = optarg; break; case 'p': password = optarg; passwd_length = strnlen_s(password, 4096); break; case 'e': policy_data = empty_pol_data; fLeng = 0; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char *argv[]) { char *file = NULL; FILE *p_file = NULL; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse the parameters input to decide * what parameters will be passed to TSS API. */ ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto exit; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto exit; } if ( file_arg && (policy_data == NULL) ) file = file_arg; else if ( file_arg && (policy_data == empty_pol_data) ) { log_error("Cannot use '-f' and '-e' option at the same time!\n"); ret_value = LCP_E_INVALID_PARAMETER; goto exit; } if ( (file_arg == NULL) && (policy_data == NULL) ) { log_error("Must specify policy file name or use -e option! \n"); ret_value = LCP_E_INVALID_PARAMETER; goto exit; } if ( policy_data == NULL ) { p_file = fopen(file, "rb"); if ( !p_file ) { log_error("Open file %s error!\n", file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } /* * Get length of file. */ fseek(p_file, 0, SEEK_END); fLeng = ftell(p_file); fseek(p_file, 0, SEEK_SET); policy_data = (unsigned char *)malloc(fLeng); if ( !policy_data ) { log_error("Memory alloc error!\n"); ret_value = LCP_E_OUTOFMEMORY; goto exit; } /* * Read policy data from file. */ if ( fLeng != fread(policy_data, 1, fLeng, p_file) ) { log_error("Read policy data from file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } } ret_value = lcp_write_index(index_value, password, passwd_length, 0, fLeng, policy_data); exit: if ( ret_value != LCP_SUCCESS ) { log_error("\nCommand WritePol failed:\n"); print_error(ret_value); } else { log_info("\nSuccessfully write policy into index 0x%08x \n", index_value); } if ( (policy_data != NULL) && (policy_data != empty_pol_data) ) free(policy_data); if ( p_file != NULL ) fclose(p_file); return ret_value; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/deprecated/man/lcp_crtpconf.80000644000000000000000000000141214210363175016473 0ustar 00000000000000.\" .TH LCP_CRTPCONF 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpconf \- create a platform configuration measurement for v1 policies .SH SYNOPSIS .B lcp_crtpconf .B \-p .IR PCR-index1,PCR-index2,...,PCR-indexN .RB [\| \-f .IR file-name \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_crtpconf is used to create a platform configuration measurement. The produced platform configuration measurement will be appended to the input file in binary mode. .SH OPTIONS .TP .BI \-p\ PCR-index1,PCR-index2,...,PCR-indexN Index values can be 0-23. .TP .BI \-f\ file-name File name to which the measurement is appended. .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_crtpconf \-p \fI0,1,2,3 \fB \-f \fIpconf-file .SH "SEE ALSO" .BR lcp_writepol (8), .BR lcp_crtpol (8). tboot-1.10.5/deprecated/man/lcp_crtpol.80000644000000000000000000000454314210363175016170 0ustar 00000000000000.\" .TH LCP_CRTPOL 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpol \- create a TXT v1 Launch Control Policy .SH SYNOPSIS .B lcp_crtpol .B \-t .I policy-type .RB [\| \-a .IR hashalg \|] .RB [\| \-v .IR version \|] .RB [\| \-sr .IR SINIT-revocation-counter \|] .RB [\| \-s .IR srtm-file \|] .RB [\| \-m .IR mle-file \|] .RB [\| \-o .IR policy-file \|] .RB [\| \-b .IR policy-data-file \|] .RB [\| \-pcf .IR policy-control-field \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_crtpol is used to create a TXT v1 LCP policy (and optionally policy data), which can later be written to the TPM. The policy created are for platforms produced before 2009 (Weybridge, Montevina, McCreary). .SH OPTIONS .TP .BI \-t\ policy-type Policy type can be UINT8 or string. 5 strings are supported for the reserved LCP policy types. Strings and default policy type values for each string are: .RS .TP 0 or "hashonly" .TP 1 or "unsigned" .TP 2 or "signed" .TP 3 or "any" .TP 4 or "forceowner" .RE .TP .BI \-a\ hashalg Hash algorithm. Currently we only support SHA-1 algorithm: 0 OR 'sha1'. .TP .BI \-v\ version Version number. Currently it can be set to 0 or 1 if specified. The default value is 0. .TP .BI \-sr\ SINIT-revocation-counter The default sinit revocation counter is 0. .TP .BI \-s\ srtm-file File name of platform configuration data, as produced by .BR lcp_crtpconf. .TP .BI \-m\ mle-file File name of file containing the MLE hash values. This is a text file that contains one SHA-1 hash per line. The value of the hash must be hexadecimal values, specified either a single un-deliminated set or as space-delimited two-character (i.e. one byte) values. This can be produced by the .BR lcp_mlehash command. .TP .BI \-o\ policy-file File name to store the output policy. .TP .BI \-b\ policy-data-file File name to store the LCP Policy data. .TP .BI \-pcf\ policy-control-field The default policy control field value is 0. .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_crtpol \-t \fI0 \fB \-m \fImle-file \fB \-o \fIpolicy-hashonly-file .PP \fBlcp_crtpol \-t \fI1 \fB \-m \fImle-file \fB \-s \fIpconf-file \fB \-b \fI policy-data-file .PP \fBlcp_crtpol \-t \fIunsigned \fB \-a \fIsha1 \fB \-m \fImle-file \fB \-s \fIpconf-file \fB \-o \fIpolicy-unsigned-file \fB \-b \fIpolicy-data-file .SH "SEE ALSO" .BR lcp_readpol (8), .BR lcp_writepol (8), .BR lcp_mlehash (8), .BR lcp_crtpconf (8). tboot-1.10.5/deprecated/man/lcp_crtpol2.80000644000000000000000000000320114210363175016240 0ustar 00000000000000.\" .TH LCP_CRTPOL2 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpol2 \- create an Intel(R) TXT policy (and policy data file) .SH SYNOPSIS .B lcp_crtpol2 .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpol2 is used to create an Intel(R) TXT policy (and policy data file) for platforms produced after 2008. .SH OPTIONS .TP .B \-\-create Create an TXT policy. The following options are available: .RS .TP \w'\fR[\fB\-\-rev\ \fIctr1\fR[,\fIctrN\fR]'u+1n \fB\-\-type\ \fIany\||\|list\fR type .TP \fB\-\-pol\ \fIfile\fR policy file .TP \fR[\fB\-\-ver\ \fIversion\fR] version .TP \fR[\fB\-\-minver\ \fIver\fR] SINITMinVersion .TP \fR[\fB\-\-rev\ \fIctr1\fR,\fIctrN\fR] revocation values (comma separated, no spaces) .TP \fR[\fB\-\-ctrl\ \fIpol-ctrl\fR] policy control .TP \fR[\fB\-\-data\ \fIfile\fR] policy data file .TP \fR[\fIfile\fR]... policy list files .RE .TP .B \-\-show Show the content of policy file or policy data file. Available options are: .RS .TP \w'\fR[\fB\-\-rev\ \fIctr1\fR[,\fIcrtN\fR]'u+1n \fR[\fB\-\-brief\fR] brief format output .TP \fR[\fIpolicy-file\fR] policy file .TP \fR[\fIpolicy-data-file\fR] policy data file .RE .TP .B \-\-help Print out the help message. .TP .B \-\-verbose Enable verbose output; can be specified with any command. .SH EXAMPLES Assuming a policy list file .I list-unsig.lst has been created by the command .B lcp_crtpolist(8). The following example will create a policy and policy data file. .PP \fBlcp_crtpol2\ \-\-create\ \-\-type \fIlist \fB\-\-pol \fIlist.pol \fB\-\-data \fIlist.data\ list-unsig.lst .SH "SEE ALSO" .BR lcp_crtpol (8), .BR lcp_mlehash (8), .BR lcp_crtpolelt (8), .BR lcp_crtpollist (8). tboot-1.10.5/deprecated/man/lcp_crtpolelt.80000644000000000000000000000516414210363175016675 0ustar 00000000000000.\" .TH LCP_CRTPOLELT 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpolelt \- create an Intel(R) TXT policy element of specified type. .SH SYNOPSIS .B lcp_crtpolelt .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpolelt is used to create an Intel(R) TXT policy element of specified type. .SH OPTIONS .TP \fB\-\-create create an policy element .RS .TP \w'\fR[\fB\-\-ctrl\ \fIpol-elt-ctr1\fR]'u+1n \fB\-\-type\ \fItype\fP type of element; must be first option; see below for type strings and their options .TP \fB\-\-out\ \fIfile\fP output file name .TP \fR[\fB\-\-ctrl\ \fIpol-elt-ctr1\fR]\fP PolEltControl field (hex or decimal) .RE .TP \fB\-\-show\ \fIfile\fP show policy element .TP \fB\-\-verbose\fP enable verbose output; can be specified with any command .TP \fB\-\-help\fP print out the help message .SS "Available type options:" .TP \fBmle\ \fR[\fB\-\-minver\ \fIver\fR]\fP minimum version of SINIT .TP \fBmle\ \fR[\fIfile1\fR][\fIfile2\fR]...\fP one or more files containing MLE hash(es); each file can contain multiple hashes .TP \fBpconf\ \fR[\fIfile1\fR][\fIfile2\fR]...\fP one or more files containing PCR numbers and the desired digest of each; each file will be a PCONF .TP \fBcustom\ \fR[\fB\-\-uuid\ \fIUUID\fR]\fP UUID in format: {0xaabbccdd, 0xeeff, 0xgghh, 0xiijj, {0xkk 0xll, 0xmm, 0xnn, 0xoo, 0xpp}} or "--uuid tboot" to use default .TP \fBcustom\ \fR[\fIfile\fR]\fP file containing element data .SH EXAMPLES .SS "Create an MLE element: .TS tab (@); l lx. 1@T{ \fBlcp_mlehash \-c \fI"logging=serial,vga,memory" /boot/tboot.gz \fR> \fImle-hash T} 2@T{ \fBlcp_crtpolelt \fB\-\-create \-\-type \fImle \fB\-\-ctrl \fI0x00 \fB\-\-minver \fI17 \fB\-\-out \fImle.elt mle-hash T} .TE .SS "Create a PCONF element: .TS tab (@); l lx. 1@T{ \fBcat \fI/sys/devices/platform/tpm_tis/pcrs \fR| \fBgrep \-e \fIPCR-00 \fB\-e \fIPCR-01 \fR> \fIpcrs T} 2@T{ \fBlcp_crtpolelt \-\-create \-\-type \fIpconf \fB\-\-out \fIpconf.elt pcrs T} .TE .SS "Create an SBIOS element: .TS tab (@); l lx. 1@T{ Create hash file containing BIOS hash(es), e.g. named \fIsbios-hash T} 2@T{ \fBlcp_crtpolelt \-\-create \-\-type \fIsbios \fB\-\-out \fIsbios.elt sbios-hash T} .TE .SS "Create a CUSTOM element: .TS tab (@); l lx. 1@T{ Create or determine the UUID that will identify this data format (e.g. using \fBuuidgen\fR(1)). T} 2@T{ Create the data file that will be placed in this element (e.g. the policy file from \fBtb_polgen\fR(8)). T} 3@T{ \fBlcp_crtpolelt \-\-create \-\-type \fIcustom \fB\-\-out \fIcustom.elt \fB\-\-uuid \fIuuid-value data-file T} .TE .SH "SEE ALSO" .BR lcp_crtpol2 (8), .BR lcp_mlehash (8), .BR lcp_crtpollist (8), .BR uuidgen (1), .BR tb_polgen (8). tboot-1.10.5/deprecated/man/lcp_crtpollist.80000644000000000000000000000560614210363175017065 0ustar 00000000000000.\" .TH LCP_CRTPOLLIST 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpollist \- create an Intel(R) TXT policy list .SH SYNOPSIS .B lcp_crtpollist .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpollist is used to create an Intel(R) TXT policy list. .SH OPTIONS .TP .B \-\-create Create an TXT policy list. The following options are available: .RS .TP \w'\fR[\fB\-\-priv\ \fIkey-file\fR]'u+1n \fB\-\-out\ \fIfile\fP policy list file .TP \fR[\fB\-\-ver\ \fIversion\fR]\fP version .TP \fR[\fIfile\fR]...\fP policy element files .RE .TP .B \-\-sigh Sign an TXT policy list. .RS .TP \w'\fR[\fB\-\-priv\ \fIkey-file\fR]'u+1n \fB\-\-pub \fIkey-file\fP PEM file of public key .TP \fB\-\-out\ \fIfile\fP policy list file .TP \fR[\fB\-\-priv \fIkey-file\fR]\fP PEM file of private key .TP \fR[\fB\-\-rev \fIrev-ctr\fR]\fP revocation counter value .TP \fR[\fB\-\-nosig\fR]\fP don't add SigBlock .RE .TP .B \-\-addsig .RS .TP \w'\fR[\fB\-\-priv\ \fIkey-file\fR]'u+1n \fB\-\-sig\ \fIfile\fP file containing signature (big-endian) .TP \fB\-\-out\ \fIfile\fP policy list file .RE .TP \fB\-\-show \fIfile\fP policy list file .TP .B \-\-help Print out the help message. .TP .B \-\-verbose Enable verbose output; can be specified with any command. .SH EXAMPLES .SS "Create policy list:" Assuming there have been two element file .I mle.elt and .I pconf.elt generated by .BR lcp_crtpolelt (8) The following example can create an unsigned policy list: .PP \fBlcp_crtpollist \-\-create \-\-out \fIlist-unsig.lst mle.elt pconf.elt .SS "Sign policy list:" Unsigned policy list can be signed by the command .BR lcp_crtpollist (8) or .BR openssl (1). The .BR openssl (1) signing is supported for cases where the signing environment is separate from the policy creation environment and the software allowed to run there is strictly controlled and already supports .BR openssl (1). .PP The following example uses .BR openssl (1) to sign the list: .TS tab (@); l lx. 1@T{ \fBopenssl rsa \-pubout \-in \fIprivkey.pem \fB\-out \fIpubkey.pem T} 2@T{ \fBcp \fIlist-unsig.lst list-sig.lst T} 3@T{ \fBlcp_crtpollist \-\-sigh \-\-pub \fIpubkey.pem \fB\-\-nosig \-\-out \fIlist-sig.lst T} 4@T{ \fBopenssl genrsa \-out \fIprivkey.pem 2048 T} 5@T{ \fBopenssl dgst \-sha1 \-sign \fIprivkey.pem \fB\-out \fIlist.sig list-sig.lst T} 6@T{ \fBlcp_crtpollist \-\-addsig \-\-sig \fIlist.sig \fB\-\-out \fIlist-sig.lst T} .TE .B lcp_crtpollist can also be used to sigh a policy list. The following example are intended to be mutually exclusive with the preceding example. .TS tab (@); l lx. 1@T{ \fBopenssl genrsa \-out \fIprivkey.pem 2048 T} 2@T{ \fBopenssl rsa \-pubout \-in \fIprivkey.pem \fB\-out \fIpubkey.pem T} 3@T{ \fBcp \fIlist-unsig.lst list-sig.lst T} 4@T{ \fBlcp_crtpollist \-\-sign \-\-pub \fIpubkey.pem \fB\-\-priv \fIprivkey.pem \fB\-\-out \fIlist-sig.lst T} .TE .SH "SEE ALSO" .BR lcp_crtpol2 (8), .BR lcp_crtpolelt (8), .BR lcp_crtpollist (8), .BR openssl(1). tboot-1.10.5/deprecated/man/lcp_mlehash.80000644000000000000000000000242214210363175016300 0ustar 00000000000000.\" .TH LCP_MLEHASH 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_mlehash \- generate a SHA-1 hash of a TXT MLE binary file suitable for use in a TXT launch control policy .SH SYNOPSIS .B lcp_mlehash .RB [\| \-v \|] .RB [\| \-c .IR cmdline \|] .RB [\| \-h \|] .I mle-file .SH DESCRIPTION .B lcp_mlehash is used to generate a SHA-1 hash of the portion of an executable file that contains the Intel® TXT measured launched environment (MLE). In the MLE binary file, the portion of the file to be used as the MLE is specified in the MLE header structure. If verbose mode is not used, the output is suitable for use as the mle-file to the .B lcp_crtpol and .B lcp_crtpolelt commands. .SH OPTIONS .TP .I mle-file File name of the MLE binary. If it is a gzip file then it will be un-ziped before hashing. .TP .B \-v Verbose mode, display progress indications. .TP .BI \-c\ cmdline Specify quote-delimited command line. It is important to specify the command line that is used when launching the MLE or the hash will not match what is calculated by SINIT. .TP .B \-h Print out the help message. .SH EXAMPLES \fBlcp_mlehash \-c \fI"logging=memory,serial,vga" \fI/boot/tboot.gz \fB> \fImle-hash .SH "SEE ALSO" .BR lcp_readpol (8), .BR lcp_writepol (8), .BR lcp_crtpol (8), .BR lcp_crtpolelt (8). tboot-1.10.5/deprecated/man/lcp_readpol.80000644000000000000000000000250714210363175016311 0ustar 00000000000000.\" .TH LCP_READPOL 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_readpol \- read the contents of an LCP policy index .SH SYNOPSIS .B lcp_readpol .B \-i .I index-value .RB [\| \-f .IR policy-file \|] .RB [\|\-s .IR size \|] .RB [\|\-p .IR passwd \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_readpol is used to read the contents of an LCP policy index. Any index can be specified but the output will be parsed as if it contained a policy. .SH OPTIONS .TP .BI \-i\ index-value Designate the index for reading. Index can be UINT32 or string. 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: .RS .IP default 0x50000001(INDEX_LCP_DEF) .IP owner 0x40000001(INDEX_LCP_OWN) .IP aux 0x50000002(INDEX_LCP_AUX) .RE .TP .BI \-f\ policy-file File name to write the policy data to. If no file name is specified then the contents will be displayed. .TP .BI \-s\ size Value size to read from NV store. If no size inputted, read by length as this index defined. .TP .BI \-p\ password The TPM owner password .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_readpol \-i \fIdefault \fB \-f \fIpolicy-file .PP \fBlcp_readpol \-i \fI0x00011101 \fB \-s \fI10 .PP \fBlcp_readpol \-i \fI0x00011101 \fB \-f \fIpolicy-file \fB \-p \fI123456 .SH "SEE ALSO" .BR lcp_writepol (8), .BR lcp_crtpol (8). tboot-1.10.5/deprecated/man/lcp_writepol.80000644000000000000000000000237514210363175016533 0ustar 00000000000000.\" .TH LCP_WRITEPOL 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_writepol \- write LCP policy into a TPM NV index .SH SYNOPSIS .B lcp_writepol .B \-i .I index-value .RB [\| \-f .IR policy-file .RB |\ \-e \|] .RB [\| \-p .IR passwd \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_writepol is used to write LCP policy into a (previously-defined) TPM NV index. It also supports writing arbitrary data into a specified index. .SH OPTIONS .TP .BI \-i\ index-value Designate the index for writing. Index can be UINT32 or string. 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: .RS .IP default 0x50000001(INDEX_LCP_DEF) .IP owner 0x40000001(INDEX_LCP_OWN) .IP aux 0x50000002(INDEX_LCP_AUX) .RE .TP .BI \-f\ policy-file File name where the policy data is stored. .TP .BI \-e Write 0 length data to the index. This is useful for special indices, such as those permission is WRITEDFINE. .TP .BI \-p\ password The TPM owner password .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_writepol \-i \fIdefault \fB \-f \fIpolicy-file .PP \fBlcp_writepol \-i \fI0x00011101 \fB \-e .PP \fBlcp_writepol \-i \fI0x00011101 \fB \-f \fIpolicy-file \fB \-p \fI123456 .SH "SEE ALSO" .BR lcp_readpol (8), .BR lcp_crtpol (8). tboot-1.10.5/deprecated/man/tpmnv_defindex.80000644000000000000000000000303414210363175017033 0ustar 00000000000000.\" .TH TPMNV_DEFINDEX 8 "2020-05-10" "tboot" "User Manuals" .SH NAME tpmnv_defindex \- define an index in TPM NV storage .SH SYNOPSIS .B tpmnv_defindex .RB \| -i \| .IR index \| .RB [\| -s .IR size \|] .RB [\| -pv .IR permission_value \|] .RB [\| -p .IR password \|] .RB [\| -av .IR authentication_value \|] .RB [\| -wl .IR write_locality \|] .RB [\| -rl .IR read_locality \|] .RB [\| -h \|] .SH DESCRIPTION .B tpmnv_defindex is used to define an index in TPM NV storage. You can use this to store data in the TPM so that it can be only accessed when certain conditions are met. .SH OPTIONS .TP .BI -i\ index NV index to use. You can specify an integer or use the following symbolic names: default (0x50000001), owner (0x40000001) or aux (0x50000002). .TP .BI -s\ size Size of the NV storage in bytes. .TP .BI -pv\ permission_value Permission value to use for the storage. This is mandatory unless you specify an index that has a default value: default (0x00002000), owner (0x00000002) or aux (0x00000000). .TP .BI -p\ password Owner password for the index. .TP .BI -av\ authentication_value Authentication value for the index. Used as a password with AUTHREAD/AUTHWRITE. .TP .BI -wl\ write_locality Write locality value. There are 5 localities: 0-4. For example the locality value is 0x18 if you want to allow localities 3 or 4. .TP .BI -rl\ read_locality Read locality value. There are 5 localities: 0-4. For example the locality value is 0x18 if you want to allow localities 3 or 4. .TP .BI -h\ Print the help text. .SH "SEE ALSO" .BR tpm_nvdefine (8) tboot-1.10.5/deprecated/man/tpmnv_getcap.80000644000000000000000000000130214210363175016504 0ustar 00000000000000.\" .TH TPMNV_GETCAP 8 "2020-05-10" "tboot" "User Manuals" .SH NAME tpmnv_getcap \- show status of an index in TPM NV storage .SH SYNOPSIS .B tpmnv_getcap .RB \| -i \| .IR index \| .RB [\| -p .IR password \|] .RB [\| -h \|] .SH DESCRIPTION .B tpmnv_relindex can be used to release an index defined in TPM NV storage. .SH OPTIONS .TP .BI -i\ index NV index to use. You can specify an integer or use the following symbolic names: default (0x50000001), owner (0x40000001) or aux (0x50000002). .TP .BI -p\ password Owner password for the index. If you specify a password then permanent flags are shown, otherwise only public data is shown. .TP .BI -h\ Print the help text. .SH "SEE ALSO" .BR tpm_nvinfo (8) tboot-1.10.5/deprecated/man/tpmnv_lock.80000644000000000000000000000053514210363175016200 0ustar 00000000000000.\" .TH TPMNV_LOCK 8 "2020-05-10" "tboot" "User Manuals" .SH NAME tpmnv_lock \- lock TPM NV storage .SH SYNOPSIS .B tpmnv_lock .RB [\| -f \|] .RB [\| -h \|] .SH DESCRIPTION .B tpmnv_lock can be used to lock TPM NV storage. .SH OPTIONS .TP .BI -f\ Lock without prompting the user. .TP .BI -h\ Print the help text. .SH "SEE ALSO" .BR tpm_nvinfo (8) tboot-1.10.5/deprecated/man/tpmnv_relindex.80000644000000000000000000000114514210363175017060 0ustar 00000000000000.\" .TH TPMNV_RELINDEX 8 "2020-05-10" "tboot" "User Manuals" .SH NAME tpmnv_relindex \- release an index in TPM NV storage .SH SYNOPSIS .B tpmnv_relindex .RB \| -i \| .IR index \| .RB [\| -p .IR password \|] .RB [\| -h \|] .SH DESCRIPTION .B tpmnv_relindex can be used to release an index defined in TPM NV storage. .SH OPTIONS .TP .BI -i\ index NV index to use. You can specify an integer or use the following symbolic names: default (0x50000001), owner (0x40000001) or aux (0x50000002). .TP .BI -p\ password Owner password for the index. .TP .BI -h\ Print the help text. .SH "SEE ALSO" .BR tpm_nvrelease (8) tboot-1.10.5/docs/Makefile0000644000000000000000000000117214210363175013446 0ustar 00000000000000# Copyright (c) 2012, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # docs makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TBOOT_MANPATH ?= $(DISTDIR)/usr/share/man # # universal rules # build : dist : install install : [ -d $(TBOOT_MANPATH)/man8 ] || $(INSTALL_DIR) $(TBOOT_MANPATH)/man8 $(INSTALL_DATA) -t $(TBOOT_MANPATH)/man8 \ man/txt-acminfo.8 man/tb_polgen.8 man/txt-stat.8 man/lcp2_crtpol.8 \ man/lcp2_crtpolelt.8 man/lcp2_crtpollist.8 man/lcp2_mlehash.8 \ man/txt-parse_err.8 clean : mrproper : clean distclean : clean # # dependencies # # # implicit rules # tboot-1.10.5/docs/howto_use.md0000644000000000000000000003551314210363175014352 0ustar 00000000000000Using TBOOT =========== Instructions for Use: -------------------- - For Grub, the new tboot module must be added as the 'kernel' in the grub.conf file. For Grub2, the new tboot module must be added as the 'multiboot' in the grub.conf file. The existing 'kernel' entry should follow as a 'module'. The SINIT AC module must be added to the grub.conf boot config as the last module, e.g.: title Xen w/ Intel(R) Trusted Execution Technology root (hd0,1) kernel /tboot.gz logging=serial,vga,memory module /xen.gz iommu=required dom0_mem=524288 com1=115200,8n1 module /vmlinuz-2.6.18-xen root=/dev/VolGroup00/LogVol00 ro module /initrd-2.6.18-xen.img module /Q35_SINIT_17.BIN - The appropriate SINIT AC Modules can be downloaded from this webiste: https://software.intel.com/en-us/articles/intel-trusted-execution-technology/ The current version of tboot (both in the repository and .tar.gz) requires version 17 or greater of the SINIT AC module. It will not work with some previous SINIT ACMs nor will it work on the TEP. - For Xen: newer versions of Xen support the `iommu=required` command line option, which causes Xen to fail to run if there is any error in programming the VT-d engines. This is the most secure configuration. Older versions of Xen used the param `vtd=1` or `iommu=1`, which enables VT-d but does not fail if it cannot be enabled. - For Linux: the `intel_iommu=on` command line option will enable VT-d and the TXT code in Linux will force this if it is not specified. Support is now part of the 2.6.32 kernel. - Progress of the launch process is indicated via debug printk's using three different logging methods: - `serial` - logging is traced over a COM/serial port to a remote console - `vga` - logging is traced to the local screen - `memory` - logging is traced to a memory location These three methods are not mutually exclusive - any combination can be enabled. Logging is enabled with command line parameters to tboot. The first parameter enables or disables logging levels (note that the default is all); any combination of "err", "warn", "info", "detail" can be used: loglvl=err,warn,info,detail|all|none To achieve a faster S3 resume, suggest to use `loglvl=err` or `loglvl=none`. The next parameter is used to configure the various logging targets; any combination can be used (note that when the parameter is not set, serial is the default): logging=vga,serial,memory If vga logging is set, the vga_delay parameter can be used to specify the number of seconds to pause after every screenful of output. It is specified as: vga_delay= If serial logging is set, the serial port settings can be configured with the following parameters: serial=[/][,[,[,[, [,]]]]] The default values for these are: `serial=115200,8n1,0x3f8`. - tboot will attempt to seal the module measurements using the TPM so that if it is put into S3 it can restore the correct PCR values on resume. In order for this to work, the TPM must be owned and the SRK auth must be set to all 0s. This can be done using the `-z` flag to tpm_takeownership. If the tboot policy being used is 'nonfatal' and the seal operation fails, tboot will continue the boot. However, for 'continue' or 'halt' policy types, tboot will halt the boot. - tboot provides a better AP wakeup mechanism based on cpu MWAIT feature for OS/VMM. This mechanism is defaultly disabled, and could be enabled with tboot command line option: ap_wake_mwait=true|false Once this mechanism is enabled, system will boot faster and will NOT require VT to be enabled. But before enabling this option, please make sure the OS/VMM has already support it, otherwise system can never boot up. Confirm it via finding lines like below in the OS/VMM booting log: TBOOT: found shared page at .... ... flags: 0x0000000x - tboot support a new PCR usage called Details / Authorities PCR Mapping(DA). DA can be enabled by below tboot command line option (note: default is legacy): pcr_map=da|legacy With DA PCR Mapping enabled it separates detailed measurements, stored in PCR17, from authorities measurements stored in PCR18. "Details" measurements include hashes of all components participating in establishing of trusted execution environment and due to very nature of hash algorithm change of any component entail change of final PCR17 value. "Authorities" measurements include hashes of some unique identifying properties of signing authorities such as public signature verification keys. This enables authority issue an update of component without affecting of final PCR18 value, because updated component is signed in the same way as old one. - Previously tboot tried to avoid including any reserved e820 region (in 1M ~4GB) into PMR low region to avoid possible SMM hang. So all e820 RAM regions after the first reserved one(above 1MB) will be discarded. It was found that some platforms reserve low memory regions to mitigate some hardware issues. Including such kind of reserved e820 regions into PMR low region does not cause SMM hang. Below tboot command line option can be used to mitigate the cases that large amount of RAM(sometime > 3GB) marked as reserved(discarded from OS/VMM usable RAM size) by tboot because some reserved e820 regions occurred in very low memory(notes: default is 0, means no mitigation for unwanted memory losing): min_ram=0xXXXXXXXX During 1MB~4GB, only the first RAM region with size less than byte and all following RAM regions will be discarded. The min_ram option gives a way to do fine-grain tuning on specific platforms. A suggested practical value for min_ram is 32M(0x2000000). - Tboot provides support to launch Revocation ACM (RACM) to revoke old buggy SINIT version if following command line option is used (default value is false): call_racm=true|false|check RACM is also loaded into memory via bootload like grub or syslinux, and is launched with getsec[ENTERACCS] instruction. Below is a example GRUB entry for RACM launch: title RACM Launch root (hd0,1) kernel /tboot.gz logging=serial,vga,memory call_racm=true module /racm.bin Tboot will always warm reset platform after RACM was launched & executed. Whether RACM launch has succeeded or not could be checked via doing a tboot launch with "call_racm=check" right after the warm reset. This tboot launch will end with halt right after the RACM launch result was output, and the system need manually reset. - Tboot support EFI boot via grub2 multiboot2 protocol. In Fedora 18/19, the OS should be installed and booted in EFI mode first, then: - Under tboot code root folder: `make; make install` - Copy appropriate SINIT for platform into /boot. - Run: `grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg` - Create directory /boot/efi/EFI/fedora/x86_64-efi, and copy multiboot2.mod and relocator.mod from /usr/lib/grub/x86_64-efi into it. - Reboot to choose tboot grub option for TXT launch. In Centos 7, the OS should be installed and booted in EFI mode first, then: - Under tboot code root folder: make; make install - Copy appropriate SINIT for platform into /boot. - Run: `grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg` - Create directory /boot/efi/EFI/centos/x86_64-efi, and copy multiboot2.mod and relocator.mod from /usr/lib/grub/x86_64-efi into it. - If there aren't multiboot2.mod and relocator.mod in directory /usr/lib/grub/x86_64-efi, run: `yum install grub2-efi-modules` - Reboot to choose tboot grub option for TXT launch. Linux launch works already. Xen for trad BIOS still work and Xen EFI is not going to work until we can get a version with Daniel Kiper's multiboot2 changes in it -- and then we'll need to make some trivial changes to the 20_xen_tboot file. Grub2 is required for all of this. - Tboot support TPM NV measuring via extended Verified Launch Tboot Policy. This works only for TPM1.2 by far. TPM NV measuring is default disabled, need below cmdline option to enable: measure_nv=true When NV measuring is enabled, it will get all NV measuring policy entry from the tboot policy structure. Every NV policy entry will specify: nv_index: TPM NV index to measure and verify pcr: PCR to be extended with the NV measurement mod_num: Tell how to measure the nv = TB_POL_MOD_NUM_NV: hash then extend, no size limitation on NV index = TB_POL_MOD_NUM_NV_RAW: extend w/o hash, size should equal hash size hash_type: = any: no verification needed = image: need verify per hashs list. hashs: hash list. optional. There is one default NV policy entry, which will try to read NV 0x40000010 and extend it into pcr 22 without hashing. The nv_index to be measured must be defined with OWNERWRITE permission, otherwise the verification will fail, and nothing will be extended into pcr. - Tboot provides support to TPM2 module, and following command line option is used to select TPM2 extend policy. extpol=agile|embedded|sha1|sha256|sm3|... When "agile" policy is selected, ACM will use specific TPM2 commands to compute hashes and extend all existing PCR banks at the expense of possible performance loss. For "embedded" policy, ACM will use algorithms supported by tboot to compute hashes and then will use TPM2_PCR_Extend commands to extend them into PCRs. If PCRs utilizing hash algorithms not supported by SW are discovered, they will be capped with "1" value. This policy when selected will ensure maximum possible performance at the expense of possible capping of some of the PCRs. Other policy, like "sha1", "sha256", etc., only represent one single algorithm. It means tboot will use this algorithm to compute hash and use TPM2_PCR_Extend to extend it into PCRs. - Recovering from measured launch failures. When there's an error during SENTER, the system usually reboots. Since the underlying cause is some sort of configuration error, the system can end up in a loop rebooting endlessly after each attempted measured launch. In some environments it make more sense to fall back to booting the kernel directly so that the system comes up and is remotely accessible. After that the issue can be diagnosed and the system power-cycled to clear the error. To enable this behavior, a command line option can be used: ignore_prev_err=false|true // defaults to true The option defaults to true, which preserves the original behavior i.e. try a measured launch even if the previous measured launch had errors. Setting the value to false will check if the previous measured launch was successful by inspecting the TXT.ERRORCODE value. If measured launch failed, tboot will launch the kernel directly without trying to perform a measured launch. Note: TXT.ERRORCODE is only cleared if the system is power cycled. A reboot is not sufficient to clear the error code. - Force TPM2 legacy log format. Some SINITs have a bug where they don't extend the MLE hash to the event log. This makes it impossible to verify the measurement chain for PCR 17. However, if we force them to use the legacy (not TCG standardized) TPM2 log format, the SINITs in question log all the inputs to PCR 17 to the event log. This setting provides a way to force use of the legacy log format for TPM 2 systems: force_tpm2_legacy_log=false|true // defaults to false - Opt-in the vtd dmar table save/restore process With recent kernel (4.16.3 in fedora28), the acpi table seems changed by kernel. So function restore_vtd_dmar_table() will not work as expected to find the vtd dmar table and restore it in S3 resume, instead, the system will run into a hang or a reset. To solve the S3 issue but still keep vtd dmar table save/restore process for specific case, add below option: save_vtd=false|true // defaults to false PCR Usage --------- - Legacy PCR mapping - PCR 17 : It will be extended with the following values (in this order): - The values as documented in the MLE Developers Manual - SHA-1 hash of: tboot policy control value (4 bytes) | SHA-1 hash of tboot policy (20 bytes) : where the hash of the tboot policy will be 0s if TB_POLCTL_EXTEND_PCR17 is clear - PCR 18 : It will be extended with the following values (in this order): - SHA-1 hash of tboot (as calculated by lcp_mlehash) - SHA-1 hash of first module in grub.conf (e.g. Xen or Linux kernel) - PCR * : tboot policy may specify modules' measurements to be extended into PCRs specified in the policy - The default tboot policy will extend, in order, the SHA-1 hashes of all modules (other than 0) into PCR 19. - Details / Authorities PCR Mapping(DA) - PCR 17 (Details) - It will be extended with the following values (in this order): - The values as documented in the MLE Developers Manual - SHA-1 hash of: tboot policy control value (4 bytes) | SHA-1 hash of tboot policy (20 bytes) ; where the hash of the tboot policy will be 0s if TB_POLCTL_EXTEND_PCR17 is clear - SHA-1 hash of first module in grub.conf (e.g. Xen or Linux kernel) - PCR 18 (Authorities) - It will be extended with the following values (in this order): - The values as documented in the MLE Developers Manual - SHA-1 hash of: tboot policy control value (4 bytes) | SHA-1 hash of tboot policy (20 bytes) ; where the hash of the tboot policy will be 0s if TB_POLCTL_EXTEND_PCR17 is clear - PCR * - tboot policy may specify modules' measurements to be extended into PCRs specified in the policy - The default tboot policy will extend, in order, the SHA-1 hashes of all modules (other than 0) into PCR 17. PE signature support -------------------- TBOOT, starting from version 2.0.0, allows to sign its binary in the same way as defined in UEFI Secure Boot specs. There is a special output file - tboot.mb2 that is a TBOOT binary with PE header. This file can be loaded by GRUB2 using multiboot2 protocol in the same way as tboot.gz file. It is not possible to run it directly from UEFI. GRUB2, from version 2.05, does not allow to run unsigned binaries via multiboot protocol if it was loaded by SHIM. That's why the only way to use TBOOT when UEFI Secure Boot is enabled is to use signed tboot.mb2 file. To create the signature standard signing tools can be used: sbsign --key my.key --cert my.crt tboot.mb2tboot-1.10.5/docs/man/lcp2_crtpol.80000644000000000000000000000661114210363175015100 0ustar 00000000000000.\" .TH LCP2_CRTPOL 8 "2020-05-10" "tboot" "User Manuals" .SH NAME lcp2_crtpol \- create an Intel TXT Launch Control Policy .SH SYNOPSIS .B lcp2_crtpol .B <--create|--show|--help> .RB [ --brief ] .RB [ --verbose ] .B --alg .I alg .B --type .I .RI [ LIST FILES ] .RB [ --minver .IR ] .RB [ --rev .IR [ ,counterN ]] .RB [ --ctrl .IR ] .B --pol .I .RB [ --data .IR ] .RB [ --mask .IR mask ] .RB [ --auxalg .IR alg ] .B --sign .I alg .RB [ --polver .IR version ] .SH DESCRIPTION .B lcp2_crtpol is used to create a TXT LCP policy (and optionally policy data), which can later be written to the TPM. This tool allows creating policies for TPM 1.2 and TPM 2.0. Policy format is specified by the --polver option. .SH COMMANDS .TP .B --create Create a policy. .TP .B --show Show contents of a policy file, policy data file or both. If you specify one file it must be either a policy file or a policy data file. If you specify two files, one must be a policy file and the other a policy data file. .TP .B --help Show help text. .TP .B --version Show tool version. .SH OPTIONS .TP .B --brief Use brief format for output. .TP .B --verbose Use verbose format for output. .TP .BI --alg\ alg Specify algorithm for the LCP. Supported values are sha1, sha256 or sm3. .TP .BI --type\ Specify type of the policy. If --type is list, specify a comma-separated list of up to 8 policy list files (created with the lcp2_crtpollist command). .TP .BI --minver\ version Specify minimum allowed SINIT module version number (SINITMinVersion). .TP .BI --max_sinit_min\ version Specify maximum allowed value of the minimal SINIT module version number (MaxSinitMinVersion). .TP .BI --rev\ [,counterN] Specify a comma-separated list of revocation counters. .TP .BI --ctrl\ Specify PolicyControl value. The default is 0 (LCP_DEFAULT_POLICY_CONTROL). .TP .BI --pol\ Specify output file for the policy. .TP .BI --data\ Specify output file for the policy data. .TP .BI --mask\ mask Specify the policy hash algorithm mask. Supported values are sha1, sha256, sha384, sha512 or sm3. This option can be used multiple times to specify several allowed algorithms. Policy versions 2.0-2.4 only support SHA1. .TP .BI --auxalg\ alg Specify the AUX hash algorithm. Supported values are sha1, sha256, sha384, sha512 or sm3. You can also specify a raw value in hex (the value must start with "0x"). This option is only valid for policy versions 3.0 or 3.1. .TP .BI --sign\ alg Specify the allowed LCP signature algorithm mask. Supported values are: rsa-2048-sha1, rsa-2048-sha256, rsa-3072-sha256, rsa-3072-sha384, ecdsa-p256, ecdsa-p384 sm3. This option can be used multiple times to specify several allowed algorithms. .TP .BI --polver\ version Specify LCP policy version. Supported values are 2.0-2.4 (for TPM 1.2) and 3.0-3.2 (for TPM 2.0). If not specified, this option defaults to 3.0. .SH EXAMPLES .EX lcp2_crtpol --create --type list --pol list.pol --alg sha256 --data list.data --sign 0x8 list.lst .EE .SH "SEE ALSO" .BR "Full documentation of MLE, Intel(R) TXT and LCP is available in Intel(R) TXT Measured Launch Environment Deleveloper's Guide, available at: http://www.intel.com/content/www/us/en/software-developers/intel-txt-software-development-guide.html .BR lcp2_crtpollist (8), .BR lcp2_crtpolelt (8), .BR lcp2_mlehash (8), tboot-1.10.5/docs/man/lcp2_crtpolelt.80000644000000000000000000001100214210363175015573 0ustar 00000000000000.\" .TH LCP2_CRTPOLELT 8 "2020-05-10" "tboot" "User Manuals" .SH NAME lcp2_crtpolelt \- create an Intel(R) TXT policy element of specified type. .SH SYNOPSIS .B lcp2_crtpolelt .I COMMAND .RI "[ ELEMENT TYPE OPTIONS ]" .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpolelt is used to create an Intel(R) TXT policy element of specified type. Supports LCP elements both in current and legacy formats: LCP_MLE_ELEMENT2, LCP_STM_ELEMENT2, LCP_PCONF_ELEMENT2, LCP_PCONF_ELEMENT, LCP_MLE_ELEMENT and LCP_CUSTOM_ELEMENT. .SH COMMANDS .TP \fB--create \fB--type \fItype \fB--out \fIFILE \fR[\fB--ctrl \fIpol_elt_ctr1\fR]\fP create a policy element specified by the --type option. .RS .TP \fB--type \fItype\fP type of element. Must be first option. See below for type strings and their options .TP \fB--out \fIFILE\fP output file name .TP \fR[\fB--ctrl \fIvalue\fR]\fP PolEltControl field (hex or decimal) .RE .TP \fB--show \fIfile\fR [\fIFILE\fP] show a policy element .TP \fB--version\fP show tool version .TP \fB--verbose\fP enable verbose output; can be specified with any command .TP \fB--help\fP print out the help message .SH OPTIONS The \fB--create\fR command requires additional parameters depending on the element's type .TP \fBmle2 \fR[\fB--minver \fIver\fR] \fR[\fB--alg \fIalgorithm\fR] \fIfile\fR [\fIfile\fR...]\fP .RS .TP \w'\fB--alg\ \fI\fP'u+1n \fB--minver \fIver\fP minimum version of SINIT (hex or decimal) .TP \fB--alg \fI\fP hash algorithm .TP \fR\fIfile\fR [\fIfile\fR...]\fP one or more text files, each containing one or more MLE hashes (as text, one hash per line); Hash files can be created with lcp2_mlehash. .RE .TP \fBcustom \fR\fB--uuid \fIUUID \fR\fIfile\fR\fP .RS .TP \w'\fB--uuid\ \fIUUID\fP'u+1n \fB--uuid \fIUUID\fP UUID in format: {0xaabbccdd, 0xeeff, 0xgghh, 0xiijj, {0xkk 0xll, 0xmm, 0xnn, 0xoo, 0xpp}} or "--uuid tboot" to use default .TP \fIfile\fP file containing element data .RE .TP \fBsbios \fR[\fB--alg \fIalgorithm\fR] \fIfile\fR [\fIfile\fR...]\fP .RS .TP \w'\fB--alg\ \fI\fP'u+1n \fB--alg \fI\fP hash algorithm .TP \fR\fIfile\fR [\fIfile\fR...]\fP one or more files containing one or more BIOS hashes (as text, one hash per line); the first hash in the first file will be the fallback hash .RE .TP \fBstm \fR[\fB--alg \fIalgorithm\fR] \fIfile\fR [\fIfile\fR...]\fP .RS .TP \w'\fB--alg\ \fI\fP'u+1n \fB--alg \fI \fP hash algorithm .TP \fIfile\fR [\fIfile\fR...]\fP one or more text files, each containing one or more STM hashes (as text, one hash per line); .RE .TP \fBpconf2 \fB--alg \fIalgorithm\fR [\fB--pcrN \fIhash_value\fR]\fP .RS .TP \w'\fB--alg\ \fI\fP'u+1n \fB--alg \fI\fR \fP PCR hash algorithm .TP \fB--pcrN \fIhash_value\fP PCR value for PCR #N, where 0 <= N <= 7. .RE .TP \fBmle \fR[\fB--minver \fIver\fR] \fIfile\fR [\fIfile\fR...]\fP .RS \fB--minver \fIver\fP minimum version of SINIT (hex or decimal) .TP \fR\fIfile\fR [\fIfile\fR...]\fP one or more text files, each containing one or more MLE SHA1 hashes (as text, one hash per line); Hash files can be created with lcp2_mlehash. .RE .TP \fBpconf \fIfile\fR [\fIfile\fR...]\fP .RS one or more text files, each containing PCR information; Each file should have the following structure: first line should be: 'locality:' followed by up to 8 lines, each representing one PCR (0 to 7) and its contents: e.g. Locality represents TPM's locality at release. It is a byte, of which bits 0 to 4 represent their respective locality (bit0 - locality0 and so on). Bits 5-7 are reserved and must be 0. Value must be at least 1 - locality0 selected, and at most 0x1F (all localities selected). .RE .SH EXAMPLES .P Create MLE element: .EX lcp2_crtpolelt --create --type mle --out mle.elt --ctrl 0x00 --alg sha256 --minver 0 mle_hash .EE .P Create PCONF2 element: .EX lcp2_crtpolelt --create --type pconf2 --out pconf2.elt --ctrl 0x00 --alg sha256 --pcr0 --pcr3 .EE .P Create PCONF element: .EX lcp2_crtpolelt --create --type pconf pcrInfo1.txt pcrInfo2.txt --out pconf2.elt --ctrl 0x00 .EE .SH "SEE ALSO" .BR "Full documentation of MLE, Intel(R) TXT and LCP is available in Intel(R) TXT Measured Launch Environment Deleveloper's Guide, available at: http://www.intel.com/content/www/us/en/software-developers/intel-txt-software-development-guide.html .BR lcp2_crtpol (8), .BR lcp2_mlehash (8), .BR lcp2_crtpollist (8), .BR uuidgen (1), .BR tb_polgen (8). tboot-1.10.5/docs/man/lcp2_crtpollist.80000644000000000000000000000533414210363175015775 0ustar 00000000000000.\" .TH LCP2_CRTPOLLIST 8 "2020-05-10" "tboot" "User Manuals" .SH NAME lcp2_crtpollist \- create an Intel(R) TXT policy list .SH SYNOPSIS .B lcp2_crtpollist .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp2_crtpollist is used to create an Intel(R) TXT policy list. .SH OPTIONS .TP .B --create Create a TXT policy list. The following options are available: .RS .TP \w'\fB--listver\ \fIver\fP'u+1n \fB--listver\ \fIver\fP policy list version. Supported values are: 0x100 (legacy LCP_POLICY_LIST), 0x200, 0x201 (legacy LCP_POLICY_LIST2) and 0x300 (current LCP_POLICY_LIST2_1). .TP \w'\fB--out\ \fIfile\fP'u+1n \fB--out\ \fIfile\fP output file for policy list .TP \fR[\fIfile\fR]...\fP policy element files (created with the lcp2_crpolelt command). .RE .TP .B --sign Sign a TXT policy list. .RS .TP \w'\fB--sigalg\ \fI\fP'u+1n \fB--sigalg\ \fI\fP Signature algorithm. Lists version 0x100 only support rsa (rsa pkcs 1.5). Lists version 0x200 and 0x201 support rsa (rsa pkcs 1.5) and ecdsa. Lists version 0x300 support rsapss and ecdsa. .TP \w'\fB--hashalg\ \fI\fP'u+1n \fB--hashalg\ \fI\fP Hash algorightm used for signing a list. Lists version 0x100 only support SHA1. .TP \fB--pub\ \fIfile\fP Public key to use, must be in PEM format. .TP \fB[--priv\ \fIfile\fP] Private key to use, must be in PEM format. This option is required unless you use the \fB--nosig\fP option .TP \fR[\fB--rev \fIcounter\fR]\fP Revocation counter value .TP \fR[\fB--nosig\fR]\fP Don't add a SigBlock. This option is ignored if list is version 0x300. .TP \fB--out\ \fIfile\fP Policy list file (input and output) .RE .TP .B --addsig Add a signature. This option is ignored if list is version 0x300. .RS .TP \w'\fB--sig\ \fIfile\fP'u+1n \fB--sig\ \fIfile\fP File containing signature (big-endian) .TP \fB--out\ \fIfile\fP Policy list file .RE .TP \fB--show \fIfile\fP Show contents of a policy file .TP \fB--verify \fIfile\fP Verify policy version 0x300 file. .TP \fB--version\fP Show tool version. .TP .B --help Print out the tool's help message. .TP .B --verbose Enable verbose output; can be specified with any command. .SH EXAMPLES .P Create unsigned policy list with MLE element: .EX lcp2_crtpollist --create --out list.lst mle.elt .EE .P Sign policy: .EX lcp2_crtpollist --sign --sigalg rsa --pub pubkey.pem --priv privkey.pem --out list.lst .EE .SH "SEE ALSO" .BR "Full documentation of MLE, Intel(R) TXT and LCP is available in Intel(R) TXT Measured Launch Environment Deleveloper's Guide, available at: http://www.intel.com/content/www/us/en/software-developers/intel-txt-software-development-guide.html .BR lcp2_crtpol (8), .BR lcp2_crtpolelt (8), .BR lcp2_mlehash (8), .BR openssl(1). tboot-1.10.5/docs/man/lcp2_mlehash.80000644000000000000000000000331014210363175015207 0ustar 00000000000000.\" .TH LCP_MLEHASH 8 "2020-05-10" "tboot" "User Manuals" .SH NAME lcp2_mlehash \- generate a hash of a TXT MLE binary file and print it to STDOUT as text. .SH SYNOPSIS .B lcp2_mlehash .RB [\| --create \|] .RB [\| --cmdline .IR cmdline \|] .RB [\| --alg .IR hashalg \|] .RB [\| --help \|] .RB [\| --verbose \|] .I mle-file .SH DESCRIPTION .B lcp2_mlehash is used to generate a hash of the portion of an executable file that contains the Intel(R) TXT measured launched environment (MLE). In the MLE binary file, the portion of the file to be used as the MLE is specified in the MLE header structure. If verbose mode is not used, the output is suitable for use as the mle-file to the .B lcp2_crtpolelt command. .SH OPTIONS .TP .I mle-file File name of the MLE binary. If it is a gzip file then it will be un-ziped before hashing. .TP .B --create Create a hash. .TP .BI --cmdline\ cmdline Specify quote-delimited command line. It is important to specify the command line that is used when launching the MLE or the hash will not match what is calculated by SINIT. .TP .BI --alg\ hashalg Specify the hash algorithm to use. Supported values are sha1, sha256, sha384 and sha512. .TP .B --help Print out the help message. .TP .B --verbose Verbose mode, display progress indications. .SH EXAMPLES .EX lcp2_mlehash --create --cmdline "logging=memory,serial,vga" --alg sha1 /boot/tboot.gz > mle-hash .EE .SH "SEE ALSO" .BR "Full documentation of MLE, Intel(R) TXT and LCP is available in Intel(R) TXT Measured Launch Environment Deleveloper's Guide, available at: http://www.intel.com/content/www/us/en/software-developers/intel-txt-software-development-guide.html .BR lcp2_crtpol (8), .BR lcp2_crtpolelt (8), .BR lcp2_crtpollist (8). tboot-1.10.5/docs/man/tb_polgen.80000644000000000000000000000625314210363175014630 0ustar 00000000000000.\" .TH TB_POLGEN 8 "2011-12-31" "tboot" "User Manuals" .SH NAME tb_polgen \- manage tboot verified launch policy .SH SYNOPSIS .B tb_polgen .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B tb_polgen is used to manage tboot verified launch policy. .SH COMMANDS .TP .B \-\-create Create an empty tboot verified launch policy file. .RS .TP \fB\-\-type \fInonfatal \fR|\fI continue \fR|\fI halt\fR Nonfatal means ignoring all non-fatal errors and continuing. Continue means ignoring verification errors and halting otherwise. Halt means halting on any errors. .TP \fR[\fB\-\-ctrl \fIpolicy-control-value\fR] The default value 1 is to extend policy into PCR 17. .TP \fR[\fB\-\-alg \fIsha1 \fR|\fI sha256 \fR|\fI sha384 \fR|\fI sha512\fR] Policy hashing algorithm. .TP \fIpolicy-file\fR .RE .TP .B \-\-add Add a module hash entry into a policy file. .RS .TP \fB\-\-num \fImodule-number \fR|\fI any\fR The module-number is the 0-based module number corresponding to modules loaded by the bootloader. .TP \fB\-\-pcr \fITPM-PCR-number \fR|\fI none\fR The TPM-PCR-number is the PCR to extend the module's measurement into. .TP \fB\-\-hash \fIany \fR|\fI image\fR .TP \fR[\fB\-\-cmdline \fIcommand-line\fR] The command line is from grub.conf, and it should not include the module name (e.g. "/xen.gz"). .TP \fR[\fB\-\-image \fIimage-file-name\fR] .TP \fIpolicy-file\fR .RE .TP .B \-\-del Delete a module hash entry from a policy file. .RS .TP \fB\-\-num \fImodule-number \fR|\fI any\fR The module-number is the 0-based module number corresponding to modules loaded by the bootloader. .TP \fR[\fB\-\-pos \fIhash-number\fR] The hash-number is the 0-based index of the hash, within the list of hashes for the specified module. .TP \fIpolicy-file\fR .RE .TP .B \-\-unwrap Extract the tboot verified launch policy from a TXT LCP element file. .RS .TP \fB\-\-elt \fIelt-file\fR .TP \fIpolicy-file\fR .RE .TP \fB\-\-show \fIpolicy-file\fR Show the policy information in a policy file. .TP .B \-\-help Print out the help message. .TP .B \-\-verbose Enable verbose output; can be specified with any command. .SH EXAMPLES \fBtb_polgen \-\-create \-\-type \fInonfatal vl.pol\fR .PP \fBtb_polgen \-\-add \-\-num \fI0 \fB\-\-pcr \fInone \fB\-\-hash \fIimage \fB\-\-cmdline \fI"cmdline" \fB\-\-image \fI/boot/xen.gz vl.pol\fR .PP \fBtb_polgen \-\-add \-\-num \fI1 \fB\-\-pcr \fI19 \fB\-\-hash \fIimage \fB\-\-cmdline \fI"cmdline" \fB\-\-image \fI/boot/vmlinuz-2.6.18.8-xen vl.pol\fR .PP \fBtb_polgen \-\-add \-\-num \fI2 \fB\-\-pcr \fI19 \fB\-\-hash \fIimage \fB\-\-cmdline \fI"" \fB\-\-image \fI/boot/initrd-2.6.18.8-xen.img vl.pol\fR .PP \fBtb_polgen \-\-del \-\-num \fI1 vl.pol\fR .PP \fBtb_polgen \-\-show \-\-verbose \fIvl.pol\fR .SS "Note1:" It is not necessary to specify a PCR for module 0, since this module's measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. .SS "Note2:" --unwrap is not implemented correctly. There should be a defined UUID for this and that should be checked before copying the data. There should be a wrap or similar command to generates an element file for a policy. .SH "SEE ALSO" .BR lcp_crtpol (8), .BR lcp_crtpol2 (8), .BR lcp_crtpolelt (8). tboot-1.10.5/docs/man/txt-acminfo.80000644000000000000000000000064014210363175015102 0ustar 00000000000000.\" .TH TXT-ACMINFO 8 "2011-12-31" "tboot" "User Manuals" .SH NAME txt-acminfo \- display the header info of a TXT ACM .SH SYNOPSIS .B txt-acminfo .I acm-file-name .SH DESCRIPTION .B txt-acminfo is used to display the header information for a TXT Authenticated Code Module (ACM) and match it with the current system. .SH OPTIONS .TP .I acm-file-name ACM file name .SH EXAMPLES \fBtxt-acminfo \fIi7_QUAD_SINIT_20.BIN tboot-1.10.5/docs/man/txt-parse_err.80000644000000000000000000000063414210363175015453 0ustar 00000000000000.\" .TH TXT-PARSE_ERR 8 "2020-05-10" "tboot" "User Manuals" .SH NAME txt-parse_err \- parse TXT.ERRORCODE value .SH SYNOPSIS .B txt-parse_err .RB [\| .IR error_value\ \|] .SH DESCRIPTION .B txt-parse_err can be used to parse a TXT.ERRORCODE value. If no value is given as a parameter parse_err will attempt to read the error code from memory (via /dev/mem). .SH OPTIONS .TP .BI error_value Error value to parse tboot-1.10.5/docs/man/txt-stat.80000644000000000000000000000100414210363175014434 0ustar 00000000000000.\" .TH TXT-STAT 8 "2011-12-31" "tboot" "User Manuals" .SH NAME txt-stat \- display the status of TXT .SH SYNOPSIS .B txt-stat .RB [\| \-\-heap \|] .RB [\| \-h \|] .SH DESCRIPTION .B txt-stat is used to display various information about the status of Intel(R) TXT. It will display the TXT configuration registers status and TBOOT log by default. .SH OPTIONS .TP .B \-\-heap Print out the BiosData structure from the TXT heap. .TP \fB\-h\fR, \fB\-\-help Print out this help message. .SH EXAMPLES \fBtxt-stat \-\-heap tboot-1.10.5/docs/policy_v1.txt0000644000000000000000000000644214210363175014461 0ustar 00000000000000**************************************************************************** *** *** *** Launch Control Policy v1 *** *** *** **************************************************************************** This document describes Launch Control Policies for platforms produced before 2009 (Weybridge, Montevina, McCreary). These are some example instructions for creating and provisioning both an Intel(R) TXT Launch Control Policy (LCP) and a Verified Launch policy. These steps assume that all referenced binaries have already been built and paths are relative to the lcptools/ directory: Create LCP policy: ----------------- 1. lcptools/lcp_mlehash -c "the command line for tboot from grub.conf" /boot/tboot.gz > mle_hash 2. lcptools/lcp_crtpol -t hashonly -m mle_hash -o lcp.pol Note: The '-c' parameter to lcp_mlehash is used to specify tboot's command line, as it would appear in grub.conf. It can be omitted if no command line parameters are specified in grub.conf (or it can be empty). It should not include the module name (e.g. "/tboot.gz"). Create Verified Launch policy: ----------------------------- 1. tb_polgen/tb_polgen --create --type nonfatal vl.pol 2. tb_polgen/tb_polgen --add --num 0 --pcr none --hash image --cmdline "the command line for xen from grub.conf" --image /boot/xen.gz vl.pol 3. tb_polgen/tb_polgen --add --num 1 --pcr 19 --hash image --cmdline "the command line for dom0 from grub.conf" --image /boot/vmlinuz-2.6.18.8-xen vl.pol 4. tb_polgen/tb_polgen --add --num 2 --pcr 19 --hash image --cmdline "" --image /boot/initrd-2.6.18.8-xen.img vl.pol Note: The command lines should not include the module name (e.g. "/xen.gz"). This is a change from the previous version of policy support and was done because a module's measurement should only depend on its content and not on its location. Note 2: It is not necessary to specify a PCR for module 0, since this module's measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. Take ownership of the TPM: ------------------------- 1. modprobe tpm_tis (you may need 'force=1 interrupts=0') 2. tcsd 3. tpm_takeownership -z - choose password for TPM Note: When taking ownership of the TPM it is important to set the SRK auth to all 0s so that tboot will be able to seal/unseal the measurements. The '-z' flag to tpm_takeownership will do this. Define tboot error TPM NV index: ------------------------------- 1. lcptools/tpmnv_defindex -i 0x20000002 -s 8 -pv 0 -rl 0x07 -wl 0x07 -p TPM-password Define LCP and Verified Launch policy indices: --------------------------------------------- 1. lcptools/tpmnv_defindex -i owner -p TPM-password-from-taking-ownership 2. lcptools/tpmnv_defindex -i 0x20000001 -s 256 -pv 0x02 -p TPM-password Write LCP and Verified Launch policies to TPM: --------------------------------------------- (modprobe tpm_tis; tcsd;) 1. lcptools/lcp_writepol -i owner -f lcp.pol -p TPM-password 2. lcptools/lcp_writepol -i 0x20000001 -f vl.pol -p TPM-password tboot-1.10.5/docs/policy_v2.txt0000644000000000000000000000622714210363175014463 0ustar 00000000000000**************************************************************************** *** *** *** Launch Control Policy v2 *** *** *** **************************************************************************** This document describes Launch Control Policies for platforms produced after 2008. These are some example instructions for creating and provisioning both an Intel(R) TXT Launch Control Policy (LCP) and a Verified Launch policy. These steps assume that all referenced binaries have already been built and paths are relative to the lcptools-v2/ directory: Create LCP policy: ----------------- o See the file lcptools-v2/lcptools-v2.txt for instructions on creating policies and policy data files using the new tools. Create Verified Launch policy: ----------------------------- 1. tb_polgen/tb_polgen --create --type nonfatal vl.pol 2. tb_polgen/tb_polgen --add --num 0 --pcr none --hash image --cmdline "the command line for xen from grub.conf" --image /boot/xen.gz vl.pol 3. tb_polgen/tb_polgen --add --num 1 --pcr 19 --hash image --cmdline "the command line for dom0 from grub.conf" --image /boot/vmlinuz-2.6.18.8-xen vl.pol 4. tb_polgen/tb_polgen --add --num 2 --pcr 19 --hash image --cmdline "" --image /boot/initrd-2.6.18.8-xen.img vl.pol Note: The command lines should not include the module name (e.g. "/xen.gz"). This is a change from the previous version of policy support and was done because a module's measurement should only depend on its content and not on its location. Note 2: It is not necessary to specify a PCR for module 0, since this module's measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. Take ownership of the TPM: ------------------------- 1. modprobe tpm_tis (you may need 'force=1 interrupts=0') 2. tcsd 3. tpm_takeownership -z - choose password for TPM Note: When taking ownership of the TPM it is important to set the SRK auth to all 0s so that tboot will be able to seal/unseal the measurements. The '-z' flag to tpm_takeownership will do this. Define tboot error TPM NV index: ------------------------------- 1. lcptools/tpmnv_defindex -i 0x20000002 -s 8 -pv 0 -rl 0x07 -wl 0x07 -p TPM-password Define LCP and Verified Launch policy indices: --------------------------------------------- 1. lcptools/tpmnv_defindex -i owner -s 0x36 -p TPM-owner-password 2. lcptools/tpmnv_defindex -i 0x20000001 -s 256 -pv 0x02 -p TPM-owner-password Write LCP and Verified Launch policies to TPM: --------------------------------------------- (modprobe tpm_tis; tcsd;) 1. lcptools/lcp_writepol -i owner -f list.pol -p TPM-password 2. lcptools/lcp_writepol -i 0x20000001 -f vl.pol -p TPM-password Modify grub.conf to load the policy data file: --------------------------------------------- 1. Edit grub.conf and add the following: module /list.data where you should use the path to this file. tboot-1.10.5/docs/tboot_flow.md0000644000000000000000000000764214210363175014516 0ustar 00000000000000Execution flow for TBOOT ======================== General flow ============ Diagrams below describes general flow of 4 possible use scenarios:
@startuml Boot flow :GRUB; :TBOOT (pre-SINIT); :SINIT; :TBOOT (post-SINIT); :Linux; @enduml @startuml Shutdown flow :Linux; :TBOOT (shutdown); :shutdown; @enduml @startuml S3 enter :Linux; :TBOOT (shudown); :enter sleep; @enduml @startuml S3 exit :exit sleep; :TBOOT (pre-SINIT); :SINIT; :TBOOT (post-SINIT); :Linux; @enduml
S3 sleep/wakeup and standard launch/shutdown are very similar from general perspective, main differences are entry points for jumping to Linux kernel. For detailed description what is going on in each scenario please look at next sections. Platform launch =============== In general there are few steps that TBOOT has to do during platform launch: - check if platform is TXT capable - load SINIT - prepare and launch SINIT - measure modules described in policy - launch kernel A more complex description of each step is shown below. @startuml !include launch.plantuml @enduml TBOOT entry point for pre-SINIT and post-SINIT launch is the same, so in early step there is a detection if SINIT was launched or not and there are two branches that handle each scenario. Red arrow indicates error flow which depends on policy, there are few possibilities: - boot Linux in non-trusted environment - halt platform - reboot platform To not make diagram too complex few blocks are described in details in following sections Load SINIT ---------- This step is first point where we checks if platform has any chance to perform measured boot. SINIT is mandatory module for Intel TXT, it is distributed as binary and can be either loaded by GRUB and passed to TBOOT via MBI or (only in server platforms) included in BIOS binary. If there is no SINIT, that matches current platform, provided we can stop measured boot execution at this step. @startuml !include load_sinit.plantuml @enduml TBOOT always takes newer SINIT, there can be multiple entries in MBI and one in BIOS. If both MBI and BIOS has exactly the same SINIT version, one from BIOS is taken. Prepare for SINIT launch ------------------------ There a few requirements for platform state before GETSEC[SENTER] can be called: - CPU has to be in protected mode - cache must be enabled - native FPU error reporting must be enabled - cannot be in virtual-8086 mode TBOOT also has to configure MTRRs and VT-d to be compliant wth MLE developers guide, in other case SINIT will detect wrong configuration and invoke LT-reset. Handle post-launch ------------------ When SINIT finished its job it returns back to TBOOT and post-SINIT code branch is executed. There few operations that are done just after returning from SINIT: - verify TXT heap structures - verify saved MTRRs - verify PMRs - wakeup RLPs - restore MTRRs - set TXT.CMD.SECRETS flag - open locality 1 Platform shutdown ================= If Linux is launched inside measured environment, the last step in shutdown/S3 procedure will be jumping to TBOOT shutdown entry point to properly tear down environment and wipe secrets from memory. Shutdown flow in TBOOT is shown below: @startuml !include shutdown.plantuml @enduml As all CPUs are jumping to TBOOT's shutdown entry, it has to filter-out all APs and continue work only on BSP. One of the important step is to call GETSEC[SEXIT] to exit measured environment. Before executing that instruction, TBOOT has to: - clear SECRETS flag - unlock memory configuration - close TXT private config space (implicitly closes TPM localities 1 + 2) - disable SMXE After GETSEC[SEXIT] TBOOT can proceed to finish shutdown process.tboot-1.10.5/docs/txt-info.txt0000644000000000000000000000124314210363175014316 0ustar 00000000000000Intel's technology for safer computing, Intel(R) Trusted Execution Technology (Intel(R) TXT), defines platform-level enhancements that provide the building blocks for creating trusted platforms. Intel(R) TXT was formerly known by the code name LaGrande Technology (LT). Intel(R) TXT in Brief: ---------------------- o Provides dynamic root of trust for measurement (DRTM) o Data protection in case of improper shutdown o Verification and enforcement of launched environment For more information, see http://www.intel.com/technology/security/. This site also has a link to the Intel(R) TXT MLE Developers Manual, which has been updated for the new released platforms. tboot-1.10.5/docs/vlp.txt0000644000000000000000000000474514210363175013361 0ustar 00000000000000**************************************************************************** *** *** *** Verified Launch control Policy *** *** *** **************************************************************************** After entering a trusted environment, Tboot will extend verification from MLE to OS/VMM and dom0, called Verified Launch, using policies similar to the LCP and also store the policy in TPM NV. Verified Launch control Policy (VLP) is defined by platform owner/user for OS/VMM verified Launch purpose on Intel TXT platforms. VLP can be created and managed by tb_polgen tool in tb_polgen/ directory and provisioned into TPM NV using the lcptools in lcptools/ or lcptools-v2/ directory in tboot package. Unlike Launch Control Policy, VLP is tboot specific and mainly consumed by tboot itself to verify if OS/VMM to be launched match the VLP. VLP related data structures and policy enforcement engine are defined and implemented in tboot, more details can be found in tboot VLP related source codes. Currently TPM nv index 0x20000001 is specifically defined to store VLP crreated by tb_polgen tool and consumed by tboot to verify OS/VMM during a verified launch process. For how to create TPM nv index, please refer to Linux_LCP_Tools_User_Manual in lcptools/ directory. Create Verified Launch control Policy: ----------------------------- 1. tb_polgen/tb_polgen --create --type nonfatal vl.pol 2. tb_polgen/tb_polgen --add --num 0 --pcr none --hash image --cmdline "the command line for xen from grub.conf" --image /boot/xen.gz vl.pol 3. tb_polgen/tb_polgen --add --num 1 --pcr 19 --hash image --cmdline "the command line for dom0 from grub.conf" --image /boot/vmlinuz-2.6.18.8-xen vl.pol 4. tb_polgen/tb_polgen --add --num 2 --pcr 19 --hash image --cmdline "" --image /boot/initrd-2.6.18.8-xen.img vl.pol Note: The command lines should not include the module name (e.g. "/xen.gz"). This is a change from the previous version of policy support and was done because a module's measurement should only depend on its content and not on its location. Note 2: It is not mandatory to specify a PCR for module 0, since this module's Measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. tboot-1.10.5/include/config.h0000644000000000000000000001057314210363175014124 0ustar 00000000000000/* * config.h: project-wide definitions * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __CONFIG_H__ #define __CONFIG_H__ /* * build/support flags */ /* address tboot will load and execute at */ #define TBOOT_START 0x0804000 /* start address of tboot MLE page table, also the beginning of tboot memory */ #define TBOOT_BASE_ADDR 0x0800000 /* address that tboot will do s3 resume at */ /* (must be in lower 1MB (real mode) and less than Xen trampoline @ 0x8c000) */ #define TBOOT_S3_WAKEUP_ADDR 0x8a000 /* these addrs must be in low memory so that they are mapped by the */ /* kernel at startup */ /* address/size for memory-resident serial log (when enabled) */ #define TBOOT_SERIAL_LOG_ADDR 0x60000 #define TBOOT_SERIAL_LOG_SIZE 0x08000 /* address/size for modified e820 table */ #define TBOOT_E820_COPY_ADDR (TBOOT_SERIAL_LOG_ADDR + \ TBOOT_SERIAL_LOG_SIZE) #define TBOOT_E820_COPY_SIZE 0x01800 /* address/size for modified EFI memory map table */ #define TBOOT_EFI_MEMMAP_COPY_ADDR (TBOOT_E820_COPY_ADDR + \ TBOOT_E820_COPY_SIZE) #define TBOOT_EFI_MEMMAP_COPY_SIZE 0x08000 /* address/size for modified VMM/kernel command line */ #define TBOOT_KERNEL_CMDLINE_ADDR (TBOOT_EFI_MEMMAP_COPY_ADDR + \ TBOOT_EFI_MEMMAP_COPY_SIZE) #define TBOOT_KERNEL_CMDLINE_SIZE 0x0400 #ifndef NR_CPUS #define NR_CPUS 1024 #endif #ifdef __ASSEMBLY__ #define ENTRY(name) \ .globl name; \ .align 16,0x90; \ name: #else extern char _start[]; /* start of tboot */ extern char _end[]; /* end of tboot */ #endif #define COMPILE_TIME_ASSERT(e) \ { \ struct tmp { \ int a : ((e) ? 1 : -1); \ }; \ } #define __data __attribute__ ((__section__ (".data"))) #define __text __attribute__ ((__section__ (".text"))) #define __mlept __attribute__ ((__section__ (".mlept"))) #define __packed __attribute__ ((packed)) /* tboot log level */ #ifdef NO_TBOOT_LOGLVL #define TBOOT_NONE #define TBOOT_ERR #define TBOOT_WARN #define TBOOT_INFO #define TBOOT_DETA #define TBOOT_ALL #else /* NO_TBOOT_LOGLVL */ #define TBOOT_NONE "<0>" #define TBOOT_ERR "<1>" #define TBOOT_WARN "<2>" #define TBOOT_INFO "<3>" #define TBOOT_DETA "<4>" #define TBOOT_ALL "<5>" #endif /* NO_TBOOT_LOGLVL */ /* Framebuffer */ #define FB_MAX_HRES 2560 #define FB_MAX_VRES 1440 #define FB_BPP 32 #endif /* __CONFIG_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/elf_defns.h0000644000000000000000000001411514210363175014600 0ustar 00000000000000/* * elf_defns.h: ELF file type definitions * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __ELF_DEFNS_H__ #define __ELF_DEFNS_H__ /* Elf header */ typedef struct { unsigned char e_ident[16]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint32_t e_entry; uint32_t e_phoff; uint32_t e_shoff; uint32_t e_flags; uint16_t e_ehsz; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } elf_header_t; /* elf64_header_t */ typedef struct { unsigned char e_ident[16]; /* ELF identification */ uint16_t e_type; /* Object file type */ uint16_t e_machine; /* Machine type */ uint32_t e_version; /* Object file version */ uint64_t e_entry; /* Entry point address */ uint64_t e_phoff; /* Program header offset */ uint64_t e_shoff; /* Section header offset */ uint32_t e_flags; /* Processor-specific flags */ uint16_t e_ehsize; /* ELF header size */ uint16_t e_phentsize; /* Size of program header entry */ uint16_t e_phnum; /* Number of program header entries */ uint16_t e_shentsize; /* Size of section header entry */ uint16_t e_shnum; /* Number of section header entries */ uint16_t e_shstrndx; /* Section name string table index */ } elf64_header_t; /* e_ident[] Identification Indexes */ #define EI_MAG0 0 /* File identification */ #define EI_MAG1 1 /* File identification */ #define EI_MAG2 2 /* File identification */ #define EI_MAG3 3 /* File identification */ #define EI_CLASS 4 /* File class */ #define EI_DATA 5 /* Data encoding */ #define EI_VERSION 6 /* File version */ #define EI_PAD 7 /* Start of padding bytes */ #define EI_NIDENT 8 /* Size of e_ident[] */ /* Magic number */ #define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ #define ELFMAG1 'E' /* e_ident[EI_MAG1] */ #define ELFMAG2 'L' /* e_ident[EI_MAG2] */ #define ELFMAG3 'F' /* e_ident[EI_MAG3] */ /* e_ident[EI_CLASS] */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ /* e_ident[EI_DATA] */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* Least significant byte */ #define ELFDATA2MSB 2 /* Most significant byte */ /* e_type */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_LOPROC 0xff00 /* Processor-specific */ #define ET_HIPROC 0xffff /* Processor-specific */ /* e_machine */ #define ET_NONE 0 /* No machine */ #define EM_M32 1 /* At&t We 32100 */ #define EM_SPARC 2 /* SPARC */ #define EM_386 3 /* Intel architecture */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS RS3000 Big-Endian */ #define EM_MIPS_RS4_BE 10 /* MIPS RS4000 Big-Endian */ #define EM_AMD64 62 /* AMDs x86-64 architecture */ /* e_version */ #define EV_NONE 0 /* Invalid version */ #define EV_CURRENT 1 /* Current version */ /* Program header */ typedef struct { uint32_t p_type; uint32_t p_offset; uint32_t p_vaddr; uint32_t p_paddr; uint32_t p_filesz; uint32_t p_memsz; uint32_t p_flags; uint32_t p_align; } elf_program_header_t; typedef struct{ uint32_t p_type; /* Type of segment */ uint32_t p_flags; /* Segment attributes */ uint64_t p_offset; /* Offset in file */ uint64_t p_vaddr; /* Virtual address in memory */ uint64_t p_paddr; /* Reserved */ uint64_t p_filesz; /* Size of segment in file */ uint64_t p_memsz; /* Size of segment in memory */ uint64_t p_align; /* Alignment of segment */ } elf64_program_header_t; /* p_type */ #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff /* multiboot magic */ #define MB_MAGIC 0x2badb002 #endif /* __ELF_DEFNS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/hash.h0000644000000000000000000001032014210363175013570 0ustar 00000000000000/* * hash.h: definition of and support fns for tb_hash_t type * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __HASH_H__ #define __HASH_H__ #define TB_HALG_SHA1_LG 0x0000 /* legacy define for SHA1 */ #define TB_HALG_SHA1 0x0004 #define TB_HALG_SHA256 0x000B #define TB_HALG_SM3 0x0012 #define TB_HALG_SHA384 0x000C #define TB_HALG_SHA512 0x000D #define TB_HALG_NULL 0x0010 #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 #define SM3_LENGTH 32 #define SHA384_LENGTH 48 #define SHA512_LENGTH 64 typedef uint8_t sha1_hash_t[SHA1_LENGTH]; typedef uint8_t sha256_hash_t[SHA256_LENGTH]; typedef uint8_t sm3_hash_t[SM3_LENGTH]; typedef uint8_t sha384_hash_t[SHA384_LENGTH]; typedef uint8_t sha512_hash_t[SHA512_LENGTH]; typedef union { uint8_t sha1[SHA1_LENGTH]; uint8_t sha256[SHA256_LENGTH]; uint8_t sm3[SM3_LENGTH]; uint8_t sha384[SHA384_LENGTH]; uint8_t sha512[SHA512_LENGTH]; } tb_hash_t; static inline const char *hash_alg_to_string(uint16_t hash_alg) { if ( hash_alg == TB_HALG_SHA1 || hash_alg == TB_HALG_SHA1_LG ) return "TB_HALG_SHA1"; else if ( hash_alg == TB_HALG_SHA256 ) return "TB_HALG_SHA256"; else if ( hash_alg == TB_HALG_SM3 ) return "TB_HALG_SM3"; else if ( hash_alg == TB_HALG_SHA384 ) return "TB_HALG_SHA384"; else if ( hash_alg == TB_HALG_SHA512 ) return "TB_HALG_SHA512"; else return "unsupported"; } static inline unsigned int get_hash_size(uint16_t hash_alg) { if ( hash_alg == TB_HALG_SHA1 || hash_alg == TB_HALG_SHA1_LG ) return SHA1_LENGTH; else if ( hash_alg == TB_HALG_SHA256 ) return SHA256_LENGTH; else if ( hash_alg == TB_HALG_SM3 ) return SM3_LENGTH; else if ( hash_alg == TB_HALG_SHA384 ) return SHA384_LENGTH; else if ( hash_alg == TB_HALG_SHA512 ) return SHA512_LENGTH; else return 0; } extern bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg); extern bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash, uint16_t hash_alg); extern bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg); extern void print_hash(const tb_hash_t *hash, uint16_t hash_alg); extern bool import_hash(const char *string, tb_hash_t *hash, uint16_t alg); extern void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg); #endif /* __HASH_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/lcp.h0000644000000000000000000000762314210363175013437 0ustar 00000000000000/* * Copyright 2001 - 2007 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __TXT_LCP_H__ #define __TXT_LCP_H__ #ifndef __packed #define __packed __attribute__ ((packed)) #endif /*--------- LCP UUID ------------*/ #define LCP_POLICY_DATA_UUID {0xab0d1925, 0xeee7, 0x48eb, 0xa9fc, \ {0xb, 0xac, 0x5a, 0x26, 0x2d, 0xe}} /*--------- LCP Policy Algorithm ------------*/ #define LCP_POLHALG_SHA1 0 /*--------- LCP Policy Type ------------*/ #define LCP_POLTYPE_HASHONLY 0 #define LCP_POLTYPE_UNSIGNED 1 #define LCP_POLTYPE_SIGNED 2 #define LCP_POLTYPE_ANY 3 #define LCP_POLTYPE_FORCEOWNERPOLICY 4 /*--------- LCP Policy List type ------------*/ #define LCP_POLDESC_MLE_UNSIGNED 0x0001 #define LCP_POLDESC_PCONF_UNSIGNED 0x0002 /*--------- LCP reserved Indices------------*/ #define INDEX_LCP_DEF 0x50000001 #define INDEX_LCP_OWN 0x40000001 #define INDEX_AUX 0x50000002 /*------ Default Permission, size and locality for reserved Indices--------*/ #define PERMISSION_DEF 0x00002000 #define PERMISSION_OWN 0x00000002 #define PERMISSION_AUX 0x0 #define DATASIZE_POL 34 #define DATASIZE_AUX 64 #define LOCALITY_DEFAULT 0x1f #define WR_LOCALITY_AUX 0x18 /*--------- Other data structures of LCP Policy ------------*/ #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 typedef union { uint8_t sha1[SHA1_LENGTH]; uint8_t sha256[SHA256_LENGTH]; } lcp_hash_t; typedef struct __packed { uint8_t version; uint8_t hash_alg; /* one of LCP_POLHALG_* */ uint8_t policy_type; /* one of LCP_POLTYPE_* */ uint8_t sinit_revocation_counter; uint32_t policy_control; uint16_t reserved[3]; lcp_hash_t policy_hash; } lcp_policy_t; typedef struct __packed { uint8_t version; uint8_t count; union{ lcp_hash_t* hashes; TPM_PCR_INFO_SHORT* pcrs; }; } lcp_unsigned_list_t; typedef struct __packed { uint16_t type; /* One of LCP_POLDESC_* */ lcp_unsigned_list_t unsigned_list; } lcp_policy_list_t; typedef struct __packed { uint8_t version; uint8_t policy_data_listsize; lcp_policy_list_t policy_data_list[]; } lcp_unsigned_policy_data_t; typedef struct __packed { uuid_t uuid; lcp_unsigned_policy_data_t unsigned_data; } lcp_policy_data_t; #endif /* __TXT_LCP_H__ */ tboot-1.10.5/include/lcp2.h0000644000000000000000000001313114210363175013510 0ustar 00000000000000/* * Copyright 2001 - 2014 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __TXT_LCP2_H__ #define __TXT_LCP2_H__ #ifndef __packed #define __packed __attribute__ ((packed)) #endif /*--------- LCP UUID ------------*/ #define LCP_POLICY_DATA_UUID {0xab0d1925, 0xeee7, 0x48eb, 0xa9fc, \ {0xb, 0xac, 0x5a, 0x26, 0x2d, 0xe}} /*--------- CUSTOM ELT UUID ------------*/ #define LCP_CUSTOM_ELEMENT_TBOOT_UUID {0xc3930641, 0xe3cb, 0x4f40, 0x91d7, \ {0x27, 0xf8, 0xb9, 0xe2, 0x5c, 0x86}} /*--------- LCP FILE SIGNATURE ------------*/ #define LCP_POLICY_DATA_FILE_SIGNATURE "Intel(R) TXT LCP_POLICY_DATA\0\0\0\0" /*--------- LCP Policy Algorithm ------------*/ #define LCP_POLHALG_SHA1 0 /*--------- LCP Policy Type ------------*/ #define LCP_POLTYPE_LIST 0 #define LCP_POLTYPE_ANY 1 /*--------- LCP reserved TPM NV Indices ------------*/ #define INDEX_LCP_DEF 0x50000001 #define INDEX_LCP_OWN 0x40000001 #define INDEX_AUX 0x50000002 /*------ Default Permission, size and locality for reserved Indices --------*/ #define PERMISSION_DEF 0x00002000 #define PERMISSION_OWN 0x00000002 #define PERMISSION_AUX 0x0 #define DATASIZE_POL 54 #define DATASIZE_AUX 64 #define LOCALITY_DEFAULT 0x1f #define WR_LOCALITY_AUX 0x18 /*--------- Other data structures of LCP Policy ------------*/ #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 typedef union { uint8_t sha1[SHA1_LENGTH]; uint8_t sha256[SHA256_LENGTH]; } lcp_hash_t; #define LCP_DEFAULT_POLICY_VERSION 0x0202 #define LCP_DEFAULT_POLICY_CONTROL 0x00 #define LCP_MAX_LISTS 8 typedef struct __packed { uint16_t version; uint8_t hash_alg; /* one of LCP_POLHALG_* */ uint8_t policy_type; /* one of LCP_POLTYPE_* */ uint8_t sinit_min_version; uint8_t reserved1; uint16_t data_revocation_counters[LCP_MAX_LISTS]; uint32_t policy_control; uint32_t reserved2[2]; lcp_hash_t policy_hash; } lcp_policy_t; #define LCP_POLSALG_NONE 0 #define LCP_POLSALG_RSA_PKCS_15 1 #define LCP_SIG_EXPONENT 65537 typedef struct __packed { uint16_t revocation_counter; uint16_t pubkey_size; uint8_t pubkey_value[0]; uint8_t sig_block[]; } lcp_signature_t; /* set bit 0: override PS policy for this element type */ #define DEFAULT_POL_ELT_CONTROL 0x0001 typedef struct __packed { uint32_t size; uint32_t type; uint32_t policy_elt_control; uint8_t data[]; } lcp_policy_element_t; #define LCP_DEFAULT_POLICY_LIST_VERSION 0x0100 typedef struct __packed { uint16_t version; uint8_t reserved; uint8_t sig_alg; uint32_t policy_elements_size; lcp_policy_element_t policy_elements[]; /* optionally: */ /* lcp_signature_t sig; */ } lcp_policy_list_t; #define LCP_FILE_SIG_LENGTH 32 typedef struct __packed { char file_signature[LCP_FILE_SIG_LENGTH]; uint8_t reserved[3]; uint8_t num_lists; lcp_policy_list_t policy_lists[]; } lcp_policy_data_t; /*--------- LCP Element sub-types ------------*/ #define LCP_POLELT_TYPE_MLE 0 typedef struct __packed { uint8_t sinit_min_version; uint8_t hash_alg; uint16_t num_hashes; lcp_hash_t hashes[]; } lcp_mle_element_t; #define LCP_POLELT_TYPE_PCONF 1 /* clients that will use this type need a proper defintion of TPM_PCR_INFO_SHORT */ #ifndef TPM_PCR_INFO_SHORT #define TPM_PCR_INFO_SHORT uint8_t #endif typedef struct __packed { uint16_t num_pcr_infos; TPM_PCR_INFO_SHORT pcr_infos[]; } lcp_pconf_element_t; #define LCP_POLELT_TYPE_SBIOS 2 typedef struct __packed { uint8_t hash_alg; uint8_t reserved1[3]; lcp_hash_t fallback_hash; uint16_t reserved2; uint16_t num_hashes; lcp_hash_t hashes[]; } lcp_sbios_element_t; #define LCP_POLELT_TYPE_CUSTOM 3 typedef struct __packed { uuid_t uuid; uint8_t data[]; } lcp_custom_element_t; #endif /* __TXT_LCP2_H__ */ tboot-1.10.5/include/lcp3.h0000644000000000000000000003332214210363175013515 0ustar 00000000000000/* * Copyright 2014 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LCP_H__ #define __LCP_H__ #ifndef __packed #define __packed __attribute__ ((packed)) #endif /* * Version = 3.0 - new version format of LCP Policy. Major version * is incremented since layout is incompatible with previous revision. */ /*--------- LCP UUID ------------*/ #define LCP_POLICY_DATA_UUID {0xab0d1925, 0xeee7, 0x48eb, 0xa9fc, \ {0xb, 0xac, 0x5a, 0x26, 0x2d, 0xe}} /*--------- CUSTOM ELT UUID ------------*/ #define LCP_CUSTOM_ELEMENT_TBOOT_UUID {0xc3930641, 0xe3cb, 0x4f40, 0x91d7, \ {0x27, 0xf8, 0xb9, 0xe2, 0x5c, 0x86}} /*--------- LCP FILE SIGNATURE ------------*/ #define LCP_POLICY_DATA_FILE_SIGNATURE "Intel(R) TXT LCP_POLICY_DATA\0\0\0\0" /*--------- SM2 Default ID value ---------*/ #define SM2_ID '\0' #define SM2_ID_LEN 0 /*--------- LCP Policy Type ------------*/ #define LCP_POLTYPE_LIST 0 #define LCP_POLTYPE_ANY 1 #define LCP_VER_2_0 0x0200 #define LCP_VER_2_1 0x0201 #define LCP_VER_2_2 0x0202 #define LCP_VER_2_3 0x0203 #define LCP_VER_2_4 0x0204 #define LCP_VER_3_0 0x0300 #define LCP_VER_3_1 0x0301 #define LCP_VER_3_2 0x0302 #define LCP_VER_NULL 0x0000 #define LCP_DEFAULT_POLICY_VERSION LCP_VER_3_0 #define LCP_DEFAULT_POLICY_CONTROL 0x00 #define LCP_MAX_LISTS 8 /*Digest sizes*/ #define SHA1_DIGEST_SIZE 20 #define SHA256_DIGEST_SIZE 32 #define SHA384_DIGEST_SIZE 48 #define SHA512_DIGEST_SIZE 64 #define SM3_256_DIGEST_SIZE 32 /*Default RSA exponent*/ #define LCP_SIG_EXPONENT 65537 /*--------- with LCP_POLICY version 2.0 ------------*/ #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 typedef union { uint8_t sha1[SHA1_LENGTH]; uint8_t sha256[SHA256_LENGTH]; } lcp_hash_t; /*--------- legacy LCP alg names ------------*/ #define LCP_POLHALG_SHA1 0 #define LCP_POLSALG_NONE 0 #define LCP_POLSALG_RSA_PKCS_15 1 /*--------- pconf helper structs ------------*/ #define TPM_LOCALITY_SELECTION uint8_t #define DEFAULT_LOCALITY_SELECT 0x1F typedef lcp_hash_t tpm_composite_hash; typedef struct __packed { uint16_t size_of_select; uint8_t pcr_select; //We only need PCRs 0-7 so it's just one byte here } tpm_pcr_selection; typedef struct __packed { tpm_pcr_selection pcr_selection; TPM_LOCALITY_SELECTION locality_at_release; uint8_t digest_at_release[SHA1_DIGEST_SIZE]; //This is a hash of all selected pcr values } tpm_pcr_info_short_t; /*--------- legacy policy elts ------------*/ #define LCP_POLELT_TYPE_MLE 0 typedef struct __packed { uint8_t sinit_min_version; uint8_t hash_alg; //LCP_POLHALG_SHA1 uint16_t num_hashes; lcp_hash_t hashes[]; } lcp_mle_element_t; #define LCP_POLELT_TYPE_PCONF 1 typedef struct __packed { uint16_t num_pcr_infos; tpm_pcr_info_short_t pcr_infos[]; } lcp_pconf_element_t; typedef struct __packed { uint16_t revocation_counter; uint16_t pubkey_size; uint8_t pubkey_value[0]; uint8_t sig_block[]; } lcp_signature_t; /* set bit 0: override PS policy for this element type */ #define DEFAULT_POL_ELT_CONTROL 0x0001 typedef struct __packed { uint32_t size; uint32_t type; uint32_t policy_elt_control; uint8_t data[]; } lcp_policy_element_t; typedef struct __packed { uuid_t uuid; uint8_t data[]; } lcp_custom_element_t; /* LCP_POLICY_LIST deprecated, kept to support legacy systems LCP_POLICY_LIST2 supported versions currently are: 2.0 and 2.1 LCP_POLICY_LIST2_1 supported versions currently are: 3.0 */ #define LCP_TPM12_POLICY_LIST_VERSION 0x0100 #define LCP_TPM20_POLICY_LIST_VERSION 0x0200 #define LCP_TPM20_POLICY_LIST2_VERSION_201 0x0201 #define LCP_TPM20_POLICY_LIST2_1_VERSION_300 0x0300 //Max supported minor versions #define LCP_TPM12_POLICY_LIST_MAX_MINOR 0x0000 #define LCP_TPM20_POLICY_LIST2_MAX_MINOR 0x0001 #define LCP_TPM20_POLICY_LIST2_1_MAX_MINOR 0x0000 #define LCP_DEFAULT_POLICY_LIST_VERSION LCP_TPM20_POLICY_LIST_VERSION typedef struct __packed { uint16_t version; /* = 1.0 */ uint8_t reserved; uint8_t sig_alg; //LCP_POLSALG_NONE i.e. 0 or *_RSA_PKCS_15 i.e. 1 uint32_t policy_elements_size; lcp_policy_element_t policy_elements[]; /* optionally: */ /* lcp_signature_t sig; */ } lcp_policy_list_t; #define LCP_FILE_SIG_LENGTH 32 typedef struct __packed { char file_signature[LCP_FILE_SIG_LENGTH]; uint8_t reserved[3]; uint8_t num_lists; lcp_policy_list_t policy_lists[]; } lcp_policy_data_t; #define LCP_DEFAULT_POLICY_VERSION_2 0x0202 typedef struct __packed { uint16_t version; /* must be 0x0204 */ uint8_t hash_alg; /* LCP_POLHALG_SHA1* */ uint8_t policy_type; /* one of LCP_POLTYPE_* */ uint8_t sinit_min_version; uint8_t reserved1; uint16_t data_revocation_counters[LCP_MAX_LISTS]; uint32_t policy_control; uint8_t max_sinit_min_version; uint8_t reserved2; uint16_t reserved3; uint32_t reserved4; lcp_hash_t policy_hash; //Must be SHA1 - 20 bytes } lcp_policy_t; /*--------- LCP_POLICY version 3.x ------------*/ #define TPM_ALG_RSA 0x0001 #define TPM_ALG_SHA1 0x0004 #define TPM_ALG_SHA256 0x000B #define TPM_ALG_SHA384 0x000C #define TPM_ALG_SHA512 0x000D #define TPM_ALG_NULL 0x0010 #define TPM_ALG_SM3_256 0x0012 #define TPM_ALG_ECC 0x0023 #define TPM_ALG_MASK_NULL 0x0000 #define TPM_ALG_MASK_SHA1 0x0001 #define TPM_ALG_MASK_SHA256 0x0008 #define TPM_ALG_MASK_SM3_256 0x0020 #define TPM_ALG_MASK_SHA384 0x0040 #define TPM_ALG_MASK_SHA512 0x0080 #define SIGN_ALG_MASK_NULL 0x00000000 #define SIGN_ALG_MASK_RSASSA_1024_SHA1 0x00000001 //Not supported #define SIGN_ALG_MASK_RSASSA_1024_SHA256 0x00000002 #define SIGN_ALG_MASK_RSASSA_2048_SHA1 0x00000004 //Legacy #define SIGN_ALG_MASK_RSASSA_2048_SHA256 0x00000008 //ok #define SIGN_ALG_MASK_RSASSA_3072_SHA256 0x00000040 //ok #define SIGN_ALG_MASK_RSASSA_3072_SHA384 0x00000080 //ok #define SIGN_ALG_MASK_ECDSA_P256 0x00001000 //Sha256 ok #define SIGN_ALG_MASK_ECDSA_P384 0x00002000 //Sha 384 #define SIGN_ALG_MASK_SM2 0x00010000 //ok /*--------- Signature algs ------------*/ #define TPM_ALG_RSASSA 0x0014 #define TPM_ALG_RSAPSS 0x0016 #define TPM_ALG_ECDSA 0x0018 #define TPM_ALG_SM2 0x001B typedef union { uint8_t sha1[SHA1_DIGEST_SIZE]; uint8_t sha256[SHA256_DIGEST_SIZE]; uint8_t sha384[SHA384_DIGEST_SIZE]; uint8_t sha512[SHA512_DIGEST_SIZE]; uint8_t sm3[SM3_256_DIGEST_SIZE]; } lcp_hash_t2; typedef struct __packed { uint16_t hash_alg; uint8_t size_of_select; uint8_t pcr_select[]; } tpms_pcr_selection_t; typedef struct __packed { uint32_t count; tpms_pcr_selection_t pcr_selections; } tpml_pcr_selection_t; typedef struct __packed { uint16_t size; uint8_t buffer[]; } tpm2b_digest_t; typedef struct __packed { tpml_pcr_selection_t pcr_selection; tpm2b_digest_t pcr_digest; } tpms_quote_info_t; #define LCP_POLELT_TYPE_MLE2 0x10 typedef struct __packed { uint8_t sinit_min_version; uint8_t reserved; uint16_t hash_alg; uint16_t num_hashes; lcp_hash_t2 hashes[]; } lcp_mle_element_t2; #define LCP_POLELT_TYPE_PCONF2 0x11 typedef struct __packed { uint16_t hash_alg; uint16_t num_pcr_infos; tpms_quote_info_t pcr_infos[]; } lcp_pconf_element_t2; #define LCP_POLELT_TYPE_SBIOS2 0x12 typedef struct __packed { uint16_t hash_alg; uint8_t reserved1[2]; lcp_hash_t2 fallback_hash; uint16_t reserved2; uint16_t num_hashes; lcp_hash_t2 hashes[]; } lcp_sbios_element_t2; #define LCP_POLELT_TYPE_CUSTOM2 0x13 #define LCP_POLELT_TYPE_CUSTOM 0x03 //Legacy typedef struct __packed { uuid_t uuid; uint8_t data[]; } lcp_custom_element_t2; #define LCP_POLELT_TYPE_STM2 0x14 typedef struct __packed { uint16_t hash_alg; uint16_t num_hashes; lcp_hash_t2 hashes[]; } lcp_stm_element_t2; typedef struct __packed { uint16_t version; /* = 3.2 */ uint16_t hash_alg; /* one of LCP_POLHALG_* */ uint8_t policy_type; /* one of LCP_POLTYPE_* */ uint8_t sinit_min_version; uint16_t data_revocation_counters[LCP_MAX_LISTS]; uint32_t policy_control; uint8_t max_sinit_min_ver; /* Defined for PO only. Reserved for PS */ uint8_t max_biosac_min_ver; /* Defined for PO only. Reserved for PS - not used., should be zero */ uint16_t lcp_hash_alg_mask; /* Mask of approved algorithms for LCP evaluation */ uint32_t lcp_sign_alg_mask; /* Mask of approved signature algorithms for LCP evaluation */ uint16_t aux_hash_alg_mask; /* Approved algorithm for auto - promotion hash, reserved in 3.2 */ uint16_t reserved2; lcp_hash_t2 policy_hash; } lcp_policy_t2; typedef struct __packed { uint16_t revocation_counter; uint16_t pubkey_size; uint8_t pubkey_value[0]; uint8_t sig_block[]; } lcp_rsa_signature_t; typedef struct __packed { uint16_t revocation_counter; uint16_t pubkey_size; uint32_t reserved; uint8_t qx[0]; uint8_t qy[0]; uint8_t r[0]; uint8_t s[0]; } lcp_ecc_signature_t; typedef union __packed { lcp_rsa_signature_t rsa_signature; lcp_ecc_signature_t ecc_signature; } lcp_signature_t2; typedef struct __packed { uint16_t version; /* = 2.0 */ uint16_t sig_alg; uint32_t policy_elements_size; lcp_policy_element_t policy_elements[]; //#if (sig_alg != TPM_ALG_NULL) // lcp_signature_t sig; //#endif } lcp_policy_list_t2; /* LCP POLICY LIST 2.1 and its helper structs */ #define SIGNATURE_VERSION 0x10 #define MAX_RSA_KEY_SIZE 0x180 #define MIN_RSA_KEY_SIZE 0x100 #define MAX_ECC_KEY_SIZE 0x30 #define MIN_ECC_KEY_SIZE 0x20 typedef struct __packed { uint8_t Version; uint16_t KeySize; //IN BITS - 2048 or 3072! uint32_t Exponent; uint8_t Modulus[MAX_RSA_KEY_SIZE]; } rsa_public_key; typedef struct __packed { uint8_t Version; uint16_t KeySize; //IN BITS - 2048 or 3072! uint16_t HashAlg; uint8_t Signature[MAX_RSA_KEY_SIZE]; } rsa_signature; typedef struct __packed { uint8_t Version; uint16_t KeySize; //IN BITS - 256 or 384! uint8_t QxQy[2*MAX_ECC_KEY_SIZE]; } ecc_public_key; typedef struct __packed { uint8_t Version; uint16_t KeySize; //IN BITS - 256 or 384! uint16_t HashAlg; uint8_t sigRsigS[2*MAX_ECC_KEY_SIZE]; } ecc_signature; typedef struct __packed { uint8_t Version; uint16_t KeyAlg; ecc_public_key Key; uint16_t SigScheme; ecc_signature Signature; } ecc_key_and_signature; typedef struct __packed { uint8_t Version; uint16_t KeyAlg; rsa_public_key Key; uint16_t SigScheme; rsa_signature Signature; } rsa_key_and_signature; typedef union __packed { rsa_key_and_signature RsaKeyAndSignature; ecc_key_and_signature EccKeyAndSignature; } lcp_key_and_sig; typedef struct __packed { uint16_t RevocationCounter; lcp_key_and_sig KeyAndSignature; } lcp_signature_2_1; typedef struct __packed { uint16_t Version; uint16_t KeySignatureOffset; uint32_t PolicyElementsSize; lcp_policy_element_t PolicyElements[]; // signature will be added later // #if (KeySignatureOffset != 0) // lcp_signature_2_1 KeySignature; // #endif } lcp_policy_list_t2_1; typedef union __packed { lcp_policy_list_t tpm12_policy_list; lcp_policy_list_t2 tpm20_policy_list; lcp_policy_list_t2_1 tpm20_policy_list_2_1; } lcp_list_t; typedef struct __packed { char file_signature[32]; uint8_t reserved[3]; uint8_t num_lists; lcp_list_t policy_lists[]; } lcp_policy_data_t2; typedef union __packed { lcp_policy_t tpm12_policy; lcp_policy_t2 tpm20_policy; } lcp_policy_union; #endif /* __LCP_H__ */ tboot-1.10.5/include/lcp3_hlp.h0000644000000000000000000001352714210363175014365 0ustar 00000000000000/* * Copyright 2014 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __TXT_LCP2_HELPER_H__ #define __TXT_LCP2_HELPER_H__ static inline lcp_signature_t *get_tpm12_signature(const lcp_policy_list_t *pollist) { if ( pollist == NULL ) return NULL; if ( pollist->sig_alg != LCP_POLSALG_RSA_PKCS_15 ) return NULL; return (lcp_signature_t *)((const void *)&pollist->policy_elements + pollist->policy_elements_size); } static inline size_t get_tpm12_signature_size(const lcp_signature_t *sig) { if ( sig == NULL ) return 0; return offsetof(lcp_signature_t, pubkey_value) + 2*sig->pubkey_size; } static inline size_t get_tpm12_policy_list_size(const lcp_policy_list_t *pollist) { size_t size = 0; if ( pollist == NULL ) return 0; size = offsetof(lcp_policy_list_t, policy_elements) + pollist->policy_elements_size; /* add sig size */ if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) size += get_tpm12_signature_size(get_tpm12_signature(pollist)); return size; } static inline lcp_signature_t2 *get_tpm20_signature(const lcp_policy_list_t2 *pollist) { if ( pollist == NULL || pollist->sig_alg == TPM_ALG_NULL ) return NULL; return (lcp_signature_t2 *)((const void *)&pollist->policy_elements + pollist->policy_elements_size); } static inline lcp_signature_2_1 *get_tpm20_signature_2_1( const lcp_policy_list_t2_1 *pollist) { if (pollist == NULL || pollist->KeySignatureOffset == 0) return NULL; return (lcp_signature_2_1 *) ((const void *)&pollist->PolicyElements + pollist->PolicyElementsSize); } static inline size_t get_tpm20_signature_size(const lcp_signature_t2 *sig, const uint16_t sig_alg) { if ( sig == NULL ) return 0; if ( sig_alg == TPM_ALG_RSASSA) return offsetof(lcp_rsa_signature_t, pubkey_value) + 2*sig->rsa_signature.pubkey_size; else if ( sig_alg == TPM_ALG_ECDSA || sig_alg == TPM_ALG_SM2) return offsetof(lcp_ecc_signature_t, qx) + 4*sig->ecc_signature.pubkey_size; return 0; } static inline size_t get_tpm20_policy_list_size(const lcp_policy_list_t2 *pollist) { size_t size = 0; if ( pollist == NULL ) return 0; size = offsetof(lcp_policy_list_t2, policy_elements) + pollist->policy_elements_size; /* add sig size */ if ( pollist->sig_alg == TPM_ALG_RSASSA || pollist->sig_alg == TPM_ALG_ECDSA || pollist->sig_alg == TPM_ALG_SM2 ) size += get_tpm20_signature_size(get_tpm20_signature(pollist), pollist->sig_alg); return size; } static inline size_t get_raw_tpm20_sig_2_1_size(const lcp_key_and_sig *key_and_sig) { /* Calculate key and signature size treating it as a contigous buffer ( i.e. read from file). Will return physical size of signature and key, not size of lcp_key_and_sig structure. */ typedef struct __packed { uint8_t Version; uint16_t KeyAlg; uint8_t Version2; uint16_t KeySize; } sig_hdr; sig_hdr *this_hdr = NULL; if (key_and_sig == NULL) { return 0; } this_hdr = (sig_hdr *) key_and_sig; if (this_hdr->KeyAlg == TPM_ALG_RSA) { return sizeof(rsa_key_and_signature) - 2*(MAX_RSA_KEY_SIZE - (this_hdr->KeySize/8)); } else if (this_hdr->KeyAlg == TPM_ALG_ECC) { return sizeof(ecc_key_and_signature) - 4*(MAX_ECC_KEY_SIZE - (this_hdr->KeySize/8)); } else { return 0; } } static inline size_t get_raw_tpm20_list_2_1_size(const lcp_policy_list_t2_1 *pollist) { /* Calculate size of a list in a contiguous buffer (i.e. read from file). */ size_t size = 0; if (pollist == NULL) { return 0; } if (pollist->KeySignatureOffset != 0) { size = pollist->KeySignatureOffset + get_raw_tpm20_sig_2_1_size((const lcp_key_and_sig *) ((void *) pollist+pollist->KeySignatureOffset)); } else { size = offsetof(lcp_policy_list_t2_1, PolicyElements) + pollist->PolicyElementsSize; } return size; } #endif /* __TXT_LCP3_HELPER_H__ */ tboot-1.10.5/include/lcp_hlp.h0000644000000000000000000000504514210363175014276 0ustar 00000000000000/* * Copyright 2001 - 2010 Intel Corporation. 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef __TXT_LCP2_HELPER_H__ #define __TXT_LCP2_HELPER_H__ static inline lcp_signature_t *get_signature(const lcp_policy_list_t *pollist) { if ( pollist == NULL ) return NULL; if ( pollist->sig_alg != LCP_POLSALG_RSA_PKCS_15 ) return NULL; return (lcp_signature_t *)((const void *)&pollist->policy_elements + pollist->policy_elements_size); } static inline size_t get_signature_size(const lcp_signature_t *sig) { if ( sig == NULL ) return 0; return offsetof(lcp_signature_t, pubkey_value) + 2*sig->pubkey_size; } static inline size_t get_policy_list_size(const lcp_policy_list_t *pollist) { size_t size = 0; if ( pollist == NULL ) return 0; size = offsetof(lcp_policy_list_t, policy_elements) + pollist->policy_elements_size; /* add sig size */ if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) size += get_signature_size(get_signature(pollist)); return size; } #endif /* __TXT_LCP2_HELPER_H__ */ tboot-1.10.5/include/mle.h0000644000000000000000000000637614210363175013442 0ustar 00000000000000/* * mle.h: Intel(r) TXT MLE header definition * * Copyright (c) 2003-2008, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __MLE_H__ #define __MLE_H__ /* * SINIT/MLE capabilities */ typedef union { uint32_t _raw; struct { uint32_t rlp_wake_getsec : 1; uint32_t rlp_wake_monitor : 1; uint32_t ecx_pgtbl : 1; uint32_t stm : 1; uint32_t pcr_map_no_legacy : 1; uint32_t pcr_map_da : 1; uint32_t platform_type : 2; uint32_t max_phy_addr : 1; uint32_t tcg_event_log_format: 1; uint32_t cbnt_supported : 1; uint32_t reserved1 : 21; }; } txt_caps_t; /* * MLE header structure * describes an MLE for SINIT and OS/loader SW */ typedef struct { uuid_t uuid; uint32_t length; uint32_t version; uint32_t entry_point; uint32_t first_valid_page; uint32_t mle_start_off; uint32_t mle_end_off; txt_caps_t capabilities; uint32_t cmdline_start_off; uint32_t cmdline_end_off; } mle_hdr_t; #define MLE_HDR_UUID {0x9082ac5a, 0x476f, 0x74a7, 0x5c0f, \ {0x55, 0xa2, 0xcb, 0x51, 0xb6, 0x42}} /* * values supported by current version of tboot */ #define MLE_HDR_VER 0x00020001 /* 2.1 */ #define MLE_HDR_CAPS 0x000000627 /* rlp_wake_{getsec, monitor} = 1, ecx_pgtbl = 1, nolg = 0, da = 1 tcg_event_log_format = 1, cbnt_supported = 1 */ #endif /* __MLE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/tb_error.h0000644000000000000000000000744414210363175014500 0ustar 00000000000000/* * tb_error.h: error code definitions * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TB_ERROR_H__ #define __TB_ERROR_H__ typedef enum { TB_ERR_NONE = 0, /* succeed */ TB_ERR_FIXED = 1, /* previous error has been fixed */ TB_ERR_GENERIC, /* non-fatal generic error */ TB_ERR_TPM_NOT_READY, /* tpm not ready */ TB_ERR_SMX_NOT_SUPPORTED, /* smx not supported */ TB_ERR_VMX_NOT_SUPPORTED, /* vmx not supported */ TB_ERR_VTD_NOT_SUPPORTED, /* Vt-D not enabled in BIOS */ TB_ERR_TXT_NOT_SUPPORTED, /* txt not supported */ TB_ERR_MODULE_VERIFICATION_FAILED, /* module failed to verify against policy */ TB_ERR_MODULES_NOT_IN_POLICY, /* modules in mbi but not in policy */ TB_ERR_POLICY_INVALID, /* policy is invalid */ TB_ERR_POLICY_NOT_PRESENT, /* no policy in TPM NV */ TB_ERR_SINIT_NOT_PRESENT, /* SINIT ACM not provided */ TB_ERR_ACMOD_VERIFY_FAILED, /* verifying AC module failed */ TB_ERR_POST_LAUNCH_VERIFICATION, /* verification of post-launch failed */ TB_ERR_S3_INTEGRITY, /* creation or verification of S3 integrity measurements failed */ TB_ERR_FATAL, /* generic fatal error */ TB_ERR_NV_VERIFICATION_FAILED, /* NV failed to verify against policy */ TB_ERR_PREV_TXT_ERROR, /* previous measured launch failed */ TB_ERR_MAX } tb_error_t; extern void print_tb_error_msg(tb_error_t error); extern bool read_tb_error_code(tb_error_t *error); extern bool write_tb_error_code(tb_error_t error); extern bool was_last_boot_error(void); #endif /* __TB_ERROR_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/tb_policy.h0000644000000000000000000003116014210363175014636 0ustar 00000000000000/* * tb_policy.h: data structures, definitions, and helper fns for tboot * verified launch policies * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TB_POLICY_H__ #define __TB_POLICY_H__ /* * policy types */ enum { TB_POLTYPE_CONT_NON_FATAL, /* ignore all non-fatal errors and */ /* continue */ TB_POLTYPE_CONT_VERIFY_FAIL, /* ignore verification errors and */ /* halt otherwise */ TB_POLTYPE_HALT, /* halt on any errors */ TB_POLTYPE_MAX }; /* * policy hash types */ enum { TB_HTYPE_ANY, TB_HTYPE_IMAGE, }; #define TB_POL_MAX_MOD_NUM 127 /* largest supported module number */ #define TB_POL_MOD_NUM_ANY 129 /* matches any module number */ /* (should be last entry of modules) */ #define TB_POL_MOD_NUM_NV 130 /* indicate this is a nv index entry */ #define TB_POL_MOD_NUM_NV_RAW 131 /* a nv entry verified by raw content */ #define TB_POL_MAX_PCR 23 /* largest supported PCR number */ #define TB_POL_PCR_NONE 255 /* don't extend measurement into a PCR */ /* * policies */ typedef struct __packed { uint8_t mod_num; /* 0-based or TB_POL_MOD_NUM_* */ uint8_t pcr; /* PCR number (0-23) or TB_POL_PCR_* */ uint8_t hash_type; /* TB_HTYPE_* */ uint32_t nv_index; /* nv index to be measured, effective when */ /* mod_num==TB_POL_MOD_NUM_{NV | NV_RAW} */ /* mod_num: */ /* TB_POL_MOD_NUM_NV_RAW: */ /* check index size==hash size, */ /* no hashing before verify and extend */ /* TB_POL_MOD_NUM_NV: */ /* hashing before verify and extend */ uint8_t num_hashes; tb_hash_t hashes[]; } tb_policy_entry_t; #define TB_POLCTL_EXTEND_PCR17 0x1 /* extend policy into PCR 17 */ typedef struct __packed { uint8_t version; /* currently 2 */ uint8_t policy_type; /* TB_POLTYPE_* */ /* TODO should be changed to 16bit for TPM 2.0 */ uint8_t hash_alg; /* TB_HALG_* */ uint32_t policy_control; /* bitwise OR of TB_POLCTL_* */ uint32_t reserved; uint8_t num_entries; tb_policy_entry_t entries[]; } tb_policy_t; /* * TPM NV index for VL policy */ /* max size of policy in TPM NV (assumes 8 entries w/ 4 hashes each) */ #define MAX_TB_POLICY_SIZE \ sizeof(tb_policy_t) + 8*(sizeof(tb_policy_entry_t) + 4*sizeof(tb_hash_t)) #define TB_POLICY_INDEX 0x20000001 /* policy index for Verified Launch */ /* * helper fns */ #ifndef PRINT #define PRINT(...) {} #endif static inline const char *hash_type_to_string(uint8_t hash_type) { if ( hash_type == TB_HTYPE_ANY ) return "TB_HTYPE_ANY"; else if ( hash_type == TB_HTYPE_IMAGE ) return "TB_HTYPE_IMAGE"; else return "unsupported"; } static inline const char *policy_type_to_string(uint8_t policy_type) { if ( policy_type == TB_POLTYPE_CONT_NON_FATAL ) return "TB_POLTYPE_CONT_NON_FATAL"; else if ( policy_type == TB_POLTYPE_CONT_VERIFY_FAIL ) return "TB_POLTYPE_CONT_VERIFY_FAIL"; else if ( policy_type == TB_POLTYPE_HALT ) return "TB_POLTYPE_HALT"; else return "unsupported"; } static inline const char *policy_control_to_string(uint32_t policy_control) { if ( policy_control & TB_POLCTL_EXTEND_PCR17 ) return "EXTEND_PCR17"; else return ""; } static inline size_t calc_policy_entry_size(const tb_policy_entry_t *pol_entry, uint16_t hash_alg) { if ( pol_entry == NULL ) return 0; size_t size = sizeof(*pol_entry); /* tb_policy_entry_t has empty hash array, which isn't counted in size */ /* so add size of each hash */ size += pol_entry->num_hashes * get_hash_size(hash_alg); return size; } static inline size_t calc_policy_size(const tb_policy_t *policy) { size_t size = sizeof(*policy); /* tb_policy_t has empty array, which isn't counted in size */ /* so add size of each policy */ const tb_policy_entry_t *pol_entry = policy->entries; for ( int i = 0; i < policy->num_entries; i++ ) { size_t entry_size = calc_policy_entry_size(pol_entry, policy->hash_alg); pol_entry = (void *)pol_entry + entry_size; size += entry_size; } return size; } static inline tb_hash_t *get_policy_entry_hash( const tb_policy_entry_t *pol_entry, uint16_t hash_alg, int i) { /* assumes policy has already been validated */ if ( pol_entry == NULL ) { PRINT(TBOOT_ERR"Error: pol_entry pointer is NULL\n"); return NULL; } if ( i < 0 || i >= pol_entry->num_hashes ) { PRINT(TBOOT_ERR"Error: position is not correct.\n"); return NULL; } return (tb_hash_t *)((void *)pol_entry->hashes + i * get_hash_size(hash_alg)); } static inline tb_policy_entry_t* get_policy_entry(const tb_policy_t *policy, int i) { /* assumes policy has already been validated */ if ( policy == NULL ) { PRINT(TBOOT_ERR"Error: policy pointer is NULL\n"); return NULL; } if ( i < 0 || i >= policy->num_entries ) { PRINT(TBOOT_ERR"Error: position is not correct.\n"); return NULL; } tb_policy_entry_t *pol_entry = (tb_policy_entry_t *)policy->entries; for ( int j = 0; j < i; j++ ) { pol_entry = (void *)pol_entry + calc_policy_entry_size(pol_entry, policy->hash_alg); } return pol_entry; } static inline tb_policy_entry_t* find_policy_entry(const tb_policy_t *policy, uint8_t mod_num) { /* assumes policy has already been validated */ if ( policy == NULL ) { PRINT(TBOOT_ERR"Error: policy pointer is NULL\n"); return NULL; } for ( int i = 0; i < policy->num_entries; i++ ) { tb_policy_entry_t *pol_entry = get_policy_entry(policy, i); if ( pol_entry == NULL ) return NULL; if ( pol_entry->mod_num == mod_num || pol_entry->mod_num == TB_POL_MOD_NUM_ANY ) return pol_entry; } return NULL; } /* * verify and display policy */ static inline bool verify_policy(const tb_policy_t *policy, size_t size, bool print) { if ( print ) PRINT(TBOOT_DETA"policy:\n"); if ( policy == NULL ) { if ( print ) PRINT(TBOOT_ERR"policy pointer is NULL\n"); return false; } if ( size < sizeof(tb_policy_t) ) { if ( print ) PRINT(TBOOT_ERR"size of policy is too small (%lu)\n", (unsigned long)size); return false; } if ( policy->version != 0x02 ) { if ( print ) PRINT(TBOOT_ERR"unsupported version (%u)\n", policy->version); return false; } if ( print ) PRINT(TBOOT_DETA"\t version: %u\n", policy->version); if ( print ) PRINT(TBOOT_DETA"\t policy_type: %s\n", policy_type_to_string(policy->policy_type)); if ( policy->policy_type >= TB_POLTYPE_MAX ) return false; if ( print ) PRINT(TBOOT_DETA"\t hash_alg: %s\n", hash_alg_to_string(policy->hash_alg)); if ( print ) PRINT(TBOOT_DETA"\t policy_control: %08x (%s)\n", policy->policy_control, policy_control_to_string(policy->policy_control)); if ( print ) PRINT(TBOOT_DETA"\t num_entries: %u\n", policy->num_entries); const tb_policy_entry_t *pol_entry = policy->entries; for ( int i = 0; i < policy->num_entries; i++ ) { /* check header of policy entry */ if ( ((void *)pol_entry - (void *)policy + sizeof(*pol_entry)) > size ) { if ( print ) PRINT(TBOOT_ERR"size of policy entry is too small (%lu)\n", (unsigned long)size); return false; } if ( print ) PRINT(TBOOT_DETA"\t policy entry[%d]:\n", i); if ( pol_entry->mod_num > TB_POL_MAX_MOD_NUM && pol_entry->mod_num != TB_POL_MOD_NUM_ANY && pol_entry->mod_num != TB_POL_MOD_NUM_NV && pol_entry->mod_num != TB_POL_MOD_NUM_NV_RAW ) { if ( print ) PRINT(TBOOT_ERR"mod_num invalid (%u)\n", pol_entry->mod_num); return false; } if ( print ) PRINT(TBOOT_DETA"\t\t mod_num: "); if ( pol_entry->mod_num == TB_POL_MOD_NUM_ANY ) { if ( print ) PRINT(TBOOT_DETA"any\n"); } else if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV ) { if ( print ) PRINT(TBOOT_DETA"nv\n" "\t\t nv_index: %08x\n", pol_entry->nv_index); } else if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) { if ( print ) PRINT(TBOOT_DETA"nv_raw\n" "\t\t nv_index: %08x\n", pol_entry->nv_index); } else if ( print ) PRINT(TBOOT_DETA"%u\n", pol_entry->mod_num); if ( pol_entry->pcr > TB_POL_MAX_PCR && pol_entry->pcr != TB_POL_PCR_NONE ) { if ( print ) PRINT(TBOOT_ERR"pcr invalid (%u)\n", pol_entry->pcr); return false; } if ( print ) PRINT(TBOOT_DETA"\t\t pcr: "); if ( pol_entry->pcr == TB_POL_PCR_NONE ) { if ( print ) PRINT(TBOOT_DETA"none\n"); } else if ( print ) PRINT(TBOOT_DETA"%u\n", pol_entry->pcr); if ( print ) PRINT(TBOOT_DETA"\t\t hash_type: %s\n", hash_type_to_string(pol_entry->hash_type)); if ( pol_entry->hash_type > TB_HTYPE_IMAGE ) return false; if ( print ) PRINT(TBOOT_DETA"\t\t num_hashes: %u\n", pol_entry->num_hashes); /* check all of policy */ if ( ((void *)pol_entry - (void *)policy + sizeof(*pol_entry) + pol_entry->num_hashes * get_hash_size(policy->hash_alg)) > size ) { if ( print ) PRINT(TBOOT_ERR"size of policy entry is too small (%lu)\n", (unsigned long)size); return false; } for ( int j = 0; j < pol_entry->num_hashes; j++ ) { if ( print ) { PRINT(TBOOT_DETA"\t\t hashes[%d]: ", j); print_hash(get_policy_entry_hash(pol_entry, policy->hash_alg, j), policy->hash_alg); } } pol_entry = (void *)pol_entry + calc_policy_entry_size(pol_entry, policy->hash_alg); } return true; } #endif /* __TB_POLICY_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/tboot.h0000644000000000000000000001333714210363175014007 0ustar 00000000000000/* * tboot.h: shared data structure with MLE and kernel and functions * used by kernel for runtime support * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TBOOT_H__ #define __TBOOT_H__ #ifndef __packed #define __packed __attribute__ ((packed)) #endif /* define uuid_t here in case uuid.h wasn't pre-included */ /* (i.e. so tboot.h can be self-sufficient) */ #ifndef __UUID_H__ typedef struct __packed { uint32_t data1; uint16_t data2; uint16_t data3; uint16_t data4; uint8_t data5[6]; } uuid_t; #endif /* * used to communicate between tboot and the launched kernel (i.e. Xen) */ #define TB_KEY_SIZE 64 /* 512 bits */ #define MAX_TB_MAC_REGIONS 32 typedef struct __packed { uint64_t start; /* must be 4k byte -aligned */ uint32_t size; /* must be 4k byte -granular */ } tboot_mac_region_t; /* GAS - Generic Address Structure (ACPI 2.0+) */ typedef struct __packed { uint8_t space_id; /* only 0,1 (memory, I/O) are supported */ uint8_t bit_width; uint8_t bit_offset; uint8_t access_width; /* only 1-3 (byte, word, dword) are supported */ uint64_t address; } tboot_acpi_generic_address_t; typedef struct __packed { tboot_acpi_generic_address_t pm1a_cnt_blk; tboot_acpi_generic_address_t pm1b_cnt_blk; tboot_acpi_generic_address_t pm1a_evt_blk; tboot_acpi_generic_address_t pm1b_evt_blk; uint16_t pm1a_cnt_val; uint16_t pm1b_cnt_val; uint64_t wakeup_vector; uint32_t vector_width; uint64_t kernel_s3_resume_vector; } tboot_acpi_sleep_info_t; typedef struct __packed { /* version 3+ fields: */ uuid_t uuid; /* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */ uint32_t version; /* currently 0.6 */ uint32_t log_addr; /* physical addr of log or NULL if none */ uint32_t shutdown_entry; /* entry point for tboot shutdown */ uint32_t shutdown_type; /* type of shutdown (TB_SHUTDOWN_*) */ tboot_acpi_sleep_info_t acpi_sinfo; /* where kernel put acpi sleep info in Sx */ uint32_t tboot_base; /* starting addr for tboot */ uint32_t tboot_size; /* size of tboot */ uint8_t num_mac_regions; /* number mem regions to MAC on S3 */ /* contig regions memory to MAC on S3 */ tboot_mac_region_t mac_regions[MAX_TB_MAC_REGIONS]; /* version 4+ fields: */ /* populated by tboot; will be encrypted */ uint8_t s3_key[TB_KEY_SIZE]; /* version 5+ fields: */ uint8_t reserved_align[3]; /* used to 4byte-align num_in_wfs */ uint32_t num_in_wfs; /* number of processors in wait-for-SIPI */ /* version 6+ fields: */ uint32_t flags; uint64_t ap_wake_addr; /* phys addr of kernel/VMM SIPI vector */ uint32_t ap_wake_trigger; /* kernel/VMM writes APIC ID to wake AP */ } tboot_shared_t; #define TB_SHUTDOWN_REBOOT 0 #define TB_SHUTDOWN_S5 1 #define TB_SHUTDOWN_S4 2 #define TB_SHUTDOWN_S3 3 #define TB_SHUTDOWN_HALT 4 #define TB_SHUTDOWN_WFS 5 #define TB_FLAG_AP_WAKE_SUPPORT 0x00000001 /* kernel/VMM use INIT-SIPI-SIPI if clear, ap_wake_* if set */ /* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */ #define TBOOT_SHARED_UUID {0x663c8dff, 0xe8b3, 0x4b82, 0xaabf, \ {0x19, 0xea, 0x4d, 0x5, 0x7a, 0x8 }} /* * used to log tboot printk output */ #define ZIP_COUNT_MAX 10 typedef struct { uuid_t uuid; uint16_t max_size; uint16_t curr_pos; uint16_t zip_pos[ZIP_COUNT_MAX]; uint16_t zip_size[ZIP_COUNT_MAX]; uint8_t zip_count; char buf[]; } tboot_log_t; /* {C0192526-6B30-4db4-844C-A3E953B88174} */ #define TBOOT_LOG_UUID {0xc0192526, 0x6b30, 0x4db4, 0x844c, \ {0xa3, 0xe9, 0x53, 0xb8, 0x81, 0x74 }} extern tboot_shared_t *g_tboot_shared; static inline bool tboot_in_measured_env(void) { return (g_tboot_shared != NULL); } #endif /* __TBOOT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/include/uuid.h0000644000000000000000000000604614210363175013625 0ustar 00000000000000/* * uuid.h: support functions for UUIDs * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __UUID_H__ #define __UUID_H__ typedef struct __packed { uint32_t data1; uint16_t data2; uint16_t data3; uint16_t data4; uint8_t data5[6]; } uuid_t; static inline bool are_uuids_equal(const uuid_t *uuid1, const uuid_t *uuid2) { return (uuid1->data1 == uuid2->data1 && uuid1->data2 == uuid2->data2 && uuid1->data3 == uuid2->data3 && uuid1->data4 == uuid2->data4 && uuid1->data5[0] == uuid2->data5[0] && uuid1->data5[1] == uuid2->data5[1] && uuid1->data5[2] == uuid2->data5[2] && uuid1->data5[3] == uuid2->data5[3] && uuid1->data5[4] == uuid2->data5[4] && uuid1->data5[5] == uuid2->data5[5] ); } #ifndef PRINT #define PRINT printk #endif #ifndef TBOOT_DETA #define TBOOT_DETA "<4>" #endif static inline void print_uuid(const uuid_t *uuid) { PRINT(TBOOT_DETA"{0x%08x, 0x%04x, 0x%04x, 0x%04x,\n" "\t\t{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}", uuid->data1, (uint32_t)uuid->data2, (uint32_t)uuid->data3, (uint32_t)uuid->data4, (uint32_t)uuid->data5[0], (uint32_t)uuid->data5[1], (uint32_t)uuid->data5[2], (uint32_t)uuid->data5[3], (uint32_t)uuid->data5[4], (uint32_t)uuid->data5[5]); } #endif /* __UUID_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcp-gen2/ElementBase.py0000644000000000000000000000326714210363175015232 0ustar 00000000000000 from struct import * from array import * from defines import DEFINES class ElementBase(object): #MleDataSha1HashFormatString = "<20B" #MleDataSha256HashFormatString = "<32B" #MleDataSha384HashFormatString = "<48B" #MleDataSha512HashFormatString = "<64B" def __init__(self): pass # alg is a string that specifies hash algorithm # hash is the array of bytes of the hash value # def packHash(self, alg, hash): #hashFormatString = "<" + str(DEFINES.DIGEST_SIZE[alg]) + "B" # Build the pack format string for different hash algorithms #hashData = pack(hashFormatString, array('B', hash)) #print "DEBUG: hash format string = "+ HashFormatString # Check hash size vs. expected size for specified algorithm hashData = None if (DEFINES.DIGEST_SIZE[alg] == len(hash)): b = bytes() hashData = b.join(pack('B', val) for val in hash) else: print ("ERROR: Hash buffer size %d does not match required size for %s" %(len(hash), alg)) return hashData if __name__ == "__main__": sha1data = [val for val in range(DEFINES.DIGEST_SIZE['SHA1'])] sha256data = [val for val in range(DEFINES.DIGEST_SIZE['SHA256'])] e = ElementBase(); packedHash = pack("<20B", sha1data[0], sha1data[1], sha1data[2], sha1data[3], sha1data[4], sha1data[5], sha1data[6], sha1data[7], sha1data[8], sha1data[9], sha1data[10], sha1data[11], sha1data[12], sha1data[13], sha1data[14], sha1data[15], sha1data[16], sha1data[17], sha1data[18], sha1data[19]) joinedHash = e.packHash('SHA256', sha1data) if (packedHash == joinedHash): print "SUCCESS" else: print "FAILED" print packedHash print joinedHash tboot-1.10.5/lcp-gen2/ElementGui.py0000644000000000000000000001064714210363175015104 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" import os import shutil from defines import DEFINES # # TXT Policy Generator Tool # class ElementGui( object ): CONST_TITLE = "Choose file" CONST_WILDCARD = "All Files (*.*)|*.*" def __init__( self ): pass # isElementType() compares the name argument to the class name and stored hash algorithm name # to find a matching element. # The name argument should have a format of - def isElementType(self, name): result = False type = name.split('-') if len(type) != 2: result = False else: elementType, hashAlg = type if hashAlg == 'LEGACY': if elementType in self.__class__.__name__: result = True else: if elementType in self.__class__.__name__ and self.myHashAlg == DEFINES.TPM_ALG_HASH[hashAlg]: result = True return result def getHashAlgName(self): if 'Legacy' in self.__class__.__name__: name = 'SHA1-LEGACY' else: try: name = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == self.myHashAlg)).next() except StopIteration: name = None return name # getName() is intended to get the class name from the classes defined in pdef.py # #def getName(self): # if 'Legacy' in self.__class__.__name__: # hashname = 'LEGACY' # name = self.__class__.__name__.split('Legacy')[0] + '-' + hashname # else: # try: # hashname = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == self.myHashAlg)).next() # name = self.__class__.__name__.split('_DEF')[0] + '-' + hashname # except StopIteration: # name = None # return name def selectFile(self): """onAddButtonClick - This code is common to all elements to select a file and copy file into current working directory if the file doesn't exist """ filepath = '' filename = '' workdir = self.pdef.WorkingDirectory dlg = wx.FileDialog(self.parent, self.CONST_TITLE, workdir, "", self.CONST_WILDCARD, wx.FD_OPEN) if dlg.ShowModal() == wx.ID_CANCEL : self.StatusBar.SetStatusText( "Add cancelled" ) else: filename = dlg.GetFilename() filepath = dlg.GetDirectory() dlg.Destroy() # return null string indicate file select cancelled. return filepath, filename def copyFile(self, filepath, filename): workdir = self.pdef.WorkingDirectory if (filepath != workdir): if (os.path.exists(os.path.join(workdir, filename))) : dlg = wx.MessageDialog(self.parent, filename+" already exists in working directory\nOverwrite file in working directory?", "Confirm Copy", wx.OK|wx.CANCEL|wx.ICON_QUESTION) if (dlg.ShowModal() == wx.ID_OK): shutil.copyfile(os.path.join(filepath, filename), os.path.join(workdir, filename)) self.StatusBar.SetStatusText( "File copied" ) else: self.StatusBar.SetStatusText( "File copy aborted" ) dlg.Destroy() else: shutil.copyfile(os.path.join(filepath, filename), os.path.join(workdir, filename)) def setListModified(self): """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" currentList = self.pdef.getCurrentListObject() #print("PCONF setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG if(currentList.ListModified == False): currentList.RevocationCounter += 1 self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI currentList.ListModified = True self.pdef.Modified = True def showV20Gui(self, enable): if enable: self.overridePsPolicy.Show() else: self.overridePsPolicy.Hide() def enableDisableOverridePsPolicy(self, value): """enableDisableOverridePsPolicy widget""" self.overridePsPolicy.Enable(value) tboot-1.10.5/lcp-gen2/LcpPolicy.py0000644000000000000000000010555114210363175014743 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # TXT Policy Generator Tool # LcpPolicy and LcpPolicyData Classes - LCP_POLICY and LCP_POLICY_DATA File Structure # from defines import DEFINES from ElementBase import * class LCP_POLICY2( object ): """ LCP_POLICY2 Class""" # # LCP_POLICY2 struct # def __init__( self ): """__init__() - LCP_POLICY2 class constructor""" #self.Version # UINT16 - from pdef.PolVersion = 0x0300 self.VersionMajor = 03 # UINT8 self.VersionMinor = 00 # UINT8 self.HashAlg = 00 # UINT16 - TPM_ALG_* from pdef.HashAlg self.PolicyType = 00 # UINT8 - 0=LIST, 1=ANY - from pdef.PolicyType self.SINITMinVersion = 00 # UINT8 - from pdef.SinitMinVersion self.DataRevocationCounters = [0,0,0,0,0,0,0,0] # UINT16 DataRevocationCounters[MAX_LISTS] Default is 0's # from pdef.DataRevocationCounters[] self.PolicyControl = 0 # UINT32 Encoding of (NPW, PCR17, Force PO), from pdef.PolicyControl self.MaxSinitMinVer = 0 # UINT8 PO only, reserved for PS self.MaxBiosAcMinVer = 0 # UINT8 PO only, reserved for PS self.LcpHashAlgMask = 0 # UINT16 HashMask for LCP eval. self.LcpSignAlgMask = 0 self.AuxHashAlgMask = 0 # UINT16 Hash Mask for Auto-Promotion # Reserved # UINT16 self.PolicyHash = [] # Doesn't really need to use 2 variable for each hash size for python #self.PolicyHashSha1 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] # LCP_HASH #self.PolicyHashSha256 = [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] # # The raw [ie binary] format LCP_POLICY.pol file is generated using struct.pack # based on the format string below. # # 'struct' module format string for a LCP_POLICY Structure # where: B = UINT8, H = UINT16, L = UINT32 # '<' means Little Endian, std size, no alignment between fields #self.LcpPolicyFormatString = "pcr_selection.size_of_select = 3; # // TPM structures are big-endian, so byte-swap # bswap16(&pcr_info->pcr_selection.size_of_select); # # So do likewise elementData += pack( self.PconfDataSha1PcrInfoFormatString, thisPcrInfo.pcrSelection.sizeOfSelect, thisPcrInfo.pcrSelection.pcrSelect[0], thisPcrInfo.pcrSelection.pcrSelect[1], thisPcrInfo.pcrSelection.pcrSelect[2], thisPcrInfo.localityAtRelease) # thisPcrInfo.digestAtRelease is the binary string produced by hash.digest() # struct.pack() requires ints, not strings. # But don't need to pack it, just output it directly elementData += thisPcrInfo.digestAtRelease i += 1 return( elementData ) # #define TPM_LOCALITY_SELECTION BYTE # # typedef struct tdTPM_PCR_INFO_SHORT{ # TPM_PCR_SELECTION pcrSelection; # UINT8 localityAtRelease; //0x1F # TPM_COMPOSITE_HASH digestAtRelease; # } TPM_PCR_INFO_SHORT; class TPM_PCR_INFO_SHORT( object ): """TPM_PCR_INFO_SHORT class""" def __init__(self): """__init__() - TPM_PCR_INFO_SHORT class constructor""" self.pcrSelection = TPM_PCR_SELECTION() # TPM_PCR_SELECTION self.localityAtRelease = 0x1f # UINT8 self.digestAtRelease = [] # # typedef struct tdTPM_PCR_SELECTION { # UINT16 sizeOfSelect; // shall be 0x0003 # [size_is(sizeOfSelect)] BYTE pcrSelect[]; # } TPM_PCR_SELECTION; # class TPM_PCR_SELECTION( object ): """TPM_PCR_SELECTION class""" def __init__(self): """__init__() - TPM_PCR_SELECTION class constructor""" self.sizeOfSelect = 0x0003 # UINT16 self.pcrSelect = [0, 0, 0] # [size_is(sizeOfSelect)] BYTE pcrSelect[] # typedef struct tdTPM_DIGEST{ # BYTE digest[digestSize]; // digestSize = 20 bytes for SHA1 # } TPM_DIGEST; # # typedef TPM_DIGEST TPM_COMPOSITE_HASH; // hash of multiple measurements # class TPM_DIGEST( object ): """TPM_DIGEST class""" def __init__(self): """__init__() - TPM_DIGEST class constructor""" self.digest = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0] # BYTE digest[digestSize] MAX_HASH = 20 for SHA1 # typedef struct { # UINT32 ElementSize; # UINT32 ElementType; // Type = 2 = LCP_POLELT_TYPE_SBIOS # UINT32 PolEltControl; # UINT8 HashAlg; // one of LCP_POLHALG_* # UINT8 Reserved1[3]; // 0, 0, 0 # LCP_HASH FallbackHash; # UINT16 Reserved2; // 0x0000 # UINT16 NumHashes; # LCP_HASH Hashes[NumHashes]; # } LCP_SBIOS_ELEMENT # class LCP_SBIOS_ELEMENT( ElementBase ): """LCP_SBIOS_ELEMENT class""" def __init__(self): """__init__() - LCP_SBIOS_ELEMENT class constructor""" self.ElementSize = 0 # UINT32 - header self.ElementType = DEFINES.LCP_POLELT_TYPE_SBIOS # UINT32 - header self.PolEltControl = 0 # UINT32 - header self.HashAlg = 0 # UINT8 #self.Reserved1[3] # UINT8 0, 0, 0 self.FallbackHash = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] # LCP_HASH #self.Reserved2 # UINT16 0x0000 self.NumHashes = 0 # UINT16 self.Hashes = [] # LCP_HASH Hashes[NumHashes] # 'struct' module format string for a LCP_SBIOS_ELEMENT Structure # where: B = UINT8, H = UINT16, L = UINT32 c = char # '<' means Little Endian, std size, no alignment between fields #self.SbiosDataFormatString = " 3): if(sys.argv[3] == '-build'): print("Starting %s ..." % (msg)) self.batchBuild() print("%s complete" % (msg)) sys.exit() # exit if batch build succeeded else: status = False else: status = False if(status == False): error = " failed. Expected a '-build' option" print("%s %s" % (msg, error)) sys.exit() # exit else: error = " failed. Invalid pdef file." print("%s %s" % (msg, error)) sys.exit() # exit elif(sys.argv[1] == '-hash'): if(len(sys.argv) < 5): # invalid -hash syntax print("%s" % (hashImageSyntax)) else: tools.hashImage(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) sys.exit() # exit else: print("%s" % (hashImageSyntax)) sys.exit() else: # invalid CLI syntax, using GUI, print syntax help help = "\n'TxtPolGen2' - invoke GUI\n'TxtPolGen2 -open File.pdef -build' - performs a batch build of File.pdef\n" print("%s%s" % (help, hashImageSyntax)) sys.exit() # verify the .pdef file to be opened for a batch build def verifyPdefFile(self): """verifyPdefFile - verify the file in argv[2] exists and has a .pdef extention""" if(len(sys.argv) > 2): # chk for a .pdef ext base, ext, = filename.rsplit('.', 1) if(ext == "pdef"): # chk the file exists by opening it try: f = open(os.path.join(dirname, filename), 'r') except: print("Error opening file %s" % (filename)) return(False) # open failed so nothing to close f.close() else: return False # invalid extention return True # ok # # Create the menu bar with file & help menus. # def createMenuBar( self ): """createMenuBar - create the Menu Bar""" FileMenu = wx.Menu() HelpMenu = wx.Menu() BuildMenu = wx.Menu() ToolMenu = wx.Menu() FileMenuNew = FileMenu.Append(wx.ID_NEW, "&New", " Create a new Policy") FileMenuOpen = FileMenu.Append(wx.ID_OPEN, "&Open", " Open a saved PDEF file") FileMenuSave = FileMenu.Append(wx.ID_SAVE, "&Save", " Save Policy to a PDEF file") FileMenuSaveAs= FileMenu.Append(wx.ID_SAVEAS, "&Save As", " Save Policy to a PDEF file") FileMenuPrint = FileMenu.Append(wx.ID_PRINT, "&Print", " Save Policy to a printable text file") FileMenuClose = FileMenu.Append(wx.ID_EXIT, "&Close", " Close the Policy and exit") # Creating the menubar. MenuBar = wx.MenuBar() MenuBar.Append(FileMenu, "&File") # Adding the "FileMenu" to the MenuBar BuildMenuBuildNvPolicy = BuildMenu.Append(wx.ID_ANY, "&Build just NV Policy File", "Build only the NV Policy") BuildMenuBuildPolicyDataStruct = BuildMenu.Append(wx.ID_ANY, "&Build just Policy Data File", "Build only the Policy Data Struct") BuildMenuBuildBoth = BuildMenu.Append(wx.ID_ANY, "&Build Policy (both files)", "Build the full Policy") MenuBar.Append(BuildMenu, "&Build") #ToolMenuHashFile = ToolMenu.Append(wx.ID_ANY, "&Hash a file", "Create a hash from the specified file") #ToolMenuInsertPolicy = ToolMenu.Append(wx.ID_ANY, "&Insert policy", "Insert a policy into an image per its FIT7 record") #MenuBar.Append(ToolMenu, "&Tools") # Adding the "ToolMenu" to the MenuBar HelpMenuToolInfo = HelpMenu.Append(wx.ID_ABOUT, "&Tool Info", " Display information about this tool") HelpMenuLicense = HelpMenu.Append(wx.ID_ANY, "&License", " Display the license") HelpMenuKeyGen = HelpMenu.Append(wx.ID_ANY, "&Key Generation", " How to generatekeys with OpenSSL") HelpMenuBatch = HelpMenu.Append(wx.ID_ANY, "Batch Build Help", "Build from the command line") HelpMenuHash = HelpMenu.Append(wx.ID_ANY, "Hash Image Help", "Hash an image from the command line") HelpMenuGuide = HelpMenu.Append(wx.ID_ANY, "&Guide", " Open the User Guide") HelpMenuTutorial = HelpMenu.Append(wx.ID_ANY, "&Tutorial", " Open the Tutorial") MenuBar.Append(HelpMenu, "&Help") # Adding the "HelpMenu" to the MenuBar self.SetMenuBar(MenuBar) # Adding the MenuBar to the Frame content. # # Menu events # self.Bind(wx.EVT_MENU, self.onNew, FileMenuNew) self.Bind(wx.EVT_MENU, self.onOpen, FileMenuOpen) self.Bind(wx.EVT_MENU, self.onSave, FileMenuSave) self.Bind(wx.EVT_MENU, self.onSaveAs, FileMenuSaveAs) self.Bind(wx.EVT_MENU, self.onPrint, FileMenuPrint) self.Bind(wx.EVT_MENU, self.onExit, FileMenuClose) self.Bind(wx.EVT_MENU, self.onAbout, HelpMenuToolInfo) self.Bind(wx.EVT_MENU, self.onLicense, HelpMenuLicense) self.Bind(wx.EVT_MENU, self.onKeyGen, HelpMenuKeyGen) self.Bind(wx.EVT_MENU, self.batchBuildHelp, HelpMenuBatch) self.Bind(wx.EVT_MENU, self.hashImageHelp, HelpMenuHash) self.Bind(wx.EVT_MENU, self.onGuide, HelpMenuGuide) self.Bind(wx.EVT_MENU, self.onTutorial, HelpMenuTutorial) self.Bind(wx.EVT_MENU, self.onBuildButtonClick, BuildMenuBuildBoth) self.Bind(wx.EVT_MENU, self.onBuildNvPolicy, BuildMenuBuildNvPolicy) self.Bind(wx.EVT_MENU, self.onBuildPolicyDataStruct, BuildMenuBuildPolicyDataStruct) #self.Bind(wx.EVT_MENU, self.onHashFile, ToolMenuHashFile) #self.Bind(wx.EVT_MENU, self.onInsertPolicy, ToolMenuInsertPolicy) # # Create the ToolBar # def createToolBar( self ): """createToolBar - create the Tool Bar""" toolbar = self.CreateToolBar() for each in self.toolBarData(): self.createSimpleTool( toolbar, *each ) toolbar.AddSeparator() toolbar.Realize() #exitTool = ToolBar.AddLabelTool( wx.ID_ANY, 'Exit', wx.Bitmap('texit.png')) #ToolBar.Realize() #self.Bind(wx.EVT_TOOL, self.OnExit, ExitTool) def createSimpleTool( self, toolbar, label, filename, help, handler): """createSimpleTool - create a simple tool for the Tool Bar""" bmp = wx.Image( filename, wx.BITMAP_TYPE_BMP).ConvertToBitmap() tool = toolbar.AddSimpleTool( -1, bmp, label, help) #tool = toolbar.AddSimpleTool( -1, wx.NullBitmap, label, help) self.Bind( wx.EVT_MENU, handler, tool ) def toolBarData( self ): # label, filename, help, handler return(("New", "new.bmp", "Create a new Policy", self.onNew), ("Open", "open.bmp", "Open a saved PDEF file", self.onOpen), ("Save", "save.bmp", "Save Policy to a PDEF file", self.onSave), ("Save as a printable text file", "save.bmp", "Save Policy to a printable text file", self.onPrint), # ("Tool Info", "help.bmp", "Tool info", self.onAbout) ) # # Create the Default Policy Panel # # Policy Rules Version Control Options Policy Type Hash Alg # [rnd chk box text box sq chkbox rnd chk box pulldown] # -------------------------------------------------------------------------- # PS Version 2.2 Allow NPW LIST SHA1 # PO MinSINITVer 0 SINIT Cap... ANY # # Number of View List Add List Delete List ACM Revocation Limits [text] # Lists BIOS SINIT # [text box text box button button text box text box] # def createPolicyPanel( self ): """ createPolicyPanel - create the Policy Panel""" # Create a ScrolledWindow with a BoxSizer to contain every panel self.scrollableWindow = wx.ScrolledWindow(self, wx.ID_ANY, style=wx.TAB_TRAVERSAL) self.scrollableWindow.SetScrollbars(1, 1, 1, 1) self.scrollableWindow.SetScrollRate(10, 10) self.scrollableWindow.SetAutoLayout(1) self.scrollableWindowSizer = wx.BoxSizer(wx.VERTICAL) self.scrollableWindow.SetSizer(self.scrollableWindowSizer) # create the Policy Panel with a GridBagSizers self.policyPanel = wx.Panel(self.scrollableWindow, -1) self.policyPanelSizer = wx.GridBagSizer(hgap=5, vgap=5) self.policyPanel.SetSizer(self.policyPanelSizer) policyLabel = wx.StaticText(self.policyPanel, -1, "Policy") font18 = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) policyLabel.SetFont( font18 ) self.policyPanelSizer.Add( policyLabel, pos=(1, 0)) pdefFileLabel = wx.StaticText(self.policyPanel, label="PDEF File: ") self.policyPanelSizer.Add( pdefFileLabel, pos=(0,4)) self.pdefFileName = wx.TextCtrl( self.policyPanel, value='None', size=(140, -1)) self.pdefFileName.Enable( False ) # Version cannot be modified self.policyPanelSizer.Add( self.pdefFileName, pos=(0,7)) # PS/PO Policy Rules Radio Buttons - PDEF.Rules self.psRadioButton = wx.RadioButton( self.policyPanel, -1, "PS Policy Rules", style=wx.RB_GROUP) self.poRadioButton = wx.RadioButton( self.policyPanel, -1, "PO Policy Rules") self.poRadioButton.SetValue( True ) self.policyPanelSizer.Add( self.psRadioButton, pos=(2,0), span=(1,2)) self.policyPanelSizer.Add( self.poRadioButton, pos=(3,0), span=(1,2)) self.Bind(wx.EVT_RADIOBUTTON, self.onPolicyRulesRadioClick, self.psRadioButton) self.Bind(wx.EVT_RADIOBUTTON, self.onPolicyRulesRadioClick, self.poRadioButton) # Version text boxes: Version [PDEF.PolVersion] & Min SINIT Version [PDEF.SINITMinVersion] self.versionLabel = wx.StaticText(self.policyPanel, label="Version: ") self.policyPanelSizer.Add( self.versionLabel, pos=(1,3)) supportedversions = sorted(DEFINES.SUPPORTED_LCP_VERSION.keys(), reverse=True) defaultversion = supportedversions[0] self.versionEdit = wx.ComboBox( self.policyPanel, size=(40, -1), value=defaultversion, choices=supportedversions, style=wx.CB_READONLY) #self.versionEdit.Enable( False ) # Version cannot be modified self.policyPanelSizer.Add( self.versionEdit, pos=(1,4)) self.Bind(wx.EVT_TEXT, self.onPolicyVersion, self.versionEdit) majorstring, minorstring = defaultversion.split('.') pdef.PolVersionMajor = int(majorstring) pdef.PolVersionMinor = int(minorstring) self.minSinitVersionLabel = wx.StaticText(self.policyPanel, label="Min SINIT Version: ") self.policyPanelSizer.Add(self.minSinitVersionLabel, pos=(2,3)) minSinitVersion = pdef.SinitMinVersion # get current value self.minSinitVersionEdit = wx.TextCtrl( self.policyPanel, value=str(minSinitVersion), size=(30, -1)) self.policyPanelSizer.Add( self.minSinitVersionEdit, pos=(2,4)) self.Bind(wx.EVT_TEXT, self.onMinSinitVersion, self.minSinitVersionEdit) # Control Options - Checkboxes - PDEF.PolicyControl contolOptionsLabel = wx.StaticText(self.policyPanel, -1, "Control Options") font10 = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) contolOptionsLabel.SetFont( font10 ) self.allowNPW = wx.CheckBox(self.policyPanel, label="Allow NPW") self.sinitCapabilites = wx.CheckBox(self.policyPanel, label="SINIT Capabilities in PCR17") self.auxDelete = wx.CheckBox(self.policyPanel, label="AUX Delete") self.auxDelete.Enable( False ) self.forceOwnerPolicyValue = False self.forcePsPconfValue = True pdef.PolicyControl |= DEFINES.PolicyControlForceOwnerBitMask # Initialize PolicyConrol with forcePsPconf bit set. self.forcePsOrPo = wx.CheckBox(self.policyPanel, label="Force PS PCONF") # inverse of Force Owner Policy self.forcePsOrPo.SetValue( self.forcePsPconfValue ) # defaults to checked => bit=0 #self.forceOwnerPolicy = wx.CheckBox(self.policyPanel, label="Force Owner Policy") # inverse of Force PS PCONFIG #self.forceOwnerPolicy.Hide() self.ignorePsStm = wx.CheckBox(self.policyPanel, label="Ignore PS STM") self.ignorePsPconf = wx.CheckBox(self.policyPanel, label="Ignore PS PCONF") self.ignorePsMle = wx.CheckBox(self.policyPanel, label="Ignore PS MLE") self.Bind(wx.EVT_CHECKBOX, self.onNpwPolicyControl, self.allowNPW) self.Bind(wx.EVT_CHECKBOX, self.onPcr17PolicyControl, self.sinitCapabilites) self.Bind(wx.EVT_CHECKBOX, self.onForcePsOrPoPolicyControl, self.forcePsOrPo) #self.Bind(wx.EVT_CHECKBOX, self.onForceOwnerPolicyControl, self.forceOwnerPolicy) self.Bind(wx.EVT_CHECKBOX, self.onAuxDelete, self.auxDelete) self.Bind(wx.EVT_CHECKBOX, self.onIgnorePsStm, self.ignorePsStm) self.Bind(wx.EVT_CHECKBOX, self.onIignorePsPconf, self.ignorePsPconf) self.Bind(wx.EVT_CHECKBOX, self.onIgnorePsMle, self.ignorePsMle) self.policyPanelSizer.Add(contolOptionsLabel, pos=(3,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.allowNPW, pos=(4,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.sinitCapabilites, pos=(5,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.auxDelete, pos=(6,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.forcePsOrPo, pos=(7,7), span=(1,2), flag=wx.BOTTOM, border=5) #self.policyPanelSizer.Add(self.forceOwnerPolicy, pos=(7,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.ignorePsStm, pos=(8,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.ignorePsPconf, pos=(9,7), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.ignorePsMle, pos=(10,7), span=(1,2), flag=wx.BOTTOM, border=5) # Hide ignoreXXX GUI if it's not LCP policy version 3.1 if defaultversion == '3.1': self.showV31Gui(True) else: self.showV31Gui(False) # Policy Type Radios List: LIST, ANY - PDEF.PolicyType policyTypeLabel = wx.StaticText(self.policyPanel, -1, "Policy Type") policyTypeLabel.SetFont( font10 ) self.listRadioButton = wx.RadioButton( self.policyPanel, -1, "LIST", style=wx.RB_GROUP) self.anyRadioButton = wx.RadioButton( self.policyPanel, -1, "ANY") self.anyRadioButton.SetValue( True ) self.selectedPolicyType = self.anyRadioButton self.Bind(wx.EVT_RADIOBUTTON, self.onPolicyTypeRadioClick, self.listRadioButton) self.Bind(wx.EVT_RADIOBUTTON, self.onPolicyTypeRadioClick, self.anyRadioButton) self.policyPanelSizer.Add(policyTypeLabel, pos=(5,0), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.listRadioButton, pos=(7,0), span=(1,2), flag=wx.BOTTOM, border=5) self.policyPanelSizer.Add(self.anyRadioButton, pos=(6,0), span=(1,2), flag=wx.BOTTOM, border=5) # Hash Alg combobox Control hashList = DEFINES.SUPPORTED_HASHES self.hashAlgLabel = wx.StaticText(self.policyPanel, label="Hash\nAlgorithm") self.hashAlgLabel.SetFont( font10 ) self.policyPanelSizer.Add(self.hashAlgLabel, pos=(0,10)) self.hashAlgEdit = wx.ComboBox( self.policyPanel, size=(75, -1), value="SHA256", choices=hashList, style=wx.CB_READONLY ) self.hashAlgEdit.Enable( False ) # disabled since Policy Type: ANY is default self.policyPanelSizer.Add(self.hashAlgEdit, pos=(1,10)) self.Bind(wx.EVT_TEXT, self.onHashAlg, self.hashAlgEdit) # Algorithm for Auto-Promotion self.algForApLabel = wx.StaticText(self.policyPanel, label="Algorithm for\nAuto-Promotion") self.algForApLabel.SetFont( font10 ) self.policyPanelSizer.Add(self.algForApLabel, pos=(0,13)) self.algForApEdit = wx.ComboBox( self.policyPanel, size=(75, -1), value="SHA256", choices=hashList, style=wx.CB_READONLY ) self.algForApEdit.Enable( True ) # disabled since Policy Type: ANY is default self.policyPanelSizer.Add(self.algForApEdit, pos=(1,13)) self.Bind(wx.EVT_TEXT, self.onAlgForAp, self.algForApEdit) # Algorithm Allowed for LCP self.algAllowedForLcpLabel = wx.StaticText(self.policyPanel, label="Algorithms Allowed for\nLaunch Control Policy") self.algAllowedForLcpLabel.SetFont( font10 ) self.policyPanelSizer.Add(self.algAllowedForLcpLabel, pos=(2,10), span=(1,2)) hashList = DEFINES.ALLOWED_HASHES self.algAllowedForLcpEdit = wx.CheckListBox( self.policyPanel, -1, size=wx.DefaultSize, choices=hashList, style=wx.LB_MULTIPLE) self.policyPanelSizer.Add(self.algAllowedForLcpEdit, pos=(3,10), span=(8,3)) self.Bind(wx.EVT_CHECKLISTBOX, self.onAlgAllowedForLcp, self.algAllowedForLcpEdit) # Set the default value from PDEF structure checkedLCP = [] for item in DEFINES.TPM_ALG_HASH_MASK.keys(): if(pdef.LcpHashAlgMask & DEFINES.TPM_ALG_HASH_MASK[item]): checkedLCP.append(item) self.algAllowedForLcpEdit.SetCheckedStrings(checkedLCP) # Allowed Signature Schemes self.allowedSigSchemesLabel = wx.StaticText(self.policyPanel, label="Allowed Signature\nSchemes") self.allowedSigSchemesLabel.SetFont( font10 ) self.policyPanelSizer.Add(self.allowedSigSchemesLabel, pos=(2,13)) sigList = DEFINES.ALLOWED_SIGNATURE_SCHEMES self.allowedSigSchemesEdit = wx.CheckListBox( self.policyPanel, -1, size=wx.DefaultSize, choices=sigList, style=wx.LB_MULTIPLE) self.policyPanelSizer.Add(self.allowedSigSchemesEdit, pos=(3,13), span=(8,3)) self.Bind(wx.EVT_CHECKLISTBOX, self.onAllowedSigSchemes, self.allowedSigSchemesEdit) checkedSign = [] for item in DEFINES.TPM_ALG_SIGN_MASK.keys(): if(pdef.LcpSignAlgMask & DEFINES.TPM_ALG_SIGN_MASK[item]): checkedSign.append(item) self.allowedSigSchemesEdit.SetCheckedStrings(checkedSign) # Number of Lists text box self.numOfListsLabel = wx.StaticText(self.policyPanel, label="Number of Lists") self.policyPanelSizer.Add( self.numOfListsLabel, pos=(8,3)) self.numOfListsEdit = wx.TextCtrl( self.policyPanel, value="", size=(30, -1)) self.numOfListsLabel.Enable( False ) self.numOfListsEdit.Enable( False ) self.policyPanelSizer.Add( self.numOfListsEdit, pos=(8,4)) # View List text box self.viewListLabel = wx.StaticText(self.policyPanel, label="View List") self.policyPanelSizer.Add( self.viewListLabel, pos=(9,3)) self.viewListEdit = wx.TextCtrl( self.policyPanel, value="", size=(30, -1)) self.viewListLabel.Enable( False ) self.viewListEdit.Enable( False ) self.policyPanelSizer.Add( self.viewListEdit, pos=(9,4)) self.Bind(wx.EVT_TEXT, self.onViewList, self.viewListEdit) # Add and Delete List buttons self.addListButton = wx.Button( self.policyPanel, -1, label="Add List ", style=wx.BU_EXACTFIT) self.addListButton.Enable( False ) self.policyPanelSizer.Add( self.addListButton, pos=(8, 0)) self.Bind(wx.EVT_BUTTON, self.onAddListButtonClick, self.addListButton) # add event handler self.deleteListButton = wx.Button( self.policyPanel, -1, label="Delete List", style=wx.BU_EXACTFIT) self.deleteListButton.Enable( False ) self.policyPanelSizer.Add( self.deleteListButton, pos=(9, 0)) self.Bind(wx.EVT_BUTTON, self.onDeleteListButtonClick, self.deleteListButton) # add event handler # ACM Revocation Limits static text [PDEF.MaxBiosMinVersion & PDEF.MaxSinitMinVersion ] self.acmRevLabel = wx.StaticText(self.policyPanel, -1, "ACM Revocation Limits") self.acmRevLabel.SetFont( font10 ) self.policyPanelSizer.Add( self.acmRevLabel, pos=(3, 3), span=(1,4)) # BIOS text box self.biosLabel = wx.StaticText(self.policyPanel, label="BIOS") self.policyPanelSizer.Add( self.biosLabel, pos=(4,3)) value = pdef.MaxBiosMinVersion # get current value self.biosEdit = wx.TextCtrl( self.policyPanel, value=str(value), size=(30, -1)) self.policyPanelSizer.Add( self.biosEdit, pos=(4,4)) self.Bind(wx.EVT_TEXT, self.onBiosRevLimit, self.biosEdit) # SINIT text box self.sinitLabel = wx.StaticText(self.policyPanel, label="SINIT") self.policyPanelSizer.Add( self.sinitLabel, pos=(5,3)) value = pdef.MaxSinitMinVersion # get current value self.sinitEdit = wx.TextCtrl( self.policyPanel, value=str(value), size=(30, -1)) self.policyPanelSizer.Add( self.sinitEdit, pos=(5,4)) self.Bind(wx.EVT_TEXT, self.onSinitRevLimit, self.sinitEdit) #self.policyPanelSizer.Add(policyGridSizer, 0, wx.ALL, 5) #policyHorizSizer.Add(policyGridSizer, 0, wx.ALL, 5) #self.policyPanelSizer.Add(policyHorizSizer, 0, wx.ALL, 5) #self.scrollableWindow.SetSizerAndFit(self.policyPanelSizer) self.scrollableWindowSizer.Add(self.policyPanel, 0, wx.ALL, 5) w,h = self.scrollableWindowSizer.GetMinSize() self.scrollableWindow.SetVirtualSize((w,h)) self.scrollableWindow.Layout() self.StatusBar.SetStatusText( "FileTypeSignature = %s, DefCompany = %s, StructVersion = %s" % (pdef.FileTypeSignature, pdef.DefCompany, pdef.StructVersion)) ############################ # File Menu Event Handlers # ############################ def onNew(self, event): """ onNew - Create a new PDEF file""" global pdef, list if(pdef.Modified == True): self.StatusBar.SetStatusText( "Save current PDEF file first?." ) self.savePdefFile(title="Save current PDEF file?", name=filename) self.StatusBar.SetStatusText( "" ) if(pdef.NumLists != 0): list.hideListPanel() w,h = self.scrollableWindowSizer.GetMinSize() self.scrollableWindow.SetVirtualSize((w,h)) self.scrollableWindow.Layout() pdef = PDEF() list = LIST() self.PolListInfo = {'0':None, '1':None, '2':None, '3':None, '4':None, '5':None, '6':None, '7':None } #self.setDefaultPdef() self.restorePanel() # Create a new PDEF project file with default settings. # The selected directory will be the working directory. self.savePdefFile(title="New PDEF project", name="NewPlatform.pdef") def onOpen(self, event): """ onOpen - Open an existing PDEF file""" global filename, dirname, pdef #self.dirname = '' # current owrking directory wildcard = "PDEF file (*.pdef)|*.pdef|" \ "All Files (*.*)|*.*" dlg = wx.FileDialog(self, "Choose the PDEF file", dirname, "", wildcard, wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() pdef = PDEF() # loadAndDisplayPdefFile use pickle to load the saved file, does it overwrite pdef entirely? self.pdefFileName.ChangeValue(filename) self.loadAndDisplayPdefFile() pdef.WorkingDirectory = dirname dlg.Destroy() # # If the PDEF has been modified, save it to specified name and return True # if not modified, return False # def savePdefFile(self, title, name): """ savePdefFile - perform Save or SaveAs""" global filename, dirname wildcard = "PDEF file (*.pdef)|*.pdef|" \ "All Files (*.*)|*.*" dlg = wx.FileDialog(self, title, dirname, name, wildcard, wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() pdef.Modified = False pdef.WorkingDirectory = dirname self.pdefFileName.ChangeValue(filename) self.writePdefFile() self.printPdefTextFile() if (self.listRadioButton.GetValue() == True ): self.enableDisableListWidgets( True ) else: self.enableDisableListWidgets( False ) # originally, filename had no extension so strip it off keeping the user supplied base name #filename, ext = filename.rsplit('.', 1) print("DEBUG TxtPolicyGen2: Working Directory = %s" %dirname) else: print("savePdefFile: user cancelled, PDEF not saved") # DBGDBG dlg.Destroy() #print("savePdefFile - done. filename=%s" % (filename)) # DBGDBG return True def confirmSavePdefFile(self, title, name): """ savePdefFile - perform Save or SaveAs""" dlg = wx.MessageDialog(self, name+" Exists.\nOverwrite existing file?", title, wx.OK|wx.CANCEL|wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_OK: pdef.Modified = False # Want to save this status self.writePdefFile() self.printPdefTextFile() print("DEBUG TxtPolicyGen2: Working Directory = %s" %dirname) else: print("savePdefFile: user cancelled, PDEF not saved") # DBGDBG dlg.Destroy() return True def onSave(self, event): """ onSave - Save a file""" base = self.getBasePdefFile() if (self.pdefFileName.GetValue() == "None"): self.savePdefFile(title="Save PDEF File", name=base) return True else: self.confirmSavePdefFile(title="Confirm Overwrite", name=filename) return True def onSaveAs(self, event): """ onSaveAs - Save a file as ...""" base = self.getBasePdefFile() self.savePdefFile(title="Save PDEF File As", name=base) def onPrint(self, event): """ onPrint - save policy as a printable text file""" self.printPdefFile() def onExit(self, event): """ onExit - close any open PDEF's and exit""" if(pdef.Modified == True): self.savePdefFile(title="Save Policy before exiting?", name=filename) self.Close(True) # Close the frame. ############################ # Help Menu Event Handlers # ############################ def onAbout(self, event): """ onAbout - provide Help/About info""" # A message dialog box with an OK button. dlg = wx.MessageDialog( self, "TXT Policy Generator v%d, Release %s, Build date %s" % (DEFINES.LCP_VERSION, DEFINES.TOOL_VERSION, DEFINES.BUILD_DATE), "About TXT Policy Generator" ) dlg.ShowModal() # Show dialog & wait for OK or Cancel dlg.Destroy() # finally destroy it when finished. def onLicense(self, event): """ onLicense - display the license""" license = 'Win LCP Generator License.pdf' self.openPdf(license) def openPdf(self, file): """openPdf - display the specified pdf file""" #import subprocess #from subprocess import CalledProcessError # make sure the file is present try: f = open(file, 'r') except: msg = "File %s not found" % (file) self.StatusBar.SetStatusText("%s" % (msg)) print("%s" % (msg)) return f.close() self.StatusBar.SetStatusText( "Opening Acrobat reader to display file %s..." % (file)) # form the aboslute path to the pdf and pass that to acrobat try: if os.name == 'nt': #subprocess.check_call(['C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe', os.path.join(os.getcwd(),file)]) os.startfile(file) else: #subprocess.check_call(['evince', os.path.join(os.getcwd(),file)]) os.system('xdg-open ' + file) except Exception as e: print(e.returncode) self.StatusBar.SetStatusText( "" ) def onKeyGen(self, event): """ onKeyGen - Generating keys with OpenSSL""" dlg = wx.MessageDialog( self, "To create public and private keys with OpenSSL:\n openssl genrsa -out PrivateKeyFile.pem [1024,2048,3072]\n openssl rsa -pubout -in PrivateKeyFile.pem -out PublicKeyFile.pem\n", "Key Generation") dlg.ShowModal() # Show dialog & wait for OK or Cancel dlg.Destroy() # finally destroy it when finished. def batchBuildHelp(self, event): """ batchBuildHelp - help for batch builds""" dlg = wx.MessageDialog( self, "To perform a build of a previously saved pdef file from the command line or a script:\ttxtPolGen2 -open MySystem.pdef -build\n", "Batch Build Help") dlg.ShowModal() # Show dialog & wait for OK or Cancel dlg.Destroy() # finally destroy it when finished. def hashImageHelp(self, event): """ hashImageHelp - help for hashing image from cmd line""" dlg = wx.MessageDialog( self, "To hash an image from the command line or a script:\ttxtPolGen2 -hash image.bin startOffset offsetSize hashAlgorithm\nwhere 4=SHA1, 0xb=SHA256", "Hash Image Help") dlg.ShowModal() # Show dialog & wait for OK or Cancel dlg.Destroy() # finally destroy it when finished. def onGuide(self, event): """ onGuide - Open the User Guide""" file = 'LCP2Gen User Guide.pdf' self.openPdf(file) def onTutorial(self, event): """ onTutorial - Open the Tutorial""" #TODO: NiceToHave: onTutorial - implement HelpMenu: Tutorial self.StatusBar.SetStatusText("No Tutorial yet.") #def onHashFile(self, event): # """onHashFile - hash the specified file""" # self.StatusBar.SetStatusText( "This feature is not implemented from GUI, please use command line." ) # # #from tools import TOOLS # #tools = TOOLS() # # # #TODO: For GUI, need to get the parameters:biosFileName, startOffset, offsetSize and hashAlg from the user # # # #tools.hashImage(biosFileName, startOffset, offsetSize, hashAlg) # #def onInsertPolicy(self, event): # """onInsertPolicy - insert a policy into an image per the FIT type 7 record""" # self.StatusBar.SetStatusText( "This feature is not implemented yet." ) ######################## ###GUI Event Handlers### ######################## # # LIST or ANY Policy Type Radio buttons clicked # def onPolicyTypeRadioClick(self, event): """ onPolicyTypeRadioClick - LIST or ANY Policy Type radio button selected, enable /disable widgets """ #self.StatusBar.SetStatusText( "You clicked a Policy Type Radio Button! id %i, LIST id= %i" % ( event.GetId(), self.listRadioButton.GetId() ) ) #print("in onPolicyTypeRadioClick") # DBGDBG #pdef.Modified = True if event.GetId() == self.listRadioButton.GetId() : # Policy Type: LIST selected, enable LIST widgets if(self.pdefFileName.GetValue() == "None"): # Force user to create a new empty .pdef file for project working directory. value = False else: value = True self.hashAlgEdit.Enable( True ) # enable Hash Algorithm ComboBox when switch from ANY to LIST pdef.PolicyType = DEFINES.LIST if(pdef.NumLists > 0): list.showListPanel() else : # Policy Type: ANY selected, disable LIST widgets & LIST panel value = False self.hashAlgEdit.Enable( False ) # disabled since Policy Type: ANY is default pdef.PolicyType = DEFINES.ANY list.hideListPanel() self.enableDisableListWidgets( value ) policyTypeRadioSelected = event.GetEventObject() def setPsRulesMode(self): """ setPsRulesMode - set for PS rules""" # PS Policy Rules selected, enable forceOwnerPolicy #self.forceOwnerPolicy.Enable( True ) #self.forcePsPconf.Enable( False ) # Cannot place 2 widgets in the same location, so remove one self.forcePsOrPo.SetLabel("Force Owner Policy") self.forcePsOrPo.SetValue(self.forceOwnerPolicyValue) #self.forcePsPconf.Hide() #self.forceOwnerPolicy.Hide() #self.policyPanelSizer.Remove(self.forcePsPconf) # remove both checkboxes and add one back to avoid error #self.policyPanelSizer.Remove(self.forceOwnerPolicy) #self.policyPanelSizer.CheckForIntersection(self.forceOwnerPolicy, excludeItem=self.forcePsPconf) #self.policyPanelSizer.Add(self.forceOwnerPolicy, pos=(7,7), span=(1,2), flag=wx.BOTTOM, border=5) #self.forceOwnerPolicy.Show() self.ignorePsStm.Enable( False ) self.ignorePsPconf.Enable( False ) self.ignorePsMle.Enable( False ) self.auxDelete.Enable( True ) #self.acmRevLabel.Enable( False ) self.biosEdit.Enable( False ) self.sinitEdit.Enable( False ) #self.biosLabel.Enable( False ) #self.sinitLabel.Enable( False ) self.policyPanelSizer.Layout() # update pdef.PolicyControl after switching to PS Policy Rule radio button. if(self.forcePsOrPo.GetValue() == 1): pdef.PolicyControl |= DEFINES.PolicyControlForceOwnerBitMask else: pdef.PolicyControl &= ~DEFINES.PolicyControlForceOwnerBitMask if(self.auxDelete.GetValue() == 1): pdef.PolicyControl |= DEFINES.PolicyControlAUXDeletionControl else: pdef.PolicyControl &= ~DEFINES.PolicyControlAUXDeletionControl # Clear Ignore_PS_xxx bits pdef.PolicyControl &= ~DEFINES.PolicyControlIgnorePsStmBitMask pdef.PolicyControl &= ~DEFINES.PolicyControlIgnorePsPconfBitMask pdef.PolicyControl &= ~DEFINES.PolicyControlIgnorePsMleBitMask self.StatusBar.SetStatusText("PDEF.PolicyControl = 0x%x" % (pdef.PolicyControl) ) # if current list has a PCONF element, disable its OverridePsPolicy checkbox #if((1 <= pdef.CurrentListView) and (pdef.CurrentListView <= pdef.NumLists)): # list.enablePconfOverridePsPolicyCheckbox(False) def setPoRulesMode(self): """ setPoRulesMode - set for PO rules""" # PO Policy Rules selected, disable forceOwnerPolicy #self.forceOwnerPolicy.Enable( False ) #self.forcePsPconf.Enable( True ) # Cannot place 2 widgets in the same location, so destroy and recreate self.forcePsOrPo.SetLabel("Force PS PCONF") self.forcePsOrPo.SetValue(self.forcePsPconfValue) #self.forceOwnerPolicy.Hide() #self.forcePsPconf.Hide() #self.policyPanelSizer.Remove(self.forceOwnerPolicy) #self.policyPanelSizer.Remove(self.forcePsPconf) # remove both checkboxes and add one back to avoid error #self.policyPanelSizer.CheckForIntersection(self.forcePsPconf, excludeItem=self.forceOwnerPolicy) #self.policyPanelSizer.Add(self.forcePsPconf, pos=(7,7), span=(1,2), flag=wx.BOTTOM, border=5) #self.forcePsPconf.Show() self.ignorePsStm.Enable( True ) self.ignorePsPconf.Enable( True ) self.ignorePsMle.Enable( True ) self.auxDelete.Enable( False ) #self.acmRevLabel.Enable( True ) self.biosEdit.Enable( True ) self.sinitEdit.Enable( True ) #self.biosLabel.Enable( True ) #self.sinitLabel.Enable( True ) self.policyPanelSizer.Layout() # update pdef.PolicyControl after switching to PO Policy Rule radio button if(self.forcePsOrPo.GetValue() == 1): pdef.PolicyControl |= DEFINES.PolicyControlForceOwnerBitMask else: pdef.PolicyControl &= ~DEFINES.PolicyControlForceOwnerBitMask if(self.ignorePsStm.GetValue() == 1): pdef.PolicyControl |= DEFINES.PolicyControlIgnorePsStmBitMask else: pdef.PolicyControl &= ~DEFINES.PolicyControlIgnorePsStmBitMask if(self.ignorePsPconf.GetValue() == 1): pdef.PolicyControl |= DEFINES.PolicyControlIgnorePsPconfBitMask else: pdef.PolicyControl &= ~DEFINES.PolicyControlIgnorePsPconfBitMask if(self.ignorePsMle.GetValue() == 1): pdef.PolicyControl |= DEFINES.PolicyControlIgnorePsMleBitMask else: pdef.PolicyControl &= ~DEFINES.PolicyControlIgnorePsMleBitMask # clear AuxDelete bit pdef.PolicyControl &= ~DEFINES.PolicyControlAUXDeletionControl self.StatusBar.SetStatusText("PDEF.PolicyControl = 0x%x" % (pdef.PolicyControl) ) # if current list has a PCONF element, enable its OverridePsPolicy checkbox # if((1 <= pdef.CurrentListView) and (pdef.CurrentListView <= pdef.NumLists)): # list.enablePconfOverridePsPolicyCheckbox(True) # # PS or PO Policy Rules Radio buttons clicked # def onPolicyRulesRadioClick(self, event): """ onPolicyRulesRadioClick - PS or PO Policy Rules Radio button selected, enable/disable widgets """ #print("in onPolicyRulesRadioClick") # DBGDBG pdef.Modified = True if event.GetId() == self.psRadioButton.GetId() : self.setPsRulesMode() pdef.Rules = DEFINES.PsRules # if the list panel has been created, and no Sbios panel exists, enable the Add SBIOS button if(pdef.NumLists > 0): currentListObject = pdef.getCurrentListObject() list.rebuildAddElementChoicesForPsRules() # add SBIOS if they don't exist # Does all element has PS Policy override checkbox? # earlier code only enable/disable OverridePsPolicy for SBOS and MLE list.syncVersion(pdef.Rules) #for element in list.includedElements: # element.enableDisableOverridePsPolicy(False) else : self.setPoRulesMode() pdef.Rules = DEFINES.PoRules # if the list panel has been created, remove the SBIOS entries if(pdef.NumLists > 0): currentListObject = pdef.getCurrentListObject() list.rebuildAddElementChoicesForPoRules() list.syncVersion(pdef.Rules) #for element in list.includedElements: # element.enableDisableOverridePsPolicy(True) def onHashAlg(self, event): """onHashAlg - update pdef.HashAlg""" pdef.HashAlg = DEFINES.TPM_ALG_HASH[event.GetString()] #if(event.GetString() == "SHA1"): # pdef.HashAlg = DEFINES.TPM_ALG_SHA1 #elif(event.GetString() == "SHA256"): # pdef.HashAlg = DEFINES.TPM_ALG_SHA256 #elif(event.GetString() == "SHA384"): # pdef.HashAlg = DEFINES.TPM_ALG_SHA384 #elif(event.GetString() == "SHA512"): # pdef.HashAlg = DEFINES.TPM_ALG_SHA512 pdef.Modified = True self.StatusBar.SetStatusText( "HashAlg=%d" %(pdef.HashAlg)) def onAlgForAp(self, event): """onAlgForAp - update algorithm for auto promotion""" pdef.AuxHashAlgMask = DEFINES.TPM_ALG_HASH_MASK[event.GetString()] #if(event.GetString() == "SHA1"): # pdef.AuxHashAlgMask = DEFINES.TPM_ALG_HASH_MASK_SHA1 #elif(event.GetString() == "SHA256"): # pdef.AuxHashAlgMask = DEFINES.TPM_ALG_HASH_MASK_SHA256 pdef.Modified = True self.StatusBar.SetStatusText( "AuxHashAlgMask=0x%X" %(pdef.AuxHashAlgMask)) def onAlgAllowedForLcp(self, event): """onAlgAllowedForLcp - update algorithm allowed for launch control policy (pdef.LcpHashAlgMask)""" checkedList = self.algAllowedForLcpEdit.GetCheckedStrings() mask = 0 for item in checkedList: mask = mask | DEFINES.TPM_ALG_HASH_MASK[item] pdef.LcpHashAlgMask = mask pdef.Modified = True #print("DEBUG onAlgAllowedForLcp: mask = 0x%08x" %mask) self.StatusBar.SetStatusText("LcpHashAlgMask=0x%X" %(pdef.LcpHashAlgMask)) def onAllowedSigSchemes(self, event): """onAllowedSigSchemes - update allowed signature schemes (pdef.LcpSignAlgMask)""" checkedList = self.allowedSigSchemesEdit.GetCheckedStrings() mask = 0 for item in checkedList: mask = mask | DEFINES.TPM_ALG_SIGN_MASK[item] pdef.LcpSignAlgMask = mask pdef.Modified = True self.StatusBar.SetStatusText("LcpSignAlgMask=0x%X" %(pdef.LcpSignAlgMask)) #print("DEBUG onAllowedSigSchemes: mask = 0x%08x" %mask) # # BUILD Button clicked # # Update pdef.LastBuild[Date,Time]Stamp # if modified, Save .pdef [& .pdef.txt] use that base name for .dat, .pol & .txt # else prompt for a base name # # Generate a .dat [LCP_POLICY_DATA] which includes building the elements and hashing the signed and unsigned lists # Generate .pol and txt of the LCP_POLICY # def onBuildButtonClick(self, event): """ onBuildButtonClick - BUILD button clicked, build the current definition """ status = self.build(BUILD_BUTTON) # doing a build from a button click event if (status == True): dlg = wx.MessageDialog(self, "Build Completed", "Build Status", wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() else: dlg = wx.MessageDialog(self, "Build Failed", "Build Status", wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() currentList = pdef.getCurrentListObject() list.restoreListPanel(currentList) # Update revocation number def onBuildNvPolicy(self, event): """ onBuildNvPolicy - build just the NV Policy""" status = self.build(BUILD_NV_POLICY_ONLY) if (status == True): dlg = wx.MessageDialog(self, "Build Completed", "Build Status", wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() else: dlg = wx.MessageDialog(self, "Build Failed", "Build Status", wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() currentList = pdef.getCurrentListObject() list.restoreListPanel(currentList) # Update revocation number def onBuildPolicyDataStruct(self, event): """ onBuildPolicyDataStruct - build just the Policy Data Struct""" status = self.build(BUILD_POLICY_DATA_ONLY) if (status == True): dlg = wx.MessageDialog(self, "Build Completed", "Build Status", wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() else: dlg = wx.MessageDialog(self, "Build Failed", "Build Status", wx.OK|wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() currentList = pdef.getCurrentListObject() list.restoreListPanel(currentList) # Update revocation number # buildMode can be: # BUILD_BATCH if build initiated from cmd line: # txtPolicyGen.py -open MySystem.pdef -build # BUILD_BUTTON - if build initiated by clicking the build button or build both build menu # BUILD_NV_POLICY_ONLY - if build initiated by clicking the 'build just NV Policy' build menu (.pol) # BUILD_POLICY_DATA_ONLY- if build initiated by clicking the 'build just POLICY DATA' build menu (.dat) # def build(self, buildMode): """build - perform a build""" global filename, dirname # update the build time and date stamps # Per TXT Policy Generator 5.3.1, clear the PDEF's Data Revocation Counters # if PolicyType = LIST, and at least 1 list, then update the list and pdef RevocationCounters # do all this now so it is in the pdef and pdef.txt saved below self.updateLastBuildDateAndTimeStamps() pdef.DataRevocationCounters = [0,0,0,0,0,0,0,0] if(pdef.PolicyType == DEFINES.LIST): if(pdef.NumLists > 0): list.onBuildButtonClick(pdef) # don't need to save current pdef if doing a batch build if((buildMode == BUILD_BUTTON) or (buildMode == BUILD_NV_POLICY_ONLY) or (buildMode == BUILD_POLICY_DATA_ONLY)): # if needed save the current PDEF to base.pdef & base.pdef.txt # NOTE: in the saved PDEF's, the PolicyHash has not been calculated yet # if(self.checkModified() == True): base = filename # default base filename if(self.confirmSavePdefFile(title="Save Policy before building?", name=filename) == True): # True returned if PDEF was modified and so was saved # False returned if not modified so no save needed # # Note: saving the .pdef and .pdef.txt files here ensures that # their LastBuild[Time,Date]Stamp's are updated for this build # reuse the base name [with .pdef.txt extention] provided above # and don't prompt for a file name again #filename = utilities.formFileName(filename, "txt") self.printPdefTextFile() # originally, filename had no extention so strip it off keeping the user supplied base name #filename, ext, ext1 = filename.rsplit('.', 1) else: # If PDEF not saved, then get the base name for the LCP_POLICY & LCP_POLICY_DATA files to build wildcard = "LCP_POLICY (*.pol)|*.pol|" \ "All Files (*.*)|*.*" title = "Please specify a name for the the LCP_POLICY and LCP_POLICY_DATA files to build." dlg = wx.FileDialog(self, title, dirname, filename, wildcard, wx.SAVE|wx.OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() dlg.Destroy() else: # user didn't click OK dlg.Destroy() self.StatusBar.SetStatusText( "No file specified, aborting build" ) return False # originally, filename had no extension so strip it off keeping the user supplied base name #filename, ext = filename.rsplit('.', 1) elif(buildMode == BUILD_BATCH): # originally, filename had no extention so strip it off keeping the user supplied base name #filename, ext = filename.rsplit('.', 1) pass else: # should never get here print("build - unknown buildMode=%d!!!!!!!**********" % (buildMode)) build.filename = filename build.dirname = dirname # If PolicyType==LIST, build the LCP_POLICY_DATA struct, # which includes creating the LIST_MEASUREMENTS[] used to calculate the pdef.PolicyHash # text1 = "Building LCP_POLICY files " text2 = ".[pol and txt]" self.StatusBar.SetStatusText("%s %s %s" % (text1, build.filename, text2)) #print("build - BuildMode=%d" % (buildMode)) # DBGDBG if(build.buildLcpPolicyDataStruct(pdef, self.StatusBar) == False): # Abort build if there was a failure, Build can fail reading hash or pcr files print("build failed, aborting build") return False if(buildMode != BUILD_NV_POLICY_ONLY): # warn if PolicyType == ANY but BUILD_POLICY_DATA_ONLY was requested # since # If PolicyType == ANY, there is no policy data file if((buildMode == BUILD_POLICY_DATA_ONLY) and (pdef.PolicyType == DEFINES.ANY)): self.StatusBar.SetStatusText("Warning - No Policy Data File (.dat) is built when Policy Type is ANY") elif(pdef.PolicyType == DEFINES.LIST): # Per TXT SW Dev Guide 3.1.1.1 p50: if PolicyType is ANY, no LCP_POLICY_DATA is expected # If PolicyType == ANY, there is no policy data file build.buildLcpPolicyDataFile(pdef) if(buildMode != BUILD_POLICY_DATA_ONLY): # generate the LCP_POLICY files if(build.buildRawLcpPolicyFile(pdef, self.StatusBar) == True): # abort if error build.buildTxtLcpPolicyFile(pdef) #build.buildXmlLcpPolicyFile(pdef) # XML output file not requied for LCP2 else: return False # Complete build successfully. Save Pdef file again because pdef.Modified and list.ListModified bits are set False during the build. self.writePdefFile() return True # # Do a batch build - defind as: # when tool invoked from cmd line as: txtpolgen2 -open MySystem.pdef -build # validate the specified file ends with .pdef and exists # open it # do a build # Assumes file in argv[2] exists and has a .pdef extention # def batchBuild(self): """batchBuild - open and buiild the specified file""" #global filename # TODO: validate the .pdef, then open it #filename = sys.argv[2] print("Opening file: %s\%s" % (dirname, filename)) self.loadAndDisplayPdefFile() print("Building") self.build(BUILD_BATCH) # doing a batch build # # Add List Button clicked # def onAddListButtonClick(self, event): """ onAddListButtonClick - Add List button clicked """ maxLists = pdef.MaxLists listNumber = pdef.NumLists # current number of lists pdef.Modified = True if( listNumber+1 == maxLists ): # if only space for 1 more list, disable ADD LIST button self.addListButton.Enable( False ) if( listNumber < maxLists ): # create 1st list panel or update Nth panel listNumber += 1 self.StatusBar.SetStatusText( "Adding List: %i MaxLists=%i" % (listNumber, maxLists)) self.numOfListsEdit.ChangeValue(str(listNumber)) # update the number of Lists widget pdef.NumLists = listNumber pdef.CurrentListView = listNumber # NOTE: ChangeValue() does NOT trigger an event [as if the field was edited by the user] as SetValue() does self.viewListEdit.ChangeValue( str(listNumber)) pdef.addPlistDef(listNumber) if(listNumber == 1): # create list panel 1 # need to enable delete and view list controls self.deleteListButton.Enable( True ) # enable Delete List button self.viewListEdit.Enable( True ) # enable the view list button self.viewListLabel.Enable( True ) # enable the view list label list.createListPanel(wx, self.scrollableWindow, listNumber, pdef, self.StatusBar) else: # update list panel N [< max] to defaults # PDEF object's LIST section should always contain current values list.setListPanelToDefaults(wx, self.scrollableWindow, listNumber, pdef) #w, h = self.scrollableWindow.GetMinSize() #self.scrollableWindow.SetVirtualSize( (w, h) ) self.scrollableWindow.Layout() #self.Layout() #print("AddList: pdef.PolListInfo now = %s" % (pdef.PolListInfo)) # DBGDBG # # Delete List Button clicked # def onDeleteListButtonClick(self, event): """ onDeleteListButtonClick - Delete List button clicked """ dlg = wx.MessageDialog(None, "Deleted Lists cannot be recovered. Continue?", 'Confirm List Deletion', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "List Deletion cancelled" ) else: self.StatusBar.SetStatusText( "Deleted List %i, NumLists now %i" % (pdef.CurrentListView, pdef.NumLists-1)) pdef.Modified = True # sanity check: chk that current list indicated by view list is between 1 & PDEF.NumLists if((1 <= pdef.CurrentListView) and (pdef.CurrentListView <= pdef.NumLists)): currentListObject = pdef.getCurrentListObject() # delete the current list indicated by view list del currentListObject else: self.StatusBar.SetStatusText( "List Deletion cancelled. CurrentListView=%i, NumLists=%i??" % (pdef.CurrentListView, pdef.NumLists)) # decrement PDEF.NumLists, if now = 0, ViewList and DeleteList are disabled # otherwise, update CurrentListView and display it deletedList = pdef.CurrentListView pdef.NumLists -= 1 if(pdef.NumLists == 0): pdef.PolListInfo[str(pdef.CurrentListView-1)] = None self.viewListLabel.Enable( False ) self.viewListEdit.Enable( False ) self.viewListEdit.ChangeValue("") self.addListButton.Enable( True ) self.deleteListButton.Enable( False ) pdef.CurrentListView = 0 pdef.NumLists = 0 self.numOfListsEdit.ChangeValue(str(pdef.NumLists)) list.hideListPanel() self.scrollableWindow.Layout() #TODO: WxPython: onDeleteListButtonClick - Layout() didn't resize policyPanel after deleting the last list? Due to Show/Hide? print("DeleteList=0: NumLists=%i CurrentListView=%i" % (pdef.NumLists, pdef.CurrentListView)) # DBGDBG print("Delete List: pdef.PolListInfo now = %s" % (pdef.PolListInfo)) # DBGDBG else: #pdef.PolListInfo[str(pdef.CurrentListView-1)] = None pdef.CurrentListView -= 1 if(pdef.CurrentListView == 0): pdef.CurrentListView = 1 # if list 1 was deleted, and there are >1 lists left, show new list 1 currentListStr = str(pdef.CurrentListView) self.viewListEdit.ChangeValue(currentListStr) self.numOfListsEdit.ChangeValue(str(pdef.NumLists)) list.listLabelNum.ChangeValue(currentListStr) print("DeleteList>0: NumLists=%i CurrentListView=%i" % (pdef.NumLists, pdef.CurrentListView)) # DBGDBG print("\nDeleted List %i: NumLists=%i\npdef.PolListInfo was %s" % (deletedList, pdef.NumLists, pdef.PolListInfo)) # DBGDBG i=deletedList end = pdef.NumLists+1 for i in range(i, end): pdef.PolListInfo[str(i-1)] = pdef.PolListInfo[str(i)] print("shift %i to %i" % (i, i-1)) # DBGDBG i += 1 pdef.PolListInfo[str(end-1)] = None print("delete %i" % (end)) # DBGDBG print("pdef.PolListInfo now %s\n" % (pdef.PolListInfo)) # DBGDBG def onPolicyVersion(self, event): policyversion = event.GetString() majorstring, minorstring = policyversion.split('.') pdef.PolVersionMajor = int(majorstring) pdef.PolVersionMinor = int(minorstring) if policyversion == '3.0': self.showV31Gui(False) else: self.showV31Gui(True) # go thru each list and change list version number listversion = DEFINES.SUPPORTED_LCP_VERSION[policyversion] majorstring, minorstring = listversion.split('.') for listobj in pdef.PolListInfo.values(): if listobj != None: listobj.ListVersionMajor = int(majorstring) listobj.ListVersionMinor = int(minorstring) # refresh text in the current list displayed if pdef.NumLists != 0: list.syncVersion(pdef.Rules) pdef.Modified = True # # MinSinitVersion value changed - update PDEF.SINITMinVersion # def onMinSinitVersion(self, event): """ onMinSinitVersion - MinSinitVersion value was changed""" #self.StatusBar.SetStatusText( "You changed MinSinitVersion to %s" % ( event.GetString() )) #print("in onMinSinitVersion") # DBGDBG string = event.GetString() try: value = int(string) except: self.StatusBar.SetStatusText( "%s is invalid, Please enter only digits between 0 and 9" % (string)) else: if(int(value) > DEFINES.maxVersion): self.StatusBar.SetStatusText( "%i is too large, the max value for MinSinitVersion is %i" % ( int(value), DEFINES.maxVersion )) else: pdef.SinitMinVersion = int(value) pdef.Modified = True self.StatusBar.SetStatusText("") # clear any warnings pdef.Modified = True # # Allow NPW, SINIT cap. in PCR17 or Force Owner Policy 'Policy Control' check box changed # def setPolicyControl(self, event, bit): """ setPolicyControl - the control bits in pdef.PolicyControl. This function is call by all CheckBox callback functions for the policy Control Options. """ policyControl = pdef.PolicyControl if(event.IsChecked()): policyControl |= bit else: policyControl &= ~bit pdef.PolicyControl = policyControl pdef.Modified = True self.StatusBar.SetStatusText("PDEF.PolicyControl = 0x%x" % (policyControl) ) def onNpwPolicyControl(self, event): """ onNpwPolicyControl - Allow NPW change""" self.setPolicyControl(event, DEFINES.PolicyControlAllowNpwBitMask) def onPcr17PolicyControl(self, event): """ onPcr17PolicyControl - Allow SINIT Capability in PCR17 change""" self.setPolicyControl(event, DEFINES.PolicyControlPcr17BitMask) # 'Force Owner Policy' is inverse of 'Force PS PCONFIG', # i.e. they share the same bit in the Control word, and their checkboxes are always opposite values # Enable Force Owner Policy, if PS rules # Enable Force PS PCONFIG, if PO rules # # def onForceOwnerPolicyControl(self, event): # """ onForceOwnerPolicyControl - Force Owner Policy change""" # # if(event.IsChecked()): # self.forceOwnerPolicyValue = True # else: # self.forceOwnerPolicyValue = False # self.setPolicyControl(event, DEFINES.PolicyControlForceOwnerBitMask) def onForcePsOrPoPolicyControl(self, event): """ onForcePsPconfPolicyControl - Force PS PCONF change""" if pdef.Rules == DEFINES.PsRules: if(event.IsChecked()): self.forceOwnerPolicyValue = True else: self.forceOwnerPolicyValue = False else: if(event.IsChecked()): self.forcePsPconfValue = True else: self.forcePsPconfValue = False self.setPolicyControl(event, DEFINES.PolicyControlForceOwnerBitMask) def onAuxDelete(self, event): """ onAuxDelete - AuxDelete Policy change""" self.setPolicyControl(event, DEFINES.PolicyControlAUXDeletionControl) def onIgnorePsStm(self, event): """ onIgnorePsStm - AuxDelete Policy change""" self.setPolicyControl(event, DEFINES.PolicyControlIgnorePsStmBitMask) def onIignorePsPconf(self, event): """ onIignorePsPconf - AuxDelete Policy change""" self.setPolicyControl(event, DEFINES.PolicyControlIgnorePsPconfBitMask) def onIgnorePsMle(self, event): """ onIgnorePsMle - AuxDelete Policy change""" self.setPolicyControl(event, DEFINES.PolicyControlIgnorePsMleBitMask) def onBiosRevLimit(self, event): """ onBiosRevLimit - BIOS Revocation Limit change""" #print("in onBiosRevLimit") # DBGDBG string = event.GetString() try: value = int(string) except: self.StatusBar.SetStatusText( "%s is invalid, Please enter only digits between 0 and 9" % (string)) else: if(int(value) > DEFINES.maxVersion): self.StatusBar.SetStatusText( "%i is too large, the max value for BIOS Revocation Limit is %i" % ( int(value),DEFINES. maxVersion )) else: pdef.MaxBiosMinVersion = int(value) pdef.Modified = True self.StatusBar.SetStatusText("") # clear any warnings def onSinitRevLimit(self, event): """ onSinitRevLimit SINIT Revocation Limit change""" #print("in onSinitRevLimit") # DBGDBG string = event.GetString() try: value = int(string) except: self.StatusBar.SetStatusText( "%s is invalid, Please enter only digits between 0 and 9" % (string)) else: if(int(value) > DEFINES.maxVersion): self.StatusBar.SetStatusText( "%i is too large, the max value for SINIT Revocation Limit is %i" % ( int(value), DEFINES.maxVersion )) else: pdef.MaxSinitMinVersion = int(value) pdef.Modified = True self.StatusBar.SetStatusText("") # clear any warnings def onViewList(self, event): """ onViewList - View List value changed""" #print("in onViewList") # DBGDBG self.StatusBar.SetStatusText("You changed the View List value to %s" % ( event.GetString() )) maxValue = pdef.NumLists string = event.GetString() try: value = int(string) except: self.StatusBar.SetStatusText( "%s is invalid, Please enter only digits between 0 and %i" % (string, maxValue)) else: if(value == 0): self.StatusBar.SetStatusText( "List number must be > 0" ) self.viewListEdit.ChangeValue(str(pdef.CurrentListView)) # restore previous value elif(value > maxValue): self.StatusBar.SetStatusText( "List %i has not been added yet" % ( int(value) )) self.viewListEdit.ChangeValue(str(pdef.CurrentListView)) # restore previous value else: pdef.CurrentListView = int(value) pdef.Modified = True list.setListPanelToCurrentListView( ) # update the list panel to the specified list self.StatusBar.SetStatusText( "Viewing List %d" % ( pdef.CurrentListView )) def setAlgMask(self, event, bit, algsAllowed, which): """setAlgMask - common code for setting LCP/AutoProtection Algorithms Allowed masks""" if(event.IsChecked()): newValue = algsAllowed | bit else: newValue = algsAllowed & ~bit if(which == "LCP"): pdef.LcpHashAlgMask = newValue self.StatusBar.SetStatusText("Algorithm for %s = %d" % (which, pdef.LcpHashAlgMask)) elif(which == "AP"): pdef.AuxHashAlgMask = newValue self.StatusBar.SetStatusText("Algorithm for %s = %d" % (which, pdef.AuxHashAlgMask)) else: self.StatusBar.SetStatusText("ERROR: Illegal value = %s passed to setAlgMask(), expected LCP or AP") pdef.Modified = True print("setAlgMask: LcpHashAlgMask=%x, AuxHashAlgMask=%x" % (pdef.LcpHashAlgMask, pdef.AuxHashAlgMask)) # DBGDBG # # Utility Functions # def enableDisableListWidgets( self, value ) : """ enableDisableListWidgets """ self.addListButton.Enable( value ) self.hashAlgEdit.Enable( value ) self.numOfListsLabel.Enable( value ) # if value = True, set NumberOfLists to 0 if( value == True ): self.numOfListsEdit.ChangeValue("0") # # reset policy panel (& PDEF object) to default vaules # def setDefaultPdef(self): """ setDefaultPdef - set the PDEF to default values""" pdef.Modified = False self.poRadioButton.SetValue( True ) pdef.Rules = 1 pdef.MaxBiosMinVersion = 255 self.biosEdit.ChangeValue(str(pdef.MaxBiosMinVersion)) pdef.MaxSinitMinVersion = 255 self.sinitEdit.ChangeValue(str(pdef.MaxSinitMinVersion)) pdef.SinitMinVersion = 0 self.minSinitVersionEdit.ChangeValue(str(pdef.SinitMinVersion)) pdef.PolicyControl = 0 self.allowNPW.SetValue(False) self.sinitCapabilites.SetValue(False) self.auxDelete.SetValue(False) self.forceOwnerPolicyValue = False self.forcePsPconfValue = True self.forcePsOrPo.label = "Force PS PCONF" self.forcePsOrPo.SetValue(self.forcePsPconfValue) self.setPoRulesMode() self.anyRadioButton.SetValue( True ) pdef.PolicyType = 1 self.hashAlgEdit.Enable( False ) pdef.HashAlg = DEFINES.TPM_ALG_HASH['SHA256'] self.numOfListsLabel.Enable( False ) self.numOfListsEdit.Enable( False ) self.numOfListsEdit.ChangeValue("") self.viewListLabel.Enable( False ) self.viewListEdit.Enable( False ) self.addListButton.Enable( False ) self.deleteListButton.Enable( False ) self.biosEdit.ChangeValue("255") self.sinitEdit.ChangeValue("255") self.acmRevLabel.Enable( True ) self.biosEdit.Enable( True ) self.sinitEdit.Enable( True ) self.biosLabel.Enable( True ) self.sinitLabel.Enable( True ) pdef.LcpHashAlgMask = DEFINES.TPM_ALG_HASH_MASK['SHA256'] pdef.AuxHashAlgMask = DEFINES.TPM_ALG_HASH_MASK['SHA256'] checkedSign = [] for item in DEFINES.TPM_ALG_SIGN_MASK.keys(): if(pdef.LcpSignAlgMask & DEFINES.TPM_ALG_SIGN_MASK[item]): checkedSign.append(item) self.allowedSigSchemesEdit.SetCheckedStrings(checkedSign) checkedLCP = [] for item in DEFINES.TPM_ALG_HASH_MASK.keys(): if(pdef.LcpHashAlgMask & DEFINES.TPM_ALG_HASH_MASK[item]): checkedLCP.append(item) self.algAllowedForLcpEdit.SetCheckedStrings(checkedLCP) #self.algAllowedForLcpEdit.SetCheckedStrings("") #self.allowedSigSchemesEdit.SetCheckedStrings("") pdef.PolicyHash = 0 pdef.LastBuildDateStampYear = 2000 pdef.LastBuildDateStampMonth = 01 pdef.LastBuildDateStampDay = 01 pdef.LastBuildTimeStampHour = 00 pdef.LastBuildTimeStampMinute = 00 pdef.LastBuildTimeStampSecond = 00 pdef.LastBuildTimeStampLowByte = 00 pdef.CurrentListView = 0 pdef.NumLists = 0 # refresh GUI def loadAndDisplayPdefFile(self): """ loadAndDisplayPdefFile - get a saved pdef object from a PDEF file and update the policy panel""" global pdef file = None try: fullFileName = os.path.join(dirname, filename) file = open(fullFileName, 'r') self.StatusBar.SetStatusText("Opened file: %s" % (filename)) #TODO: WxPython: loadAndDisplayPdefFile - append current filename to the frame title instead showing in the StatusBar or add a widget? pdef = PDEF() pdef = pickle.load(file) # load pdef from file list.hideListPanel() print("loadDisplayPdefFile load PDEF") # DBGDBG except IOError: self.openError(filename, "IOError") #except PickleError: # not defined in this Python ... # self.openError(filename, "PickleError") except AttributeError: self.openError(filename, "AttributeError") except EOFError: self.openError(filename, "EOFError") except ImportError: self.openError(filename, "ImportError") except IndexError: self.openError(filename, "IndexError") except: self.openError(filename, "") # Note: list numbering is 1 based. If pdef.NumLists is less than 1, it must be policy type of Any listNum = 1 if pdef.NumLists >= listNum: list.loadAndDisplayPlistDefFile(file, wx, pdef, self.StatusBar, self.scrollableWindow) file.close() self.restorePanel() def openError(self, file, exception): """openError - tell user that open failed""" self.StatusBar.SetStatusText("Open of pdef file: %s failed. Exception: %s" % (file, exception)) print("Open of pdef file: %s failed. Exception: %s" % (file, exception)) # DBGDBG # # write the current PDEF object to a file # the policy panel should always display the PDEF object's state # # file format: # Header # memberName '=' 'value # ... # def writePdefFile(self) : """ writePdefFile - write the current PDEF object to a file""" global dirname, filename try: f = open(os.path.join(dirname, filename), 'w') except IOError: self.openError(filename, "IOError") #except PickleError: # not defined in this Python ... # self.openError(filename, "PickleError") except AttributeError: self.openError(filename, "AttributeError") except EOFError: self.openError(filename, "EOFError") except ImportError: self.openError(filename, "ImportError") except IndexError: self.openError(filename, "IndexError") except: self.openError(filename, "") pickle.dump(pdef, f) # write out the pdef object print("writePdefFile: file: %s" % (filename)) # DBGDBG #print("writePdefFile: Rules=%x, PolicyType=%x PolicyControl=%x, NumLists=%x, CurrentListView=%x, MaxBiosMinVersion=%x, MaxSinitMinVersion=%x" % # (pdef.Rules, pdef.PolicyType, pdef.PolicyControl, pdef.NumLists, pdef.CurrentListView, # pdef.MaxBiosMinVersion, pdef.MaxSinitMinVersion)) # DBGDBG # Write the PLIST_DEF's # pickle.dump of pdef should be sufficient to dump the entire structure. f.close() def checkModified(self): """checkModified - return True if the Policy, List or Element panels were modified, else False""" if(pdef.Modified == True): #print("checkModified - return PDEF was Modified" ) # DBGDBG return True elif(list.checkListModified(pdef) == True): #print("checkModified - return list was Modified" ) # DBGDBG return True else: #print("checkModified - return nothing Modified" ) # DBGDBG return False def showV31Gui(self, enable): if enable: self.ignorePsMle.Show() self.ignorePsPconf.Show() self.ignorePsStm.Show() else: self.ignorePsMle.Hide() self.ignorePsPconf.Hide() self.ignorePsStm.Hide() def restorePanel(self): """restorePanel - restore the policy panel""" print("restorePolicyPanel: Rules=%x, PolicyType=%x PolicyControl=%x, NumLists=%x, CurrentListView=%x, MaxBiosMinVersion=%x, MaxSinitMinVersion=%x" % (pdef.Rules, pdef.PolicyType, pdef.PolicyControl, pdef.NumLists, pdef.CurrentListView, pdef.MaxBiosMinVersion, pdef.MaxSinitMinVersion)) # DBGDBG if(pdef.Rules == DEFINES.PoRules): # 0=PS, 1=PO self.poRadioButton.SetValue(True) self.psRadioButton.SetValue(False) self.setPoRulesMode() else: self.psRadioButton.SetValue(True) self.poRadioButton.SetValue(False) self.setPsRulesMode() policyversion = str(pdef.PolVersionMajor)+'.'+str(pdef.PolVersionMinor) if policyversion in DEFINES.SUPPORTED_LCP_VERSION: self.versionEdit.SetStringSelection(policyversion) else: print("Invalid Policy version number %s" %(policyversion)) self.biosEdit.ChangeValue(str(pdef.MaxBiosMinVersion)) self.sinitEdit.ChangeValue(str(pdef.MaxSinitMinVersion)) self.minSinitVersionEdit.ChangeValue(str(pdef.SinitMinVersion)) if(pdef.PolicyControl & DEFINES.PolicyControlAllowNpwBitMask): self.allowNPW.SetValue(True) if(pdef.PolicyControl & DEFINES.PolicyControlPcr17BitMask): self.sinitCapabilites.SetValue(True) if(pdef.PolicyControl & DEFINES.PolicyControlForceOwnerBitMask): if(pdef.Rules == 0): # ps rule self.setPsRulesMode() else: self.setPoRulesMode() if(pdef.PolicyControl & DEFINES.PolicyControlAUXDeletionControl): self.auxDelete.SetValue(True) policyversion = str(pdef.PolVersionMajor)+'.'+str(pdef.PolVersionMinor) if policyversion == '3.0': self.showV31Gui(False) else: self.showV31Gui(True) if(pdef.PolicyType == DEFINES.ANY): self.anyRadioButton.SetValue( True ) self.listRadioButton.SetValue( False ) self.enableDisableListWidgets( False ) else: self.anyRadioButton.SetValue( False ) self.listRadioButton.SetValue( True ) self.enableDisableListWidgets( True ) try: # Set GUI for Hash Algorithm ComboBox hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == pdef.HashAlg)).next() self.hashAlgEdit.SetStringSelection(hashAlgName) except StopIteration: self.StatusBar.SetStatusText("HashAlg=%d for Hash Algorithm is not supported" % (pdef.HashAlg)) try: # Set GUI Algorithm for Auto-Promotion ComboBox hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH_MASK.items() if (val == pdef.AuxHashAlgMask)).next() self.algForApEdit.SetStringSelection(hashAlgName) except StopIteration: self.StatusBar.SetStatusText("HashAlg=%d for Auto-Promotion is not supported" % (pdef.AuxHashAlgMask)) checkedLCP = [] for item in DEFINES.TPM_ALG_HASH_MASK.keys(): if(pdef.LcpHashAlgMask & DEFINES.TPM_ALG_HASH_MASK[item]): checkedLCP.append(item) self.algAllowedForLcpEdit.SetCheckedStrings(checkedLCP) checkedSign = [] for item in DEFINES.TPM_ALG_SIGN_MASK.keys(): if(pdef.LcpSignAlgMask & DEFINES.TPM_ALG_SIGN_MASK[item]): checkedSign.append(item) self.allowedSigSchemesEdit.SetCheckedStrings(checkedSign) self.numOfListsEdit.ChangeValue(str(pdef.NumLists)) self.viewListEdit.ChangeValue(str(pdef.CurrentListView)) if(pdef.NumLists > 0): self.deleteListButton.Enable() self.viewListEdit.Enable() else: self.deleteListButton.Disable() self.viewListEdit.Disable() self.biosEdit.ChangeValue(str(pdef.MaxBiosMinVersion)) self.sinitEdit.ChangeValue(str(pdef.MaxSinitMinVersion)) pdef.Modified = False; # # save the current PDEF object to human readable textfile for printing # the policy panel should always display the PDEF object's state # # file format: # Header # memberName '=' 'value # ... # def printPdefFile(self): """ printPdefFile - save the current PDEF object to human readable textfile for printing""" global filename, dirname if(self.checkModified() == False): self.StatusBar.SetStatusText( "Current file not modified" ) return else: #wildcard = "PDEF text file (*.pdef.txt) | *.pdef.txt|" \ # "All Files (*.*) | *.*" #title = "Please specify a text file (.txt) to save the PDEF to. This file can be printed from your OS." #base = self.getBasePdefFile() #dlg = wx.FileDialog(self, title, dirname, base, wildcard, wx.SAVE|wx.OVERWRITE_PROMPT) #if dlg.ShowModal() == wx.ID_OK: # filename = dlg.GetFilename() # dirname = dlg.GetDirectory() self.printPdefTextFile() # # originally, filename had no extention so strip it off keeping the user supplied base name # filename, ext, ext1 = filename.rsplit('.', 1) #print("printPdefFile - done. filename=%s" % (filename)) # DBGDBG #dlg.Destroy() def printPdefTextFile(self): basefilename, ext = filename.rsplit('.', 1) textfile = utilities.formFileName(basefilename, "pdef.txt") self.StatusBar.SetStatusText( "Policy saved as text file: %s, which can be printed from your OS" % (textfile )) #print("printPdefTextFile: file: %s, PDEF object: %s" % (textfile, pdef)) # DBGDBG print("printPdefTextFile: file: %s" % (textfile)) # DBGDBG try: f = open(os.path.join(dirname, textfile), 'w') print("PDEF file: ", textfile, " written on: ", wx.Now(), file=f ) print("\n", file=f) # for readability print("FileTypeSignature", " = ", pdef.FileTypeSignature, file=f) print("DefCompany", " = ", pdef.DefCompany, file=f) print("StructVersion", " = ", pdef.StructVersion, file=f) print("MaxLists", " = ", pdef.MaxLists, file=f) print("MaxElements", " = ", pdef.MaxElements, file=f) print("MaxHashSize", " = ", pdef.MaxHashSize, file=f) print("MaxHashes", " = ", pdef.MaxHashes, file=f) print("MaxFileNameSize", " = ", pdef.MaxFileNameSize, file=f) print("ToolDate", " = ", pdef.ToolDate, file=f) print("ToolVersion", " = ", pdef.ToolVersionMajor, ".", pdef.ToolVersionMinor, sep='', file=f) # suppress separator so 2.2 print("Rules", " = ", pdef.Rules, file=f) print("Modified", " = ", pdef.Modified, file=f) print("PolVersion", " = ", pdef.PolVersionMajor, ".", pdef.PolVersionMinor, sep='', file=f) # suppress separator so 1.0 print("HashAlg", " = ", pdef.HashAlg, file=f) print("PolicyType", " = ", pdef.PolicyType, file=f) print("SinitMinVersion", " = ", pdef.SinitMinVersion, file=f) print("DataRevocationCounters", " = ", pdef.DataRevocationCounters, file=f) # this is a list! print("PolicyControl", " = ", pdef.PolicyControl, file=f) print("MaxSinitMinVersion", " = ", pdef.MaxSinitMinVersion, file=f) print("MaxBiosMinVersion", " = ", pdef.MaxBiosMinVersion, file=f) print("LcpHashAlgMask", " = ", pdef.LcpHashAlgMask, file=f) print("LcpSignAlgMask", " = ", pdef.LcpSignAlgMask, file=f) print("AuxHashAlgMask", " = ", pdef.AuxHashAlgMask, file=f) if(pdef.HashAlg == DEFINES.TPM_ALG_HASH_MASK['SHA256']): print("PolicyHash", " = ", pdef.PolicyHashSha256Hex, file=f) # need to print the hex hash elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH_MASK['SHA1']): print("PolicyHash", " = ", pdef.PolicyHashSha1Hex, file=f) # need to print the hex hash # make sure MM, DD, HH, MM and SS fields print as 2 digits with leading 0 ie YYMMDD and HHMMSS month = '%02d' % (pdef.LastBuildDateStampMonth) day = '%02d' % (pdef.LastBuildDateStampDay) print("LastBuildDateStamp (YYYYMMDD)", " = ", pdef.LastBuildDateStampYear, month, day, sep='', file=f) hour = '%02d' % (pdef.LastBuildTimeStampHour) minute = '%02d' % (pdef.LastBuildTimeStampMinute) second = '%02d' % (pdef.LastBuildTimeStampSecond) print("LastBuildTimeStamp (HHMMSS)", " = ", hour, minute, second, sep='', file=f) print("CurrentListView", " = ", pdef.CurrentListView, file=f) print("NumLists", " = ", pdef.NumLists, file=f) # Show summary: which lists have been added print("PolListInfo[0]", " = ", pdef.PolListInfo['0'], file=f) print("PolListInfo[1]", " = ", pdef.PolListInfo['1'], file=f) print("PolListInfo[2]", " = ", pdef.PolListInfo['2'], file=f) print("PolListInfo[3]", " = ", pdef.PolListInfo['3'], file=f) print("PolListInfo[4]", " = ", pdef.PolListInfo['4'], file=f) print("PolListInfo[5]", " = ", pdef.PolListInfo['5'], file=f) print("PolListInfo[6]", " = ", pdef.PolListInfo['6'], file=f) print("PolListInfo[7]", " = ", pdef.PolListInfo['7'], file=f) print("\n", file=f) # for readability # print each PLIST_DEF that has been added list.printPlistDefs(pdef, f) except IOError: self.StatusBar.SetStatusText("IOError") finally: f.close() def updateLastBuildDateAndTimeStamps(self): """updateLastBuildDateAndTimeStamps - update the LastBuildDateStamp and LastBuildTimeStamp pdef fields""" # update the LastBuild[Time,Date]Stamp's # Get a datetime object and convert each value to its decimal equivalent now = datetime.datetime.now() pdef.LastBuildDateStampYear = int('%04d' % (now.year)) # YYYY as decimal pdef.LastBuildDateStampMonth = int('%02d' % (now.month)) # MM as decimal pdef.LastBuildDateStampDay = int('%02d' % (now.day)) # DD as decimal pdef.LastBuildTimeStampHour = int('%02d' % (now.hour)) # HH as decimal pdef.LastBuildTimeStampMinute = int('%02d' % (now.minute)) # MM as decimal pdef.LastBuildTimeStampSecond = int('%02d' % (now.second)) # SS as decimal #print("updateLastBuildDateAndTimeStamps - YYYY=%04d, MM=%02d, DD=%02d, HH=%02d, MM=%02d, SS=%02d 00=%02d" % # (pdef.LastBuildDateStampYear, pdef.LastBuildDateStampMonth, pdef.LastBuildDateStampDay, # pdef.LastBuildTimeStampHour, pdef.LastBuildTimeStampMinute, # pdef.LastBuildTimeStampSecond, pdef.LastBuildTimeStampLowByte)) # DBGDBG def getBasePdefFile(self): """getBasePdefFile - get the current pdef file base or use default""" # use the current pdef file, if one has been specified file = self.pdefFileName.GetValue() if(file == 'None'): base = "NewPlatform" else: base, ext = file.rsplit('.', 1) return(base) ################# ## MyApp class ## ################# class MyApp(wx.App): def OnInit(self): """ onInit - wxWindows calls this method to initialize the application""" # Create an instance of our customized Frame class frame = MyFrame(None, -1, "TXT Policy Generator") frame.Show(True) # Tell wxWindows that this is our main window self.SetTopWindow(frame) # Return a success flag return True app = MyApp(0) # Create an instance of the application class #import wx.lib.inspection #wx.lib.inspection.InspectionTool().Show() app.MainLoop() # Tell it to start processing events #TODO: Med: Open tool by double clicking a .pdef file or dropping one on the tool - WxPython book p530 tboot-1.10.5/lcp-gen2/UserGuide.txt0000644000000000000000000003503314210363175015125 0ustar 00000000000000#This is a UserGuide for LCP v3 Creator LCP v3 Creation Tool User Guide 1. Introduction This document describes how to install and use the 2nd generation of Launch Control Policy creation tool for creating Intel® TXT launch control policies for use with TPM 2.0 family devices. This LCP tool can be used to build one or more Policy Definition (PDEF) files and, using a PDEF file, can create policy files for use with Intel TXT. Intel TXT launch control policy consists of NV Policy Data stored in the TPM NVRAM and a Policy List Structure file that is stored either in the BIOS flash ROM (for Platform Supplier policy) or in the boot directory of the target platform (for Platform Owner policy). This tool creates/edits a Policy Definition File (PDEF). The PDEF identifies files that contain the data for building the NV Policy Data and Data List Structure. All source data files must be in the working directory. The GUI updates the PDEF structure and when the user selects “BUILDâ€, the tool creates the policy files based on the information in the PDEF file. The tool allows the user to: - Open an existing PDEF file or create a new one. - Save the open definition to a new file name. - Build the NV Policy Data and Policy List Structure based on the open PDEF. The output files are: - *.txt – TPM NV Policy data in readable text format (for DOS provisioning tools) - *.pol – TPM NV Policy data in raw format for provisioning tools that take unformatted data. - *.dat – file that contains the associated Policy List Structure 2. Installation This tool is written in Python, so Python 2.7.x installation is needed to run the tool. Besides Python 2.7, following Python packages installation are required as well: - python-wxpython28 - M2Crypto - PyAsn1 3. Running the tool The tool provides a Graphical User Interface (GUI) to edit and create the launch control policies. The tool can be started by typing following command in a termainal from tool's working directory: ./TxtPolicyGen2.py 4. LCP Creation 4.1 Menu Bar The menu bar of the tool provides the 3 dropdown menus: File, Build, and Help 4.1.1 File Menu The FILE menu provides standard file operations of New; Open; Save; Save As; Print; Close. • New: Resets policy to the default policy and if the current policy had been modified, it prompts to save it to a file. • Open: allows you to open a previously created PDEF file to modify and/or build. • Save & Save As: allows you to save the PDEF file to the existing or a new file name respectively. • Print: Creates an ASCII printable file of the PDEF content that can be printed. Note that this command does NOT send the file to a printer. • Close: Exits the program and, if there were changes, prompts to save the PDEF file. 4.1.2 Build Menu The BUILD menu allows you to build the NV Policy Data file, the Policy List Structure file, or both. Note that a policy list structure file will not be built when PDEF Policy Type is ANY. 4.1.3 Help Menu The HELP menu provides information about the tool, key generation, command line options, and allows you to open this user guide. 4.2 Main Screen This screen edits the data that is to be placed in the TPM NV policy data. This tool does not write to the TPM, but it does create the data to be written to it. Other utilities, such as the TPM2 Provisioning tool can take this output and write the TPM NV index. 4.2.1 Selecting Rules The user selects either PS Policy Rules (for Platform Supplier – OEM) or PO Policy Rules (for platform Owner – OS/Datacenter). Various information and allowed actions will be updated based on this selection. Selecting the appropriate rules should be done first since it affects what can be selected and/or changed in policy definition. 4.2.2 Min SINIT Version This box allows the user to specify the minimum allowed version for the SINT ACM that will be allowed to perform a measured launch. 4.2.3 ACM Revocation Limits These values allow the user to limit ACM self-revocation for the BIOS ACM and SINIT ACM. These values specify the maximum version level that can be revoked. A value of 5 means that ACM versions up to 4 can be revoked, however versions 5 and above cannot be revoked. Thus, a value of zero prohibits ACM revocation and a value of 255 allows all revocations. These fields are only valid for PO Policy. 4.2.4 Control Options These check boxes allow the user to select various control options. Certain options will not be available depending on the rules selected. 4.2.5 Policy Type User selects if policy is ANY or LIST. When LIST is selected, the screen displays list information and allows the user to create up to 8 lists. Additionally, when LIST is selected, the build command will create a policy list structure. Note that for PS policy, the policy list structure needs to be included as part of the flash image and for PO policy, the policy list structure needs to be copied to the boot directory of the target platform(s). 4.2.6 Hash Algorithm Use this box to select the hash algorithm that will protect the policy list structure. This value is only used if Policy Type is LIST. It is recommended that this be the strongest algorithm supported by the tool. 4.2.7 Algorithm for Auto-Promotion Allows you to specify which hash algorithm the BIOS ACM uses for calculating the auto-promotion measurement. You must select one – even when Signed SBIOS Policy is used instead of Auto-Promotion. When there are both PS and PO policies, the selection in the PO policy takes precedence. 4.2.8 Algorithms Allowed for Launch Control Policy These check boxes allow you to select various hash algorithms that may be evaluated when the SINIT ACM processes LCP policy list structures. If an algorithm is not selected, then any element in the list using that element will be ignored. 4.2.9 Allowed Signature Schemes These check boxes allow you to select various signing schemes that will be allowed when the ACM processes policy list structures. If an algorithm is not selected, then measurements in any list signed using that scheme will be ignored. 4.2.10 Adding and Removing a List Before you can add a list, you must select Policy Type = LIST and then click the Add List button. If this is the first list, the window will expand to include the List dialogue. A policy may have up to 8 lists. The Number of Lists box indicates the total number of lists. When there is more than one list, select the list number you wish to view/edit via the View List box. To delete a list, select the list via the View List box and click the Delete List button. 4.2.10.1 Signing a List Each list may be signed or unsigned. For an unsigned list, set Signing Algorithm to “Noneâ€. Otherwise select the desired Signing Algorithm, specify the Key Size, and then the file names for the Public and Private Keys. Changing key size clears the key file names. Click HELP: Key Generation for information on how to generate signing keys. 4.2.10.2 List Revocation This only applies to signed lists. The tool automatically increments the Revocation Count field each time the list is successfully built (and there were changes). The Allowed box specifies the minimum Revocation Count that is allowed (to protect against unauthorized list roll-back) and its value is populated in the corresponding TPM NV Policy Revocation Counter array. When the Sync box is checked, the Allowed box will automatically track the Revocation Count. The RESET button will reset the Revocation Count to 0. This should only be used for pre-production testing. 4.2.11 Adding and Deleting an Element To add an element to the current list, click on the Add Element button. A dropdown menu appears and allows you to select the element type and hash algorithm. Only one of each combination is allowed in a list. That is, a policy may have at most one of each combination of Element Type-HashAlg. The Number of Elements box indicates the total number of elements in the selected list. Select the element you wish to view/edit via the View Element box. To delete an element, select the element via the View Element box and click the Delete Element button. 4.2.11.1 SBIOS Element This is an element that provides a list of valid measurements for the Stat-up BIOS Code. That is, the code that must be trusted to clear memory when there is a Reset Attack. This element is only valid in the PS Policy and typically it is only found in signed lists. The exception is when the element specifies only a Fallback Hash. You must specify a Fallback Hash, and if you don’t support BIOS fallback, then specify a null hash of the appropriate size to match the hash algorithm. There is only one Fallback Hash measurement and may be multiple SBIOS hash measurements. The Hash File List box allows you to add or remove known good SBIOS measurements by specifying the filename of the file containing the hash. Each time you build the PDEF, the tool will open the specified files and use their current content to build the policy list structure. If there are no SBIOS elements or if none of the SBIOS elements contain any SBIOS measurements (other than the fallback hash) then the BIOS ACM uses auto-promotion. When there is at least one SBIOS Element with at least one hash file listed, then the BIOS ACM does not use auto-promotion. 4.2.11.2 PCONF Element This is an element that provides a list of valid platform configuration measurements. Each PCONF measurement is a list of selected PCRs and their composite hash (in a structure referred to as a PCRINFO). You will need to use a tool such as PCRDump2 to create PCR dump files from the target platform(s). Each PCR dump file contains the PCR values for all 24 of the PCRs (for the bank specified by its hashing algorithm). However, the tool only allows selection of the first 8 (PCR0-7). A PO Policy has the option to override the PS Policy. When the Override PS Policy box is checked in the PO Policy, the SINIT ACM will not process any PCONF elements in the PS Policy and rely solely on PCONF elements in the PO Policy. The PCR File box allows you to add or remove known good PCONF measurements (i.e., PCRINFOs) by specifying the filename of the PCR Dump file and selecting the PCRs to include. The PCR Selection boxes allow you to specify which PCRs are evaluated. Click Add button to add a PCRINFO and select the PCR Dump filename. Next check the PCR Selection boxes for the PCR numbers you wish to include and then click Apply PCR Selection. To add another PCRINFO, repeat this procedure. Note that the information in the PCR File box indicates the selected PCRs and the PCR Dump filename. The tool allows each PCRINFO to have a different set of selected PCRs. To remove a PCONF PCRINFO from the element, you first select i the entry from the PCR File dropdown box and then click on Remove. When you build the PDEF, for each entry in the PCR File list, the tool will open the specified file, generate a composite hash using the selected PCRs, and build the PCRINFO including it in the policy list structure. Note: If there are no PCONF elements in the PO Policy, then the SINIT ACM allows any platform configuration. Typically, PCRINFOs in the PS Policy only specify PCR0. 4.2.11.3 MLE Element This is an element that provides a list of valid OS/VMM measurements. The OSV or VMV should provide a list of known good MLE measurements. A PO Policy has the option to override the PS Policy. When the Override PS Policy box is checked in the PO Policy, the SINIT ACM will not process any MLE elements in the PS Policy and rely solely on MLE elements in the PO Policy. The Hash File List box allows you to add or remove known good MLE measurements. Click Add to add a measurement by selecting the filename of the file containing the hash. Repeat to add additional measurements. To remove an MLE measurement from the element, select the filename from the Hash File List box and click Remove. Each time you build the PDEF, the tool will open the specified files and use their current content to build the policy list structure. If there are no MLE elements in the PO Policy, then the SINIT ACM allows any OS to perform the measured launch. 4.2.11.4 STM Element This is an element that provides a list of valid SMM Transfer monitor (STM) measurements. The platform vendor should provide a list of known good STM measurements. Note that this element is not used on servers and high end workstations. A PO Policy has the option to override the PS Policy. When this box is checked, the SINIT ACM will not process any STM elements in the PS Policy and rely solely on STM elements in the PO Policy. The Hash File List box allows you to add or remove known good STM measurements. Click Add to add a measurement and select the filename of the file containing the hash. Each time you build the PDEF, the tool will open the specified files and use their current content to build the policy list structure. To remove an STM measurement from the element, select the filename in the Hash File List box and click on Remove. 4.2.12 Saving the Definition File You can save the PDEF file using the FILE tab on the menu bar. Specify an appropriate filename and the tool saves the file with a file extension of *.pdef in your tool working directory. 4.2.13 Opening a Definition File You can open a saved PDEF file using the FILE tab on the menu bar. Click OPEN and select the filename. 4.2.14 Generating Policy files First open the desired PDEF file and, from the BUILD tab on the menu bar, select if you want to build either the NV Policy, the Policy Data File, or both. The tool will generate the NV Policy data in 2 different formats (for various provisioning tools - .dat & .txt) and builds the policy list structure as .dat. Troubleshooting - The tool can only be run from its working directory - It is preferred to run the tool as a non-root user - Create a new PDEF before editing the policy in tool's GUI tboot-1.10.5/lcp-gen2/asn1spec.py0000644000000000000000000000773614210363175014570 0ustar 00000000000000 from pyasn1.type import univ, namedtype, tag from pyasn1.codec.der import decoder as der_decoder #RFC2313 #RSAPrivateKey ::= SEQUENCE { # version Version, # modulus INTEGER, -- n # publicExponent INTEGER, -- e # privateExponent INTEGER, -- d # prime1 INTEGER, -- p # prime2 INTEGER, -- q # exponent1 INTEGER, -- d mod (p-1) # exponent2 INTEGER, -- d mod (q-1) # coefficient INTEGER -- (inverse of q) mod p #} class RSAPrivateKey(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('Version', univ.Integer()), namedtype.NamedType('modulus', univ.Integer()), namedtype.NamedType('publicExponent', univ.Integer()), namedtype.NamedType('privateExponent', univ.Integer()), namedtype.NamedType('prime1', univ.Integer()), namedtype.NamedType('prime2', univ.Integer()), namedtype.NamedType('exponent1', univ.Integer()), namedtype.NamedType('exponent2', univ.Integer()), namedtype.NamedType('coefficient', univ.Integer()) ) #RFC3447 #RSAPublicKey ::= SEQUENCE { # modulus INTEGER, -- n # publicExponent INTEGER -- e #} class RSAPublicKey(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('modulus', univ.Integer()), namedtype.NamedType('publicExponent', univ.Integer()) ) #RFC 5480 #AlgorithmIdentifier ::= SEQUENCE { # algorithm OBJECT IDENTIFIER, # parameters ANY DEFINED BY algorithm OPTIONAL #} class AlgorithmIdentifier(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('algorithm', univ.ObjectIdentifier()), namedtype.OptionalNamedType('parameters', univ.Any()) ) #RFC 5480 #SubjectPublicKeyInfo ::= SEQUENCE { # algorithm AlgorithmIdentifier, # subjectPublicKey BIT STRING #} class SubjectPublicKeyInfo(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('algorithm', AlgorithmIdentifier()), namedtype.NamedType('subjectPublicKey', univ.BitString()) ) #RFC 5912 #ECParameters ::= CHOICE { # namedCurve CURVE.&id({NamedCurve}) # -- implicitCurve NULL # -- implicitCurve MUST NOT be used in PKIX # -- specifiedCurve SpecifiedCurve # -- specifiedCurve MUST NOT be used in PKIX # -- Details for specifiedCurve can be found in [X9.62] # -- Any future additions to this CHOICE should be coordinated # -- with ANSI X.9. # } # class ECParameters(univ.Choice): componentType = namedtype.NamedTypes( namedtype.NamedType('namedCurve', univ.ObjectIdentifier()), namedtype.NamedType('implicitCurve', univ.Null()), namedtype.NamedType('specifiedCurve', univ.ObjectIdentifier()) ) #RFC 5915 #ECPrivateKey ::= SEQUENCE { # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), # privateKey OCTET STRING, # parameters [0] EXPLICIT ECParameters {{ NamedCurve }} OPTIONAL, # publicKey [1] EXPLICIT BIT STRING OPTIONAL #} # # PKIX compliant class ECPrivateKey(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('version', univ.Integer()), namedtype.NamedType('privateKey', univ.OctetString()), #namedtype.NamedType('ECParameters', ECParameters().subtype( # explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), namedtype.OptionalNamedType('ECParameters', univ.ObjectIdentifier().subtype( explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), namedtype.OptionalNamedType('publicKey', univ.BitString().subtype( explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))) ) #DigestInfo ::= SEQUENCE { # digestAlgorithm AlgorithmIdentifier, # digest OCTET STRING #} #ECDSASignature ::= SEQUENCE { # r INTEGER, # s INTEGER #} # class ECDSASignature(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('r', univ.Integer()), namedtype.NamedType('s', univ.Integer()) ) tboot-1.10.5/lcp-gen2/build.py0000644000000000000000000011071514210363175014142 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # TXT Policy Generator Tool # support for Building LCP_POLICY and LCP_POLICY_DATA Files # using print() built in function, disable print statement from __future__ import print_function from struct import * #import hashlib import binascii from defines import DEFINES from pdef import PDEF from util import UTILS utilities = UTILS() from LcpPolicy import * LcpPolicy = LCP_POLICY2() LcpPolicyData = LCP_POLICY_DATA2() ListMeasurements = ListMeasurements() # DIGEST ListMeasurements[PDEF.NumLists] try: import os import sys except ImportError: raise ImportError, "import OS failed" import array import M2Crypto from asn1spec import * class Build( object ): """build LCP_POLICY2 and LCP_POLICY_DATA2 Files""" filename = "MyPlatformXXXXXXXXXXXXX" dirname = os.getcwd() def __init__( self ): """Build - constructor""" pass # Build the .pol file # returns True if all went ok # returns False on error def buildRawLcpPolicyFile(self, pdef, statusBar): """buildRawLcpPolicyFile - build the raw format LCP_POLICY2 file (.pol)""" self.StatusBar = statusBar # if policy version is 3.0, clear bit positions for ignore PS elements policyversion = str(pdef.PolVersionMajor)+'.'+str(pdef.PolVersionMinor) if policyversion == '3.0': mask = DEFINES.PolicyControlIgnorePsMleBitMask | DEFINES.PolicyControlIgnorePsPconfBitMask | DEFINES.PolicyControlIgnorePsStmBitMask pdef.PolicyControl &= ~mask # pack the LCP_POLICY2 struct [without the hash] into a binary string ready for the LCP_POLICY2 file packedLcpPolicy = pack(LcpPolicy.LcpPolicyFormatStringNoHash, pdef.PolVersionMinor, pdef.PolVersionMajor, pdef.HashAlg, pdef.PolicyType, pdef.SinitMinVersion, pdef.DataRevocationCounters[0], pdef.DataRevocationCounters[1], pdef.DataRevocationCounters[2], pdef.DataRevocationCounters[3], pdef.DataRevocationCounters[4], pdef.DataRevocationCounters[5], pdef.DataRevocationCounters[6], pdef.DataRevocationCounters[7], pdef.PolicyControl, pdef.MaxSinitMinVersion, pdef.MaxBiosMinVersion, pdef.LcpHashAlgMask, pdef.LcpSignAlgMask, pdef.AuxHashAlgMask, 0) # reuse the base name [with .pol extension] and don't prompt for a file name again basefilename, ext = self.filename.rsplit('.', 1) #polfilename = utilities.formFileName(basefilename, "pol") polfilename = ".".join([basefilename, 'pol']) print("buildRawLcpPolicyFile: creating Text LCP_POLICY file %s" % (polfilename)) # DBGDBG # write the raw LCP_POLICY file # 1st write the struct, then write the hash from pdef.PolicyHash try: f = open(os.path.join(self.dirname, polfilename), 'wb') print(packedLcpPolicy, end='', file=f ) # suppress EOL (0x0a) try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == pdef.HashAlg)).next() # If PolicyType==ANY, haven't updated pdef.PolicyHash (since there were no lists to process) # In that case, write a hash of all 0's if(pdef.PolicyType == DEFINES.ANY): # Pack hash value which is 0 for PolicyType of ANY b = bytes() pdef.PolicyHash = b.join(pack('B', 0) for i in range(DEFINES.DIGEST_SIZE[hashAlgName])) else: # Write packed hash value to .pol file. print(pdef.PolicyHash, end='', file=f ) except StopIteration: # pdef.HashAlg value is not found in DEFINES.TPM_ALG_HASH list self.StatusBar.SetStatusText("Aborting build, Hash Algorithm %d is not supported." % (pdef.HashAlg)) print("buildRawLcpPolicyFile: ANY - aborting - Hash Algorithm %d is not supported." % (pdef.HashAlg)) # DBGDBG f.close() return False # If PolicyType==ANY, haven't updated pdef.PolicyHash (since there were no lists to process) # In that case, write a hash of all 0's #if(pdef.PolicyType == DEFINES.ANY): # # Pack hash value which is 0 for PolicyType of ANY # if (hashAlgName != None): # b = bytes() # pdef.PolicyHash = b.join(pack('B', 0) for i in range(DEFINES.DIGEST_SIZE[hashAlgName])) # else: # self.StatusBar.SetStatusText("Aborting build, Hash Algorithm %d is not supported." % (pdef.HashAlg)) # print("buildRawLcpPolicyFile: ANY - aborting - Hash Algorithm %d is not supported." % (pdef.HashAlg)) # DBGDBG # f.close() # return False #if(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # pdef.PolicyHashSha1 = pack("20B", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) #elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # pdef.PolicyHashSha256 = pack("32B", 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) #elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA384']): # pdef.PolicyHashSha384 = pack("40B", 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,0,0,0,0,0,0,0,0) #elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SM3']): # pdef.PolicyHashSm3 = pack("32B", 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) #else: # self.StatusBar.SetStatusText("Aborting build, Hash Algorithm %d is not supported." % (pdef.HashAlg)) # print("buildRawLcpPolicyFile: ANY - aborting - Hash Algorithm %d is not supported." % (pdef.HashAlg)) # DBGDBG # f.close() # return False # Pack hash value which is 0 for PolicyType of ANY #if (hashAlgName != None): # # Write packed hash value to .pol file. # print(pdef.PolicyHash, end='', file=f ) #else: # don't hit the above else case if policyType=LIST # self.StatusBar.SetStatusText("Aborting build, Hash Algorithm %d is not supported." % (pdef.HashAlg)) # print("buildRawLcpPolicyFile: LIST - aborting - Hash Algorithm %d is not supported." % (pdef.HashAlg)) # DBGDBG # f.close() # return False #if(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # print(pdef.PolicyHashSha1, end='', file=f ) #elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # print(pdef.PolicyHashSha256, end='', file=f ) #else: # don't hit the above else case if policyType=LIST # self.StatusBar.SetStatusText("Aborting build, Hash Algorithm %d is not supported." % (pdef.HashAlg)) # print("buildRawLcpPolicyFile: LIST - aborting - Hash Algorithm %d is not supported." % (pdef.HashAlg)) # DBGDBG # f.close() # return False except IOError: print ("IOError writing raw LCP_POLICY file %s" % (polfilename)) finally: f.close() print("buildRawLcpPolicyFile: Raw LCP_POLICY file %s built" % (polfilename)) # DBGDBG # originally, filename had no extention so strip it off #self.filename, ext = self.filename.rsplit('.', 1) return True def buildTxtLcpPolicyFile(self, pdef): """buildTxtLcpPolicyFile - build the text format LCP_POLICY2 file""" # reuse the base name [with .txt extention] and don't prompt for a file name again basefilename, ext = self.filename.rsplit('.', 1) txtfilename = utilities.formFileName(basefilename, "txt") #self.filename = utilities.formFileName(self.filename, "txt") print("buildTxtLcpPolicyFile: creating Text LCP_POLICY2 file %s" % (txtfilename)) # DBGDBG try: f = open(os.path.join(self.dirname, txtfilename), 'w') # suppress separator with sep='' # use 'fmt' % (value) to prepend 0's to value print("#Policy Data", file=f) version = '%02d%02d' % (pdef.PolVersionMajor, pdef.PolVersionMinor) print("word=", version, "\t\t# Version", sep='', file=f) hashAlg = '%04d' % (pdef.HashAlg) print("word=", hashAlg, "\t\t# Hash Alg (4=Sha1[20], 11=Sha256[32]", sep='', file=f) policyType = '%02d' % (pdef.PolicyType) print("byte=", policyType, "\t\t\t# PolicyType (0 = LIST, 1 = ANY)", sep='', file=f) sinitMinVersion = '%02d' % (pdef.SinitMinVersion) print("byte=", sinitMinVersion, "\t\t\t# SinitMinVersion", sep='', file=f) i = 0 while(i < pdef.MaxLists): dataRevCnt = '%04d' % (pdef.DataRevocationCounters[i]) print("word=", dataRevCnt, "\t\t# DataRevocationCounters[", i, "]", sep='', file=f) i += 1 policyControl = '0x%08x' % (pdef.PolicyControl) print("dword=", policyControl, "\t# PolicyControl (Bit 1=Allow NPW, 2=PCR17, 3=Force Owner 15=Aux Delete)", sep='', file=f) maxSinitMinVersion = '%02d' % (pdef.MaxSinitMinVersion) print("byte=", maxSinitMinVersion, "\t\t\t# MaxSinitMinVersion", sep='', file=f) maxBiosMinVersion = '%02d' % (pdef.MaxBiosMinVersion) print("byte=", maxBiosMinVersion, "\t\t\t# MaxBiosMinVersion", sep='', file=f) lcpHashAlgMask = '%04d' % (pdef.LcpHashAlgMask) print("word=", lcpHashAlgMask, "\t\t# LcpHashAlgMask", sep='', file=f) lcpSignAlgMask = '%04d' % (pdef.LcpSignAlgMask) print("dword=", lcpSignAlgMask, "\t\t# LcpSignAlgMask", sep='', file=f) auxHashAlgMask = '%04d' % (pdef.AuxHashAlgMask) print("word=", auxHashAlgMask, "\t\t# AuxHashAlgMask", sep='', file=f) reserved = '%02d' % (0) print("byte=", reserved, "\t\t\t# Reserved", sep='', file=f) #if(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # print("byte=", pdef.PolicyHashSha256Hex, " # Hash", sep='', file=f) # need to print the hex hash #elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # print("byte=", pdef.PolicyHashSha1Hex, " # Hash", sep='', file=f) # need to print the hex hash print("byte=", binascii.b2a_hex(pdef.PolicyHash), " # Hash", sep='', file=f) # need to print the hex hash except IOError: print ("IOError writing file %s" % (txtfilename)) finally: f.close() print("buildTxtLcpPolicyFile: Text LCP_POLICY file %s built" % (txtfilename)) # DBGDBG # originally, filename had no extention so strip it off #self.filename, ext = self.filename.rsplit('.', 1) # LCP2 does not generate an XML output file - so no buildXmlLcpPolicyFile() # If no error, return True, else False # Build can fail reading hash or pcr files, or if no public or private key file was selected # def buildLcpPolicyDataStruct(self, pdef, statusBar): """buildLcpPolicyDataStruct - create a LCP_POLICY_DATA struct including calculating the PolicyHash""" global LcpPolicyData self.StatusBar = statusBar #LcpPolicy = LCP_POLICY2() LcpPolicyData = LCP_POLICY_DATA2() # ListMeasurements - object to hold ListMeasurements[pdef.NumLists] # LcpPolicyData - object for LCP_POLICY_DATA # build file header: FileSignature,0,0,0,NumLists LcpPolicyData.NumLists = pdef.NumLists print("buildLcpPolicyDataStruct: LCP_POLICY_DATA: FileSignature=%s, NumLists=%d" % (LcpPolicyData.FileSignature, LcpPolicyData.NumLists)) # DBGDBG # For each list # If 1st list, build the list header: ListVersion, 0, SigAlgorithm, PolicyElementsSize=0 # build the elements # if List is unsigned, hash the list # else list is signed so build the signature block ie: # Done with this list # Done with all the lists policyElementsSize = 0 # cumulative size of all the elements in this list listCnt = 0 listCntStr = str(listCnt) while(listCnt < pdef.NumLists): thisPdefList = pdef.PolListInfo[listCntStr] thisPolicyList = LcpPolicyData.PolicyLists[listCntStr] # build the LCP_POLICY_LIST.PolicyList[N] header from pdef.PolListInfo[N] thisPolicyList.VersionMajor = thisPdefList.ListVersionMajor thisPolicyList.VersionMinor = thisPdefList.ListVersionMinor thisPolicyList.SigAlgorithm = thisPdefList.SigAlgorithm thisPolicyList.PolicyElementsSize = 0 # TBD # if the list is signed, make sure that a public and private key file was specified # otherwise abort the build #if(thisPdefList.SigAlgorithm == DEFINES.LCP_POLSALG_RSA_PKCS_15): # TODO: add external signature support #if(thisPdefList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']): if thisPdefList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['NULL']: # Not Signing.. pass elif thisPdefList.SigAlgorithm in DEFINES.TPM_ALG_SIGN.values(): if((thisPdefList.PubKeyFile == "") or (thisPdefList.PvtKeyFile == "") and not thisPdefList.PvtKeyFileIsSignature): self.StatusBar.SetStatusText("Build failed: does not have both a public and private key file selected") print("buildLcpPolicyDataStruct failed - see status bar") # DBGDBG return False else: # What about invalid signature algorithms. print("ERROR: undefined signature algorithm") pass #IncludeElement = utilities.getIncludeElement(thisPdefList) #i=0 #flag = False #while(i < len(IncludeElement)): # if(IncludeElement[i] == True): # flag = True # i += 1 # if there are elements to build, then build them and update PolicyElementsSize #if(flag == True): if len(thisPdefList.ElementDefData): thisPolicyList.PolicyElementsSize = self.buildListElements(pdef, thisPdefList, thisPolicyList, listCnt) # check for errors building the elements, i.e. reading the hash or pcr files if(thisPolicyList.PolicyElementsSize == 0): print("buildLcpPolicyDataStruct failed: PolicyElementsSize=0") # DBGDBG return False if not self.hashListOrBuildSignatureBlock(pdef, thisPdefList, thisPolicyList, listCnt): return False print("buildLcpPolicyDataStruct: LCP_POLICY_LIST: Version=%x.%x, SigAlgorithm=%d, PolicyElementsSize=%d" % (thisPolicyList.VersionMajor, thisPolicyList.VersionMinor, thisPolicyList.SigAlgorithm, thisPolicyList.PolicyElementsSize)) # DBGDBG thisPdefList.ListModified = False listCnt += 1 listCntStr = str(listCnt) try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == pdef.HashAlg)).next() except StopIteration: print("Aborting build, Hash Algorithm %d is not supported" % (pdef.HashAlg)) return False # Calculate list measurements - hash ListMeasurements[] using pdef.HashAlg hash = M2Crypto.EVP.MessageDigest(hashAlgName.lower()) listCnt = 0 while(listCnt < pdef.NumLists): #if(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # thisHash = ListMeasurements.hashes[str(listCnt)] #elif(pdef.HashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # thisHash = ListMeasurements.hashes32[str(listCnt)] thisHash = ListMeasurements.hashes[str(listCnt)] hash.update(bytes(thisHash)) #print("buildLcpPolicyDataStruct: ListMeasurement[%d] hash=%s" % (listCnt, thisHash)) # DBGDBG print("buildLcpPolicyDataStruct: ListMeasurement[%d] hashed" % (listCnt)) # DBGDBG listCnt += 1 # save to pdef.PolicyHash pdef.PolicyHash = hash.digest() #print("buildLcpPolicyDataStruct - hash size=%d hexdigest=%s" % (hash.digest_size, hash.hexdigest())) # DBGDBG pdef.Modified = False return True # Build the elements and return their size # If an error occurred, size = 0 # Build can fail reading hash or pcr files # def buildListElements(self, pdef, thisPdefList, thisPolicyList, listCnt): """buildElements - build this lists elements""" func = 'buildListElements' print("%s: list %d - MLE, PCONF then SBIOS" % (func, listCnt)) # DBGDBG policyElementsSize = 0 thisElementSize = 0 # Sort element in this order [MLE, STM, SBIOS, PCONF] from [SHA512... SHA1, SHA1-LEGACY] sortedPdefList = [] mlelist = [element for element in thisPdefList.ElementDefData if 'MLE' in element.Name] sortedPdefList += sorted(mlelist, key=lambda x: x.HashAlg, reverse=True) stmlist = [element for element in thisPdefList.ElementDefData if 'STM' in element.Name] sortedPdefList += sorted(stmlist, key=lambda x: x.HashAlg, reverse=True) sbioslist = [element for element in thisPdefList.ElementDefData if 'SBIOS' in element.Name] sortedPdefList += sorted(sbioslist, key=lambda x: x.HashAlg, reverse=True) pconflist = [element for element in thisPdefList.ElementDefData if 'PCONF' in element.Name] sortedPdefList += sorted(pconflist, key=lambda x: x.HashAlg, reverse=True) elementCnt = 0 for element in sortedPdefList: print("building Element %s" %(element.Name)) # call the element's build function to build the elements of this policy thisElementSize = element.build(thisPdefList, thisPolicyList.PolicyElements, pdef.WorkingDirectory) policyElementsSize += thisElementSize elementCnt += 1 print("%s: list %d - elementCnt=%d, policyElementsSize=0x%x" % (func, listCnt, elementCnt, policyElementsSize)) # DBGDBG return(policyElementsSize) # Build the .dat file def buildLcpPolicyDataFile(self, pdef): """buildLcpPolicyDataFile - build the LCP_POLICY_DATA2 file (.dat)""" func = 'buildLcpPolicyDataFile' # reuse the base name [with .dat extention] and don't prompt for a file name again basefilename, ext = self.filename.rsplit('.', 1) datfilename = utilities.formFileName(basefilename, "dat") #self.filename = utilities.formFileName(self.filename, "dat") #lcpPolicyDataHeader = self.packLcpPolicyDataHeader() lcpPolicyDataHeader = LcpPolicyData.pack() # write the LCP_POLICY_DATA header to the .dat file: f # write the data to be signed to tmpFile: tmp # tmpFile = "tmpLcpPolicyList.tmp" try: f = open(os.path.join(self.dirname, datfilename), 'wb') print(lcpPolicyDataHeader, end='', file=f ) # suppress EOL (0x0a) except IOError: self.StatusBar.SetStatusText("IOError writing raw LCP_POLICY_DATA file %s" % (datfilename)) return # For each List in LcpPolicyData.PolicyLists[] print("buildLcpPolicyDataFile: creating LCP_POLICY_DATA file %s" % (datfilename)) # DBGDBG listCnt = 0 listCntStr = str(listCnt) while(listCnt < pdef.NumLists): try: tmp = open(os.path.join(self.dirname, tmpFile), 'wb') except IOError: self.StatusBar.SetStatusText("IOError opening tempFile %s" % (tmpFile)) return print("buildLcpPolicyDataFile: processing list %d of %d" % (listCnt, pdef.NumLists)) # DBGDBG thisPolicyList = LcpPolicyData.PolicyLists[listCntStr] #lcpPolicyListHeader = self.packLcpPolicyListHeader(thisPolicyList) lcpPolicyListHeader = thisPolicyList.pack() # There can be 1 element of each type of each hash algorithm, See LCP_POLICY_LIST2::PolicyElements[] lcpPolicyListElement = [None, None, None, None, None, None, None, None] # pack this list's elements, if they exist i=0 numElements = len(thisPolicyList.PolicyElements) while(i < numElements): #print("%s - checking if PolicyElement %d of %d exists" % (func, i, numElements)) # DBGDBG if(thisPolicyList.PolicyElements[i] != None): print("%s - packing PolicyElement %d of %d" % (func, i, numElements)) # DBGDBG #lcpPolicyListElement[i] = self.packLcpPolicyElement(pdef, str(listCnt), i, thisPolicyList.PolicyElements[i]) lcpPolicyListElement[i] = thisPolicyList.PolicyElements[i].pack() else: break # done after all existing elements are packed i += 1 # write this LCP_POLICY_LIST to the .dat file # 1st write the LcpPolicyListHeader, # then write the elements and optionally the signature (if list is signed) # try: print(lcpPolicyListHeader, end='', file=f ) print(lcpPolicyListHeader, end='', file=tmp ) # print the this list's elements, if they exist i=0 while(i < numElements): #print("%s - checking if PolicyElement %d of %d was packed" % (func, i, numElements)) # DBGDBG if(lcpPolicyListElement[i] != None): print("%s - writing PolicyElement %d of %d to the file" % (func, i, numElements)) # DBGDBG print(lcpPolicyListElement[i], end='', file=f ) print(lcpPolicyListElement[i], end='', file=tmp ) i += 1 except IOError: print ("IOError writing raw LCP_POLICY_DATA file %s" % (datfilename)) f.close() return # if list is signed, now that we have formed all the binary data, it can be signed # and the LCP_SIGNATURE object can be written to the file # # The RSA signature is calculated over the entire LCP_POLICY_LIST struct, # including the Signature member, EXCEPT for the SigBlock # #if(thisPolicyList.SigAlgorithm == DEFINES.LCP_POLSALG_RSA_PKCS_15): if(thisPolicyList.SigAlgorithm != DEFINES.TPM_ALG_SIGN['NULL']): print("buildLcpPolicyDataFile: sign list %d" % (listCnt)) # DBGDBG self.signThisList(pdef, listCntStr, thisPolicyList, f, tmp, tmpFile) listCnt += 1 listCntStr = str(listCnt) f.close() print("buildLcpPolicyDataFile: LCP_POLICY_DATA file %s built" % (datfilename)) # DBGDBG def signThisList(self, pdef, listCntStr, thisPolicyList, f, tmp, tmpFile): """signThisList - form the signature of the specified list and write it to the specified files""" # get the private key from its file thisPdefList = pdef.PolListInfo[listCntStr] signAlgStr = "" try: signAlgStr = (key for key,val in DEFINES.TPM_ALG_SIGN.items() if val == thisPdefList.SigAlgorithm).next() except StopIteration: print ("Unsupported signature algorithm (%d)" %(thisPdefList.SigAlgorithm)) return # pack the LCP_SIGNATURE2 object except for the PublicKeyValue and SigBlock and write it to the file # those 2 member's size depends on keySize so they are written separately lcpSignature = thisPolicyList.Signature.pack() print(lcpSignature, end='', file=f ) print(lcpSignature, end='', file=tmp ) # Append Public key to signature block. if 'RSA' in signAlgStr: print(thisPolicyList.Signature.PubkeyValue, end='', file=f) print(thisPolicyList.Signature.PubkeyValue, end='', file=tmp) else: # ECC print(thisPolicyList.Signature.Qx, end='', file=f) print(thisPolicyList.Signature.Qx, end='', file=tmp) print(thisPolicyList.Signature.Qy, end='', file=f) print(thisPolicyList.Signature.Qy, end='', file=tmp) tmp.close() # done writing to tmp # read back the list data from the tmp file so it can be hashed and signed tmp = open(os.path.join(self.dirname, tmpFile), 'rb') tmp.seek (0, os.SEEK_END) listFileSize = tmp.tell () tmp.seek (0, os.SEEK_SET) # back to the beginning tmpListData = array.array ("B") # Load file into data array try: tmpListData.fromfile (tmp, listFileSize) except: self.StatusBar.SetStatusText("Error reading list data from tmp file") print("signThisList: ******Error reading list data from tmp file!!!!!!" ) # DBGDBG ****** tmp.close() return tmp.close() print("signThisList: hashing %d bytes from %s" % (listFileSize, tmpFile)) # DBGDBG # hash the list and sign the hash signatureBE = None hashAlgName = "" try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == thisPdefList.sigAlgorithmHash)).next() except StopIteration: self.StatusBar.SetStatusText("Aborting build, Hash Algorithm %d is not supported." % (thisPdefList.sigAlgorithmHash)) print("signThisList: aborting - Hash Algorithm %d is not supported." % (thisPdefList.sigAlgorithmHash)) # DBGDBG return h = None # set hash value to null first MsgDigest = M2Crypto.EVP.MessageDigest(hashAlgName.lower()) MsgDigest.update(tmpListData) h = MsgDigest.digest() # Output hash for each list to a file for CA signing basefilename, ext = self.filename.rsplit('.', 1) hashfilename = basefilename + '_list' + listCntStr + '.hash' hashout = open(os.path.join(self.dirname, hashfilename), 'wb') hashout.write(h) hashout.close() # Output list raw binary output to a file for CA hashing and signing listbinfilename = basefilename + '_list' + listCntStr + '.bin' listbinout = open(os.path.join(self.dirname, listbinfilename), 'wb') listbinout.write(tmpListData) listbinout.close() # Write signature data. if thisPdefList.PvtKeyFileIsSignature: sig_str = "" if thisPdefList.PvtKeyFile != "": # Load signature using the file in private key fsig = open(os.path.join(self.dirname, thisPdefList.PvtKeyFile), 'rb') fsig.seek(0, 2) size = fsig.tell() fsig.seek(0, 0) sig_array = array.array('B') sig_array.fromfile(fsig, size) sig_str = sig_array.tostring() fsig.close() else: # if no file defined, then it's the first pass, before the list is signed by certificate authority(CA) pass if 'RSA' in signAlgStr: signatureBE = sig_str # byte reverse the signature, i.e. convert from big to little-endian signatureLE = signatureBE[::-1] thisPolicyList.Signature.SigBlock = signatureLE #print("signThisList: LCP_POLICY_LIST %d sigLen=0x%x sig=\n%s" % (listCnt, len(signature), signature)) # DBGDBG # write the LCP_SIGNATURE.SigBlock object to the file print(signatureLE, end='', file=f ) print("signThisList: Finished writing signature for list %d" % (int(listCntStr))) # DBGDBG else: # ECC signatures signature, substrate = der_decoder.decode(sig_str, asn1Spec=ECDSASignature()) ri = signature.getComponentByName('r') si = signature.getComponentByName('s') roctet = univ.OctetString(hexValue=format(int(ri), '0x')) soctet = univ.OctetString(hexValue=format(int(si), '0x')) rBE = roctet.asNumbers() sBE = soctet.asNumbers() rLE = rBE[::-1] sLE = sBE[::-1] thisPolicyList.Signature.r = rLE thisPolicyList.Signature.s = sLE # write the LCP_SIGNATURE.SigBlock object to the file print(rLE, end='', file=f ) print(sLE, end='', file=f ) else: # Read Private Key from file # then sign the list #key = RSA.importKey(open(os.path.join(self.dirname, thisPdefList.PvtKeyFile)).read()) key = None mb = None with open(os.path.join(self.dirname, thisPdefList.PvtKeyFile), 'rb') as kf: mb = M2Crypto.BIO.MemoryBuffer(kf.read()) if mb: if 'RSA' in signAlgStr: key = M2Crypto.RSA.load_key_bio(mb) elif 'EC' in signAlgStr: # if ECC algorithm key = M2Crypto.EC.load_key_bio(mb) else: print("DEBUG: error load key") kf.close() #print("signThisList: LCP_POLICY_LIST %s pvt key=\n%s" % (listCntStr, key)) # DBGDBG if 'RSA' in signAlgStr: #signer = PKCS1_v1_5.new(key) #signatureBE = signer.sign(h) signatureBE = key.sign(h, hashAlgName.lower()) # byte reverse the signature, i.e. convert from big to little-endian signatureLE = signatureBE[::-1] thisPolicyList.Signature.SigBlock = signatureLE #print("signThisList: LCP_POLICY_LIST %d sigLen=0x%x sig=\n%s" % (listCnt, len(signature), signature)) # DBGDBG # write the LCP_SIGNATURE.SigBlock object to the file print(signatureLE, end='', file=f ) else: # ECC signatures r, s = key.sign_dsa(h) #print("DEBUG: ECC signature size r(%d) s(%d)" %(len(rBE), len(sBE))) length = int(thisPdefList.KeySize)/8 rBE = r[-length:] sBE = s[-length:] rLE = rBE[::-1] sLE = sBE[::-1] thisPolicyList.Signature.r = rLE thisPolicyList.Signature.s = sLE # write the LCP_SIGNATURE.SigBlock object to the file print(rLE, end='', file=f ) print(sLE, end='', file=f ) print("signThisList: Finished writing signature for list %d" % (int(listCntStr))) # DBGDBG def packLcpSignatureHdr(self, lcpSignature): """packLcpSignature - pack this LCP_SIGNATURE object except its SigBlock member ad return the packed data""" # Note - The public key size in the pdef is the number of bits (1024, 2048, 3072) # while LCP_SIGNATURE.PublicKeySize is the number if bytes, hence the /8 below return(pack(lcpSignature.LcpSignatureHdrFormatString, lcpSignature.RevocationCounter, lcpSignature.PubkeySize/8)) def hashListOrBuildSignatureBlock(self, pdef, thisPdefList, thisPolicyList, listCnt) : """hashListOrBuildSignatureBlock - if list unsigned then hash it, if signed build the signature block""" #print("hashListOrBuildSignatureBlock") # DBGDBG if(thisPdefList.SigAlgorithm in DEFINES.TPM_ALG_SIGN.values()): #if(thisPdefList.SigAlgorithm == DEFINES.LCP_POLSALG_NONE): if(thisPdefList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['NULL']): if(not self.hashThisList(pdef, thisPdefList, thisPolicyList, listCnt)): return False #elif(thisPdefList.SigAlgorithm == DEFINES.LCP_POLSALG_RSA_PKCS_15): #elif(thisPdefList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']): else: # Get the key from the file again in case it was replaced type = DEFINES.KEY_FILE_TYPE['PUBLIC_RSASSA'] # once the entire file name is entered, verify it, else clear it if(thisPdefList.PubKeyFile.endswith(".pem")): if thisPdefList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']: type = DEFINES.KEY_FILE_TYPE['PUBLIC_RSASSA'] elif thisPdefList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['ECDSA']: type = DEFINES.KEY_FILE_TYPE['PUBLIC_ECDSA'] pubkeyfile = os.path.join(self.dirname, thisPdefList.PubKeyFile) if not utilities.verifyKeyFile(pubkeyfile, type, thisPdefList): print("Invalid Public Key file %s" %(thisPdefList.PubKeyFile)) return False self.createSignatureBlock(pdef, thisPdefList, thisPolicyList, listCnt) else: self.StatusBar.SetStatusText("hashListOrBuildSignatureBlock: aborting unknown pdef.SigAlgorithm=%x" % (thisPdefList.SigAlgorithm)) return False return True def hashThisList(self, pdef, thisPdefList, thisPolicyList, listCnt): """hashThisList - when building an unsigned list, calcuate its hash""" func = 'hashThisList' print("%s: list %d of %d" % (func, listCnt+1, pdef.NumLists)) # for each list in PolicyLists[] # hash the list header # hash the list's PolicyElements[] # copy the hash to ListMeasurements[i] # Note: hash of the 1st list does NOT include the hash of the LCP_POLICY_DATA header try: hashAlgString = (key for key,val in DEFINES.TPM_ALG_HASH.items() if val == pdef.HashAlg).next() except StopIteration: self.StatusBar.SetStatusText("Hash Algorithm %d is not supported." % (pdef.HashAlg)) print("%s: HashAlg %d is not supported" % (func, pdef.HashAlg)) return False if hashAlgString == 'NULL': # Nothing to do return True else: hash = M2Crypto.EVP.MessageDigest(hashAlgString.lower()) #lcpPolicyListHeader = self.packLcpPolicyListHeader(thisPolicyList) lcpPolicyListHeader = thisPolicyList.pack() hash.update(lcpPolicyListHeader) # hash this list's PolicyElements[], if they exist # Note: if list has no elements just hash the PolicyList header i=0 numElements = len(thisPolicyList.PolicyElements) while(i < numElements): print("%s - checking if PolicyElement %d of %d exists" % (func, i, numElements)) # DBGDBG if(thisPolicyList.PolicyElements[i] != None): print("%s - packing PolicyElement %d of %d" % (func, i, numElements)) # DBGDBG #lcpPolicyListElement = self.packLcpPolicyElement(pdef, str(listCnt), i, thisPolicyList.PolicyElements[i]) lcpPolicyListElement = thisPolicyList.PolicyElements[i].pack() hash.update(lcpPolicyListElement) else: break # done after all existing elements are packed i += 1 ListMeasurements.hashes[str(listCnt)] = hash.digest() #print("hashThisList - ListMeasurements[%d] hash size=%d hexdigest=%s" % # (listCnt, hash.digest_size, hash.hexdigest())) # DBGDBG return True def createSignatureBlock(self, pdef, thisPdefList, thisPolicyList, listCnt): """createSignatureBlock - when building a signed list, form its signature block""" try: signAlgStr = (key for key,val in DEFINES.TPM_ALG_SIGN.items() if val == thisPolicyList.SigAlgorithm).next() except StopIteration: print ("ERROR, Signing algorithm not supported (%d)" %(thisPolicyList.SigAlgorithm)) return if 'RSA' in signAlgStr: # Create signature block for RSA signature structure thisPolicyList.Signature = LCP_RSA_SIGNATURE() # Copy public key to Policy data structure thisPolicyList.Signature.PubkeyValue = thisPdefList.PubKeyData else: # Create signature block for ECC signature structure thisPolicyList.Signature = LCP_ECC_SIGNATURE() # Copy public key to Policy data structure thisPolicyList.Signature.Qx = thisPdefList.PubKeyQx thisPolicyList.Signature.Qy = thisPdefList.PubKeyQy # Copy other common parameters # RevocationCounter = PDEF.PolListInfo[i].RevocationCounter # Note: Code differs from the tool spec algorithm in section 5.3.1 p19 as follows: # - List Revocation Counters are incremented on the 1st change after a build, not here # - RevokeCounter is sync'd to Revocation counter in list.onBuildButtonClick() not here thisPolicyList.Signature.RevocationCounter = thisPdefList.RevocationCounter # PubkeySize = PDEF.PolListInfo[i].PubkeySize thisPolicyList.Signature.PubkeySize = int(thisPdefList.KeySize) print("createSignatureBlock - RevocationCounter=%d, keySize=%d per PDEF KeySize=%s" % (thisPolicyList.Signature.RevocationCounter, thisPolicyList.Signature.PubkeySize, thisPdefList.KeySize)) # DBGDBG # Calculate Hash of public key using PDEF,HashAlg # Copy to ListMeasurements[i] try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == pdef.HashAlg)).next() except StopIteration: self.StatusBar.SetStatusText("Hash Algorithm is not supported, (pdef.HashAlg=%d)" % (pdef.HashAlg)) return hash = M2Crypto.EVP.MessageDigest(hashAlgStr.lower()) if 'RSA' in signAlgStr: hash.update(thisPolicyList.Signature.PubkeyValue) else: hash.update(thisPolicyList.Signature.Qx) hash.update(thisPolicyList.Signature.Qy) digest = hash.digest() ListMeasurements.hashes[str(listCnt)] = digest # Build SigBlock[PubkeySize] # Calculate hash of LIST using PDEF,HashAlg # Encrypt hash using private key [ie Sign it] # A.2.1 - For a signed list, the RSA signature is calculated over the entire LCP_POLICY_LIST struct, # including the Signature member, EXCEPT for the SigBlock # Copy encrypted hash to policy data structure LCP_SIGNATURE.SigBlock # Done with signature # NOTE: The list is signed later, and the signature copied to LCP_SIGNATURE.SigBlock # when the list is written to its .dat file in buildLcpPolicyDataFile() # since that is when the 'signable' binary data is packed # [vs. the Python object form of the data available here] # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcp-gen2/defines.py0000644000000000000000000002117614210363175014462 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. class DEFINES( object ): """ Defines Class""" def __init__( self ): pass LCP_VERSION = 2 TOOL_VERSION = '0.5' BUILD_DATE = '2013-09-06' SUPPORTED_LCP_VERSION = { # Policy Version : List Verson '3.1' : '2.1', '3.0' : '2.0' } # Policy Type global values: LIST = 0 ANY = 1 # Policy Rules global values PsRules = 0 PoRules = 1 # max value for Min SINIT Version and BIOS & SINIT Revocation Limit fields maxVersion = 255 # The PolicyControlField provides a number of control bits which are defined as: # Bit31 AUXDeletionControl # Bits30:4 Reserved and should set to zero # Bit20 Ignore PS STM # Bit17 Ignore PS PCONF # Bit16 Ignore PS MLE # Bit 3 Indicates Force Owner Policy # Bit 2 Allow NPW. # Bit 1 PCR 17 # Bit 0 Reserved and should set to zero # PolicyControlAUXDeletionControl = 0x80000000 # bit 31 PolicyControlIgnorePsStmBitMask = 0x00100000 # bit 20 PolicyControlIgnorePsPconfBitMask = 0x00020000 # bit 17 PolicyControlIgnorePsMleBitMask = 0x00010000 # bit 16 PolicyControlForceOwnerBitMask = 0x00000008 # bit 3 PolicyControlPcr17BitMask = 0x00000004 # bit 2 PolicyControlAllowNpwBitMask = 0x00000002 # bit 1 # List Policy Signing Algorithm LCP_POLSALG_NONE = 0 # list not signed LCP_POLSALG_RSA_PKCS_15 = 1 # list signed LCP_POLSALG_ECDSA = 2 LCP_POLSALG_SM2 = 3 # Element types: MLE, PCONF, SBIOS and STM LCP_POLELT_TYPE_MLE = 0x00 LCP_POLELT_TYPE_PCONF = 0x01 LCP_POLELT_TYPE_SBIOS = 0x02 LCP_POLELT_TYPE_MLE2 = 0x10 LCP_POLELT_TYPE_PCONF2 = 0x11 LCP_POLELT_TYPE_SBIOS2 = 0x12 LCP_POLELT_TYPE_STM2 = 0x14 # Each list can have each element with each possible hash algorithm # So Pdef_list.[Mle,Pconf,Sbios,Stm]DefData[x] is now an array # where x is one of the indexes below which must be < MAX_ELEMENTS DEFDATA_INDEX = { 'SHA1' : 0, 'SHA256' : 1, 'SHA384' : 2, 'SHA512' : 3, #'SM3' : 4 } # Other than ELEMENT_NAME_NONE with no '-' character, # all other names must be - # This is used in list.py to create new element of the hash type. # So the following element names are possible: ELEMENT_NAME_NONE = "None" ELEMENT_NAME_MLE_SHA1 = "MLE-SHA1" ELEMENT_NAME_MLE_SHA256 = "MLE-SHA256" ELEMENT_NAME_MLE_SHA384 = "MLE-SHA384" ELEMENT_NAME_MLE_SHA512 = "MLE-SHA512" ELEMENT_NAME_MLE_SM3 = "MLE-SM3" ELEMENT_NAME_PCONF_SHA1 = "PCONF-SHA1" ELEMENT_NAME_PCONF_SHA256 = "PCONF-SHA256" ELEMENT_NAME_PCONF_SHA384 = "PCONF-SHA384" ELEMENT_NAME_PCONF_SHA512 = "PCONF-SHA512" ELEMENT_NAME_PCONF_SM3 = "PCONF-SM3" ELEMENT_NAME_SBIOS_SHA1 = "SBIOS-SHA1" ELEMENT_NAME_SBIOS_SHA256 = "SBIOS-SHA256" ELEMENT_NAME_SBIOS_SHA384 = "SBIOS-SHA384" ELEMENT_NAME_SBIOS_SHA512 = "SBIOS-SHA512" ELEMENT_NAME_SBIOS_SM3 = "SBIOS-SM3" ELEMENT_NAME_STM_SHA1 = "STM-SHA1" ELEMENT_NAME_STM_SHA256 = "STM-SHA256" ELEMENT_NAME_STM_SHA384 = "STM-SHA384" ELEMENT_NAME_STM_SHA512 = "STM-SHA512" ELEMENT_NAME_STM_SM3 = "STM-SM3" ELEMENT_NAME_MLE_LEGACY = "MLE-LEGACY" ELEMENT_NAME_PCONF_LEGACY = "PCONF-LEGACY" ELEMENT_NAME_SBIOS_LEGACY = "SBIOS-LEGACY" # element name strings for PO rules ELEMENT_PO_RULES = [ ELEMENT_NAME_STM_SHA512, ELEMENT_NAME_STM_SHA384, ELEMENT_NAME_STM_SHA256, ELEMENT_NAME_STM_SHA1, #ELEMENT_NAME_STM_SM3, ELEMENT_NAME_PCONF_SHA512, ELEMENT_NAME_PCONF_SHA384, ELEMENT_NAME_PCONF_SHA256, ELEMENT_NAME_PCONF_SHA1, #ELEMENT_NAME_PCONF_SM3, ELEMENT_NAME_PCONF_LEGACY, ELEMENT_NAME_MLE_SHA512, ELEMENT_NAME_MLE_SHA384, ELEMENT_NAME_MLE_SHA256, ELEMENT_NAME_MLE_SHA1, #ELEMENT_NAME_MLE_SM3, ELEMENT_NAME_MLE_LEGACY ] """getElement - return array of element names strings""" ELEMENT = [ ELEMENT_NAME_SBIOS_SHA512, ELEMENT_NAME_SBIOS_SHA384, ELEMENT_NAME_SBIOS_SHA256, ELEMENT_NAME_SBIOS_SHA1, #ELEMENT_NAME_SBIOS_SM3, ELEMENT_NAME_SBIOS_LEGACY, ELEMENT_NAME_STM_SHA512, ELEMENT_NAME_STM_SHA384, ELEMENT_NAME_STM_SHA256, ELEMENT_NAME_STM_SHA1, #ELEMENT_NAME_STM_SM3, ELEMENT_NAME_PCONF_SHA512, ELEMENT_NAME_PCONF_SHA384, ELEMENT_NAME_PCONF_SHA256, ELEMENT_NAME_PCONF_SHA1, #ELEMENT_NAME_PCONF_SM3, ELEMENT_NAME_PCONF_LEGACY, ELEMENT_NAME_MLE_SHA512, ELEMENT_NAME_MLE_SHA384, ELEMENT_NAME_MLE_SHA256, ELEMENT_NAME_MLE_SHA1, #ELEMENT_NAME_MLE_SM3, ELEMENT_NAME_MLE_LEGACY ] # This replaces util.getHashes() # supported hash algorithm names SUPPORTED_HASHES = [ 'SHA1', 'SHA256', 'SHA384', 'SHA512', #'SM3' ] # allowed hash algorithm names ALLOWED_HASHES = [ 'SHA1', #'SHA224', # not supported 'SHA256', 'SHA384', 'SHA512', 'SM3' ] # ALLOWED_SIGNATURE_SCHEMES is ordered list that references TPM_ALG_SIGN_MASK # allowed signing algorithm names ALLOWED_SIGNATURE_SCHEMES = [ #'RSA-1024-SHA1', 'RSA-1024-SHA256', 'RSA-2048-SHA1', # not supported 'RSA-2048-SHA256', #'RSA-2048-SHA384', 'RSA-2048-SHA512', # not supported #'RSA-3072-SHA256', 'RSA-3072-SHA384', 'RSA-3072-SHA512', # not supported #'RSA-4096-SHA256', 'RSA-4096-SHA384', 'RSA-4096-SHA512', # not supported 'ECDSA P-256', 'ECDSA P-384', 'SM2' ] SIGNATURE_ALGORITHMS = [ 'None', #'RSA PKCS1.5/SHA1', 'RSA PKCS1.5/SHA256', #'RSA PKCS1.5/SHA384', #'RSA PKCS1.5/SHA512', 'ECDSA P-256/SHA256', 'ECDSA P-384/SHA384', #'SM2/SM3' ] SIGNATURE_KEY_SIZE = { 'None' : [], 'RSA PKCS1.5/SHA256' : ['2048'], 'ECDSA P-256/SHA256' : ['256'], 'ECDSA P-384/SHA384' : ['384'], 'SM2/SM3' : ['256'] } # Hash Algorithm defines for pdef.hashAlg TPM_ALG_HASH = { 'SHA1_LEGACY' : 0x0000, 'SHA1' : 0x0004, 'SHA256' : 0x000B, 'SHA384' : 0x000C, 'SHA512' : 0x000D, 'NULL' : 0x0010, 'SM3' : 0x0012 } # Signature Algorithm defined for LCP_POLICY_LIST2.SigAlgorithm TPM_ALG_SIGN = { 'NULL' : 0x0010, # same as in Hash Algorithm 'RSASSA' : 0x0014, 'ECDSA' : 0x0018, 'SM2' : 0x001B } # SHAXXXXX_DIGEST_SIZE DIGEST_SIZE = { 'SHA1' : 20, 'SHA256' : 32, 'SHA384' : 48, 'SHA512' : 64, 'SM3' : 32 } # TPM_ALG_HASH_MASK_XXXX TPM_ALG_HASH_MASK = { 'SHA1' : 0x0001, 'SHA224' : 0x0002, 'SHA512_224' : 0x0004, 'SHA256' : 0x0008, 'SHA512_256' : 0x0010, 'SM3' : 0x0020, 'SHA384' : 0x0040, 'SHA512' : 0x0080, 'WHIRLPOOL' : 0x0100 } # TPM_ALG_SIGN_MASK_XXXX TPM_ALG_SIGN_MASK = { 'RSA-1024-SHA1' : 0x00000001, 'RSA-1024-SHA256' : 0x00000002, 'RSA-2048-SHA1' : 0x00000004, 'RSA-2048-SHA256' : 0x00000008, 'RSA-2048-SHA384' : 0x00000010, 'RSA-2048-SHA512' : 0x00000020, 'RSA-3072-SHA256' : 0x00000040, 'RSA-3072-SHA384' : 0x00000080, 'RSA-3072-SHA512' : 0x00000100, 'RSA-4096-SHA256' : 0x00000200, 'RSA-4096-SHA384' : 0x00000400, 'RSA-4096-SHA512' : 0x00000800, 'ECDSA P-256' : 0x00001000, 'ECDSA P-384' : 0x00002000, 'SM2' : 0x00010000 } # Types of hash files - see util.verifyHashFile() HashFileMode = { 'HdrNull' : 0, 'HdrSHA1' : 1, 'RawSHA1' : 2, 'RawSHA256' : 3, 'RawSHA384' : 4, 'RawSHA512' : 5, 'RawSM3' : 6 #TODO: check the value } # Types of PCR dump Files - see util.verifyPcrFile() PcrFileMode = { 'Null' : 0, 'Pcrd' : 7, 'Pcr2' : 8 } # key files are private or public keys for RSA or ECC KEY_FILE_TYPE = { 'PRIVATE_RSASSA': 1, 'PUBLIC_RSASSA' : 2, 'PRIVATE_ECDSA' : 3, 'PUBLIC_ECDSA' : 4 } PCRDFileHdrSize = 16 PCR2FileHdrSize = 8 PCRFileMinHdrSize = 7 # 1st 6 bytes of PCRD or PCR2 file are enough to determine the type and check the HashAlg tboot-1.10.5/lcp-gen2/list.py0000644000000000000000000016357014210363175014025 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function import string # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import PLIST_DEF, MLE_DEF, PCONF_DEF, SBIOS_DEF from LcpPolicy import LCP_POLICY2, LCP_SIGNATURE2 from util import UTILS utilities = UTILS() from sbios import SBIOS from mle import MLE from pconf import PCONF from stm import STM from sbiosLegacy import SBIOSLegacy from pconfLegacy import PCONFLegacy from mleLegacy import MLELegacy from pdef import * try: import cPickle as pickle except ImportError: import pickle # fall back on Python version import array import base64 from struct import * # TXT Policy Generator Tool # List Class - Policy Definition File Lists # class LIST( object ): """__init__() - List class constructor""" def __init__( self ): """LIST __init__ constructor""" self.listPanelWidgets = [] self.visibleElement = DEFINES.ELEMENT_NAME_NONE self.includedElements = [] #print("in LIST __init__() listPanelWidgets=%s" % (self.listPanelWidgets)) # DBGDBG # # create the List Panel # LIST X # Version 2.0 Number of 0 Select NONE DELETE ELEMENT # Elements Element # Revocation 23 [] Signed ADD SBIOS # Count Key File my.key BROWSE ADD MLE # Allowed 23 Key Size 2048 RSA PKCS1.5 ADD PCONF # RESET [] Sync Algorithm # def createListPanel(self, wx, parent, listNumber, pdef, statusBar): """createListPanel - create the List Panel""" #print("createListPanel - list %i" % (listNumber)) self.pdef = pdef self.StatusBar = statusBar self.parent = parent parentSizer = parent.GetSizer() # create the List Panel sizers self.listPanel = wx.Panel(parent, -1) self.listPanelSizer = wx.GridBagSizer(hgap=5, vgap=5) self.listPanel.SetSizer(self.listPanelSizer) #listHorizSizer = wx.BoxSize4r(wx.HORIZONTAL) #listLabelText = "LIST " + str(listNumber) listLabelText = "LIST" self.listLabel = wx.StaticText(self.listPanel, -1, listLabelText) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.listLabel.SetFont( font ) self.listPanelSizer.Add( self.listLabel, pos=(0, 0)) self.listPanelWidgets = [self.listLabel] self.listLabelNum = wx.TextCtrl( self.listPanel, value="X", size=(30, -1)) self.listLabelNum.Enable( False ) # LIST num cannot be modified by user self.listLabelNum.SetFont( font ) #self.listLabelNum.SetBackgroundColour(self.listPanel.GetBackgroundColour()) # no change to color?? Fore or Background N/C self.listLabelNum.SetFocus() self.listLabelNum.Refresh() # no help self.listLabelNum.ChangeValue(str(listNumber)) self.listPanelSizer.Add( self.listLabelNum, pos=(0,1)) self.listPanelWidgets.append(self.listLabelNum) # LIST Version text box - PDEF.PolList[n].ListVersion # Change list version number to corresponds to policy version number #policyversion = str(pdef.PolVersionMajor) + '.' + str(pdef.PolVersionMinor) #listversion = DEFINES.SUPPORTED_LCP_VERSION[policyversion] #majorstring, minorstring = listversion.split('.') #self.pdef.PolListInfo[str(listNumber-1)].ListVersionMajor = int(majorstring) #self.pdef.PolListInfo[str(listNumber-1)].ListVersionMinor = int(minorstring) self.versionLabel = wx.StaticText(self.listPanel, label="Version: ", size = (90, -1), style = wx.ALIGN_RIGHT) self.listPanelSizer.Add( self.versionLabel, pos=(1,0)) self.listPanelWidgets.append(self.versionLabel) version = str(self.pdef.PolListInfo[str(listNumber-1)].ListVersionMajor)+"."+str(self.pdef.PolListInfo[str(listNumber-1)].ListVersionMinor) self.versionEdit = wx.TextCtrl( self.listPanel, value=version, size=(30, -1)) self.versionEdit.Enable( False ) # Version cannot be modified self.listPanelSizer.Add( self.versionEdit, pos=(1,1)) self.listPanelWidgets.append(self.versionEdit) # Number Elements text box - number of elements that are marked VALID self.numberElementsLabel = wx.StaticText(self.listPanel, label="Number of Elements ") self.listPanelSizer.Add( self.numberElementsLabel, pos=(2,2)) self.listPanelWidgets.append(self.numberElementsLabel) self.numberElementsEdit = wx.TextCtrl( self.listPanel, value="0", size=(30, -1)) self.numberElementsEdit.Disable() self.listPanelSizer.Add( self.numberElementsEdit, pos=(2,3)) self.listPanelWidgets.append(self.numberElementsEdit) # Select Element Control - PDEF.PolList[n].CurrentElementView # Allows user to select which elements to view # Disabled when NumberOfElements = 0 # SBIOS is only valid if PS rules. # MLE and PCONF are valid for both. self.selectElementList = [DEFINES.ELEMENT_NAME_NONE] self.selectElementLabel = wx.StaticText(self.listPanel, label="\nView Element") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.selectElementLabel.SetFont( font ) self.listPanelSizer.Add(self.selectElementLabel, pos=(3,2)) self.listPanelWidgets.append(self.selectElementLabel) self.selectElementEdit = wx.ComboBox( self.listPanel, size=(100, -1), value=DEFINES.ELEMENT_NAME_NONE, choices=self.selectElementList, style=wx.CB_READONLY ) self.selectElementEdit.Enable( False ) self.selectElementEdit.SetSelection(0) self.listPanelSizer.Add(self.selectElementEdit, pos=(4,2)) self.selectElementEdit.Bind(wx.EVT_TEXT, self.onSelectElementEdit) self.listPanelWidgets.append(self.selectElementEdit) # ADD ELEMENT # adds the selected element # Disabled when all possible elements exist # sets corresponding IncludeXXX to TRUE # self.addElementButton = wx.Button( self.listPanel, -1, label="Add Element") self.listPanelSizer.Add( self.addElementButton, pos=(2,0)) self.listPanelWidgets.append(self.addElementButton) self.addElementButton.Bind(wx.EVT_BUTTON, self.onAddElementClick) self.addElementChoicesPs = [] self.addElementChoicesPs += DEFINES.ELEMENT self.addElementChoicesPo = [] self.addElementChoicesPo += DEFINES.ELEMENT_PO_RULES # DELETE ELEMENT combo # Deletes the selected element # Disabled when NumberOfElements = 0 # sets corresponding IncludeXXX to FALSE # self.deleteElementButton = wx.Button( self.listPanel, -1, label="Delete Element") self.deleteElementButton.Enable( False ) self.listPanelSizer.Add( self.deleteElementButton, pos=(3,0)) self.listPanelWidgets.append(self.deleteElementButton) self.deleteElementButton.Bind(wx.EVT_BUTTON, self.onDeleteElementButtonClick) # Revocation Count text box - PDEF.PolList[n]ListVersion.RevocationCounter # updated automatically each time the user performs a BUID, but only if the list is signed self.revocationCountLabel = wx.StaticText(self.listPanel, label="Revocation\nCount: ") self.listPanelSizer.Add( self.revocationCountLabel, pos=(2,6)) self.listPanelWidgets.append(self.revocationCountLabel) self.revocationCountEdit = wx.TextCtrl( self.listPanel, value="0", size=(30, -1)) self.revocationCountEdit.Enable(False) # disable editing since updated automatically on BUILD's self.listPanelSizer.Add( self.revocationCountEdit, pos=(2,7)) self.listPanelWidgets.append(self.revocationCountEdit) # Allowed text box - PDEF.PolList[n]ListVersion.RevokeCount # permits user to enter a value between 0 and RevocationCounter # Copied to PDEF.RevocationCounters[n] when policy is built self.allowedLabel = wx.StaticText(self.listPanel, label="Allowed") self.listPanelSizer.Add( self.allowedLabel, pos=(3,6)) self.listPanelWidgets.append(self.allowedLabel) self.allowedEdit = wx.TextCtrl( self.listPanel, value="0", size=(30, -1)) self.allowedEdit.Enable(False) # disabled since Sync checkbox defaults to True self.listPanelSizer.Add( self.allowedEdit, pos=(3,7)) self.listPanelWidgets.append(self.allowedEdit) self.allowedEdit.Bind(wx.EVT_TEXT, self.onAllowedEdit) # Reset button # Resets the Revocation Count to 0 # self.resetButton = wx.Button( self.listPanel, -1, label="Reset", style=wx.BU_EXACTFIT) self.resetButton.Enable(False) self.listPanelSizer.Add( self.resetButton, pos=(4,6)) self.listPanelWidgets.append(self.resetButton) self.resetButton.Bind(wx.EVT_BUTTON, self.onResetButtonClick) # Sync checkbox - PDEF.PolListInfo[n].SyncRevCount # if checked, force Allowed to equal Revocation Count and Allowed box is disabled # self.Sync = wx.CheckBox(self.listPanel, label="Sync") self.Sync.SetValue(True) self.Sync.Bind(wx.EVT_CHECKBOX, self.onSync) self.listPanelSizer.Add(self.Sync, pos=(4,7), span=(1,2), flag=wx.BOTTOM, border=5) self.listPanelWidgets.append(self.Sync) # Private Key File text box - PDEF.PolList[n].PvtKeyFile # allows user to specify the file that contains the signing key self.pvtKeyFileSel = wx.ComboBox( self.listPanel, size=(80, -1), value="Private Key", choices=["Private Key", "Signature"], style=wx.CB_READONLY ) self.pvtKeyFileSel.Bind(wx.EVT_TEXT, self.onPvtKeyFileSel) self.listPanelSizer.Add( self.pvtKeyFileSel, pos=(2,11)) self.listPanelWidgets.append(self.pvtKeyFileSel) self.pvtKeyFileEdit = wx.TextCtrl( self.listPanel, value="", size=(110, -1)) self.pvtKeyFileEdit.Bind(wx.EVT_TEXT, self.onPvtKeyFileEdit) self.listPanelSizer.Add( self.pvtKeyFileEdit, pos=(2,12)) self.listPanelWidgets.append(self.pvtKeyFileEdit) # BROWSE button # bring up a File Browse dialogue # self.pvtBrowseButton = wx.Button( self.listPanel, -1, label="Browse", style=wx.BU_EXACTFIT) self.listPanelSizer.Add( self.pvtBrowseButton, pos=(2,13)) self.listPanelWidgets.append(self.pvtBrowseButton) self.pvtBrowseButton.Bind(wx.EVT_BUTTON, self.onPvtBrowseButtonClick, self.pvtBrowseButton) # Key File text box - PDEF.PolList[n].PubKeyFile # allows user to specify the file that contains the signing key self.pubKeyFileLabel = wx.StaticText(self.listPanel, label="Public Key") #font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) #self.pubKeyFileLabel.SetFont( font ) self.listPanelSizer.Add( self.pubKeyFileLabel, pos=(3,11)) self.listPanelWidgets.append(self.pubKeyFileLabel) self.pubKeyFileEdit = wx.TextCtrl( self.listPanel, value="", size=(110, -1)) self.pubKeyFileEdit.Bind(wx.EVT_TEXT, self.onPubKeyFileEdit) self.listPanelSizer.Add( self.pubKeyFileEdit, pos=(3,12)) self.listPanelWidgets.append(self.pubKeyFileEdit) # BROWSE button # bring up a File Browse dialogue # self.pubBrowseButton = wx.Button( self.listPanel, -1, label="Browse", style=wx.BU_EXACTFIT) self.listPanelSizer.Add( self.pubBrowseButton, pos=(3,13)) self.listPanelWidgets.append(self.pubBrowseButton) self.pubBrowseButton.Bind(wx.EVT_BUTTON, self.onPubBrowseButtonClick) # Key Size Control - PDEF.PolList[n].KeySize # Allows user to select one of the supported key sizes: 1024, 2048, 3072 # self.keySizeList = DEFINES.SIGNATURE_KEY_SIZE["RSA PKCS1.5/SHA256"] self.keySizeLabel = wx.StaticText(self.listPanel, label="Key Size") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.keySizeLabel.SetFont( font ) self.listPanelSizer.Add(self.keySizeLabel, pos=(2,10)) self.listPanelWidgets.append(self.keySizeLabel) self.keySizeEdit = wx.ComboBox( self.listPanel, size=(110, -1), value="2048", choices=self.keySizeList, style=wx.CB_READONLY ) self.keySizeEdit.Bind(wx.EVT_TEXT, self.onKeySizeEdit) self.listPanelSizer.Add(self.keySizeEdit, pos=(3,10)) self.listPanelWidgets.append(self.keySizeEdit) # AlgorithmControl - PDEF.PolList[n].SigAlgorithm # Allows user to select supported algorithms, but only RSA PKCS1.5 # self.algorithmList = DEFINES.SIGNATURE_ALGORITHMS self.algorithmLabel = wx.StaticText(self.listPanel, label="Signing\nAlgorithm ") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.algorithmLabel.SetFont( font ) self.listPanelSizer.Add(self.algorithmLabel, pos=(1,11)) self.listPanelWidgets.append(self.algorithmLabel) self.algorithmEdit = wx.ComboBox( self.listPanel, size=(165, -1), value="None", choices=self.algorithmList, style=wx.CB_READONLY ) self.algorithmEdit.Bind(wx.EVT_TEXT, self.onAlgorithmEdit) self.listPanelSizer.Add(self.algorithmEdit, pos=(1,12), span=(1,2)) self.listPanelWidgets.append(self.algorithmEdit) self.enableDisableSigned(False) # default to not signed #listHorizSizer.Add(listGridSizer, 0, wx.ALL, 5) #self.listPanelSizer.Add(listHorizSizer, 0, wx.ALL, 5) #parent.Add(listHorizSizer) parentSizer.Add(self.listPanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) print("parent sizer type = %s size = %d, %d" %(type(parentSizer).__name__, w, h)) #parent.Fit() parent.Layout() #parent.SetSizerAndFit(self.listPanelSizer) def hideListPanel(self): """hideListPanel - remove [actually just hide] the list panel and any element panels from the policy panel""" for i in self.listPanelWidgets: i.Hide() self.hideAllPanels() # hide all the panels #TODO: wxPython: hideListPanel - how to resize window back to the original Policy Panel size when delting a list? def showListPanel(self): """showListPanel - re-show the list and element panels""" #print("in showListPanel listPanelWidgets=%s" % (self.listPanelWidgets)) # DBGDBG for i in self.listPanelWidgets: i.Show() for element in self.includedElements: element.showPanel() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setListPanelToDefaults(self, wx, parent, listNumber, pdef): """setListPanelToDefaults - widgets were all ready created, restore defaults""" #self.StatusBar.SetStatusText("Created LIST %i with default values" % (listNumber)) print("Created LIST %i with default values" % (listNumber)) self.listLabelNum.ChangeValue(str(listNumber)) policyversion = str(pdef.PolVersionMajor)+'.'+str(pdef.PolVersionMinor) listversion = DEFINES.SUPPORTED_LCP_VERSION[policyversion] self.versionEdit.ChangeValue(listversion) self.numberElementsEdit.ChangeValue("0") self.selectElementEdit.Clear() self.selectElementEdit.Append('None') self.selectElementEdit.SetSelection(0) self.addElementChoicesPs = [] self.addElementChoicesPs += DEFINES.ELEMENT self.addElementChoicesPo = [] self.addElementChoicesPo += DEFINES.ELEMENT_PO_RULES self.revocationCountLabel.Enable(True) self.revocationCountEdit.ChangeValue("0") self.allowedLabel.Enable(True) self.allowedEdit.ChangeValue("0") self.resetButton.Enable(True) self.Sync.SetValue(True) self.Sync.Enable(True) self.algorithmEdit.SetValue("None") self.pubKeyFileEdit.ChangeValue("") self.pubKeyFileEdit.Enable(False) self.pvtKeyFileEdit.ChangeValue("") self.pvtKeyFileEdit.Enable(False) self.pubBrowseButton.Enable(False) self.pvtBrowseButton.Enable(False) self.keySizeEdit.SetValue("2048") self.keySizeEdit.Enable(False) self.algorithmEdit.Enable(True) for i in self.listPanelWidgets: i.Show() for elements in self.includedElements: elements.hidePanel() # delete element GUI panels in self.includedElements[] and elements in pdef.CurrentList.ElementDefData[] self.includedElements = [] currentListObject = pdef.getCurrentListObject() currentListObject.ElementDefData = [] def restoreListPanel(self, currentList): """restoreListPanel - restore the list panel's widgets""" func = 'restoreListPanel' self.hideAllPanels() self.listLabelNum.ChangeValue(str(self.pdef.CurrentListView)) cnt = 0 self.rebuildSelectElementChoices() self.addElementChoicesPs = [] self.addElementChoicesPs += DEFINES.ELEMENT # copy elements not just reference self.addElementChoicesPo = [] self.addElementChoicesPo += DEFINES.ELEMENT_PO_RULES # copy elements not just reference cnt = len(currentList.ElementDefData) #self.numberElementsEdit.ChangeValue(str(cnt)) if(cnt > 0): flag = True self.selectElementEdit.SetValue(currentList.CurrentElementView) #self.selectElementEdit.SetSelection(cnt) else: flag = False currentList.CurrentElementView = DEFINES.ELEMENT_NAME_NONE #self.visibleElement = DEFINES.ELEMENT_NAME_NONE self.selectElementEdit.SetValue(DEFINES.ELEMENT_NAME_NONE) self.selectElementEdit.SetSelection(0) # show element panel for selected element selection = self.selectElementEdit.GetSelection() if selection > 0: self.includedElements[selection-1].showPanel() self.selectElementEdit.Enable(flag) self.deleteElementButton.Enable(flag) #print("restoreListPanel - Sync=%s SigAlgorithm=%x" % (currentList.SyncRevCount, currentList.SigAlgorithm)) # DBGDBG self.Sync.SetValue(currentList.SyncRevCount) self.allowedEdit.ChangeValue(str(currentList.RevokeCounter)) self.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) self.keySizeEdit.SetValue(str(currentList.KeySize)) #if (currentList.SigAlgorithm == 1): # For TPM 1.2 signAlgName = "" try: signAlgName = (key for key,val in DEFINES.TPM_ALG_SIGN.items() if currentList.SigAlgorithm == val).next() except StopIteration: print("WARNING - Invalid signature algorithm (%d)" %(currentList.SigAlgorithm)) hashAlgName = "" try: hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if currentList.sigAlgorithmHash == val).next() except StopIteration: print("WARNING - Invalid hash algorithm (%d)" %(currentList.sigAlgorithmHash)) selectionString = "None" if 'RSA' in signAlgName: selectionString = (name for name in DEFINES.SIGNATURE_ALGORITHMS if 'RSA' in name and hashAlgName in name).next() enable = True elif 'ECDSA' in signAlgName: selectionString = (name for name in DEFINES.SIGNATURE_ALGORITHMS if signAlgName in name and currentList.KeySize in name).next() enable = True #elif 'SM2' in signAlgName: # selectionString = (name for name in DEFINES.SIGNATURE_ALGORITHMS if signAlgName in name).next() # enable = True else: enable = False self.enableDisableSigned(enable, selectionString) self.algorithmEdit.SetValue(selectionString) self.pvtKeyFileSel.SetSelection(currentList.PvtKeyFileIsSignature) self.pubKeyFileEdit.ChangeValue(currentList.PubKeyFile) self.pvtKeyFileEdit.ChangeValue(currentList.PvtKeyFile) #currentList.ListModified = False # don't want to change the state of this variable def setListPanelToCurrentListView(self): """setListPanelToCurrentListView - update the list panel to the specified list""" currentList = self.pdef.getCurrentListObject() print("setListPanelToCurrentListView %i AllowedCounter=%i" % (self.pdef.CurrentListView, currentList.RevokeCounter)) # DBGDBG # Hide all panels before rebuilding the list for the new panel self.hideAllPanels() # Clear GUI panels for each element self.includedElements = [] # Re-build the GUI panel for each element from the PDEF persistent object in pdef.py file index = 0 for defdata in currentList.ElementDefData: # Get Name and Hash type of each and recreate GUI element with it. # Create a new element of selected spec and populate into currentListObject.MleDefData elementType, hashAlg = defdata.Name.split('-') if hashAlg == 'LEGACY': if elementType == 'SBIOS': element = SBIOSLegacy() elif elementType == 'MLE': element = MLELegacy() elif elementType == 'PCONF': element = PCONFLegacy() else: print ("ERROR: invalid element") else: if elementType == 'SBIOS': element = SBIOS(DEFINES.TPM_ALG_HASH[hashAlg]) # GUI panel elif elementType == 'STM': element = STM(DEFINES.TPM_ALG_HASH[hashAlg]) elif elementType == 'MLE': element = MLE(DEFINES.TPM_ALG_HASH[hashAlg]) elif elementType == 'PCONF': element = PCONF(DEFINES.TPM_ALG_HASH[hashAlg]) else: print ("ERROR: invalid element") element.createOrShowPanel(wx, self, self.parent, self.pdef, self.StatusBar) element.myIndex = index self.includedElements.append(element) element.restorePanel(currentList, self.pdef.MaxHashes) element.hidePanel() index += 1 # restore any element panels that exist in the current PLIST_DEF # Also update this list's element panel, if one exists # 1st hide all the elements and enable if they don't exist and rules allow that #self.hideAllPanels() # Hide all the element panels # then disable add buttons for elements that exist # and count the number of elements in this list numberOfElements = len(currentList.ElementDefData) # rebuild selectElementEdit's choices list for the elements existing in this view self.rebuildSelectElementChoices() # then show a panel # update the NumberOfElements and enable selectElementsEdit if > 0 self.numberElementsEdit.ChangeValue(str(numberOfElements)) if(numberOfElements > 0): self.selectElementEdit.Enable( True ) self.deleteElementButton.Enable( True ) self.restoreListPanel(currentList) # only called if PolicyType = LIST if pdef.NumLists > 0 # for each signed list, # If Sync is checked, # then update the current list's AllowedCounter from its RevocationCounter # update pdef.DataRevocationCounters[list#] from the current list's Allowedounter # if the current List is displayed in the list panel, update the list panel widgets # # NOTE: the current list's RevocationCounter is incr on its 1st modification # def onBuildButtonClick(self, pdef): """ onBuildButtonClick - perform a build""" #print("list::onBuildButtonClick") # DBGDBG listNum = 0 while( listNum < pdef.NumLists): thisList = pdef.PolListInfo[str(listNum)] #if(thisList.SigAlgorithm == DEFINES.LCP_POLSALG_RSA_PKCS_15): # For TPM1.2 if(thisList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']): if(thisList.SyncRevCount == True): thisList.RevokeCounter = thisList.RevocationCounter pdef.DataRevocationCounters[listNum] = thisList.RevokeCounter # is this list being shown in the list panel? if(pdef.CurrentListView == listNum + 1): self.allowedEdit.ChangeValue(str(thisList.RevokeCounter)) self.revocationCountEdit.ChangeValue(str(thisList.RevocationCounter)) if(thisList.RevocationCounter > 0): # can't reset til cnt > 0 self.resetButton.Enable(True) print("list.onBuild - list %d, RevCnt=%d, RevokeCnt=%d, pdef.DataRevocationCounters[%d]=%d" % (listNum+1, thisList.RevocationCounter, thisList.RevokeCounter, listNum+1, pdef.DataRevocationCounters[listNum])) # DBGDBG listNum += 1 #print("list.onBuild - pdef.DataRevocationCounters=%s" % (pdef.DataRevocationCounters)) # DBGDBG def onAllowedEdit(self, event): """ onAllowedEdit - handle Allowed value change""" string = event.GetString() self.StatusBar.SetStatusText("in onAllowedEdit, value=%s" % (string)) currentList = self.pdef.getCurrentListObject() maxValue = currentList.RevocationCounter #print("onAllowedEdit - MaxValue=%i" % (maxValue)) # DBGDBG try: value = int(string) except: self.StatusBar.SetStatusText( "%s is invalid, Please enter only digits between 0 and %i" % (string, maxValue)) else: #print("onAllowedEdit - Value=%i" % (value)) # DBGDBG if(value > maxValue): self.allowedEdit.ChangeValue(str(currentList.RevokeCounter)) self.StatusBar.SetStatusText( "%i is too large, the max value for Allowed is %i" % ( value, maxValue )) else: currentList.RevokeCounter = value print("onAllowedEdit - setting RevokeCounter=%i MaxValue=%i" % (value, maxValue)) self.setListModified() def onSelectElementEdit(self, event): """onSelectElementEdit - view the selected element""" func = 'onSelectElementEdit' #selection = self.selectElementEdit.GetSelection() selection = event.GetEventObject().GetSelection() selectionString = event.GetString() #self.setListModified() # just looking at different element shouldn't be considered modifying it. #Element = DEFINES.ELEMENT #Object = self.getObject() currentList = self.pdef.getCurrentListObject() #IncludeElement = utilities.getIncludeElement(currentList) # Using exhaustive find method to match selected element by it's element name and hash alg #for element in self.includedElements: # found = element.isElementType(selectionString) # if found: # self.StatusBar.SetStatusText( "Displaying the %s element" % (selectionString)) # self.hideAllPanels() # element.showPanel() # self.visibleElement = selectionString # currentList.CurrentElementView = selectionString # break if(selectionString == DEFINES.ELEMENT_NAME_NONE): self.StatusBar.SetStatusText( "No element selected") self.visibleElement = selectionString currentList.CurrentElementView = selectionString self.hideAllPanels() else: self.StatusBar.SetStatusText( "Displaying the %s element" % (selectionString)) self.hideAllPanels() self.includedElements[selection-1].showPanel() self.visibleElement = selectionString currentList.CurrentElementView = selectionString #TODO: wxPython: onSelectElementEdit - how to resize panel here? Or set min size after each panel is created? print("%s: selection=%d, visibleElement=%s" % (func, self.selectElementEdit.GetSelection(), self.visibleElement)) # DBGDBG) def onDeleteElementButtonClick(self, event): """ onDeleteElementButtonClick - delete the current element""" func = 'onDeleteElementButtonClick' self.StatusBar.SetStatusText( "Deleted the current element") #exit if None is selected, else confirm the deletion and continue if(self.visibleElement == DEFINES.ELEMENT_NAME_NONE): self.StatusBar.SetStatusText( "No element selected, Please select the element to be deleted") return # confirm delete dlg = wx.MessageDialog(None, "Deleted Elements cannot be recovered. Continue?", 'Confirm Element Deletion', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Element Deletion cancelled" ) return else: self.StatusBar.SetStatusText( "Element deleted") # ComboBox selection value is one index higher than self.includedElement[] index and PLIST_DEF.ElementDefData[] index # because of the None element to select no view. selection = self.selectElementEdit.GetSelection() # get the index selectionString = self.selectElementEdit.GetValue() # get selected element and populate into Add Element menu self.selectElementEdit.Delete(selection) print("%s - Selection=%d VisibleElement=%s - Removed" % (func, selection, self.visibleElement)) # DBGDBG currentElementsCnt = int(self.numberElementsEdit.GetValue()) if(selection > 0): nextselection = selection - 1 # fixup selection for out of order case where selection 1 was deleted, but are > 1 elements left # ie should only select 0 if 0 elements left ie None is the only choice left # Scenario: create > 1 elements, select 1, delete 1. 1 still selected if((nextselection == 0) and (currentElementsCnt > 1)): nextselection = 1 self.selectElementEdit.SetSelection(nextselection) else: print("%s: selectElementEdit.GetSelection() is invalid, Aborting!! % (func)") return # set IncludeXXX to False # hide the current element, show another element if one exists self.setListModified() #self.dumpIncludeXXX( currentListObject, 'before delete' ) # show current value of all the XXXDefData[i].IncludeXXXX # DBGDBG # Add deleted element back to Add Element menu. self.updateAddElementChoicesAfterDelete(selectionString) # update myIndex of the elements behind this element for count in range(selection, len(self.includedElements)): self.includedElements[count].myIndex -= 1 # remove item from pdef list currentListObject = self.pdef.getCurrentListObject() currentListObject.ElementDefData.pop(selection-1) # update GUI to show other element if selection > 0: self.includedElements[selection-1].hidePanel() # remove this element's GUI self.includedElements.pop(selection-1) # nextselection is indexing into the updated self.includedElements[] if nextselection != 0: self.includedElements[nextselection-1].showPanel() # Set other GUI fields currentElementsCnt -= 1 self.numberElementsEdit.ChangeValue(str(currentElementsCnt)) if(currentElementsCnt > 0): self.selectElementEdit.Enable( True ) self.addElementButton.Enable(True) self.visibleElement = self.selectElementEdit.GetValue() currentListObject.CurrentElementView = self.selectElementEdit.GetValue() print("%s - Selection=%d VisibleElement=%s" % (func, selection, self.visibleElement)) # DBGDBG elif(currentElementsCnt == 0): self.selectElementEdit.Enable( False ) self.deleteElementButton.Enable( False ) self.visibleElement = DEFINES.ELEMENT_NAME_NONE currentListObject.CurrentElementView = DEFINES.ELEMENT_NAME_NONE #self.dumpIncludeXXX( currentListObject, 'after delete' ) # show current value of all the XXXDefData[i].IncludeXXXX # DBGDBG # Object - array of all the mle, sbios, pconf & stm 1 and 256 objects # Element - array of all the ELEMENT_NAME_XXXX_SHAYYY strings # IncludeElement - array of all the XXXXDefData[DEFINES.DEFDATA_INDEX_SHANNN.IncludeXXXX # updated to indicate the just deleted element's value is now False # def showNextElement(self, Object, Element, IncludeElement, currentListObject): """showNextElement - if another element's panel exists, show it""" func = 'showNextElement' i=0 while(i < len(Element)): #print("%s - checking %s" % (func, Element[i])) # DBGDBG if(IncludeElement[i] == True): print("%s - showing %s" % (func, Element[i])) # DBGDBG Object[i].showPanel() self.visibleElement = Element[i] currentListObject.CurrentElementView = Element[i] self.selectElementEdit.SetValue(Element[i]) break i += 1 # next element def onResetButtonClick(self, event): """ onResetButtonClick - reset the revocation count""" self.StatusBar.SetStatusText( "You clicked the Reset Button!") if(self.revocationCountEdit.GetValue() != "0"): dlg = wx.MessageDialog(None, "Revocation Count reset cannot be undone. Continue?", 'Confirm Revocation Count reset', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Revocation Count reset cancelled" ) else: self.StatusBar.SetStatusText( "Reset the Revocation Count " ) self.revocationCountEdit.ChangeValue("0") currentList = self.pdef.getCurrentListObject() currentList.RevocationCounter = 0 #self.setListModified() # don't set list modified here as that re-increments the revocation ctr self.resetButton.Enable(False) def onSync(self, event): """ onSync - force Allowed to equal Revocation Count and disable Allowed""" self.StatusBar.SetStatusText("You checked Sync") currentList = self.pdef.getCurrentListObject() if(event.IsChecked()): self.allowedEdit.ChangeValue(self.revocationCountEdit.GetValue()) currentList.SyncRevCount = True currentList.RevokeCounter = currentList.RevocationCounter self.setListModified() print("onSync - PolList[%i].RevCnt=%i, Allowed=%i" % (self.pdef.CurrentListView, currentList.RevokeCounter, currentList.RevocationCounter)) # DBGDBG else: currentList.SyncRevCount = False # when checked disable editing the allowed box self.allowedEdit.Enable(not event.IsChecked()) def enableDisableSigned(self, value, signAlgName='None'): """enableDiableSigned - perform common actions when Signed or Algorithm changed""" # Note: Sync checkbox and Algorithm pulldown are redundant # Sync unchecked == LCP_POLSALG_NONE # Sync checked == LCP_POLSALG_RSA_PKCS_15 #If Unsigned [ie algorithm=None], then revocation count, allowed, RESET, Sync, Key File & Key Size are all disabled, # else enabled currentList = self.pdef.getCurrentListObject() keysizeList = DEFINES.SIGNATURE_KEY_SIZE[signAlgName] if(value == False): #value = False self.allowedEdit.Enable(value) #currentList.SigAlgorithm = DEFINES.TPM_ALG_SIGN['NULL'] # 0=Not signed #self.algorithmEdit.SetValue(DEFINES.ELEMENT_NAME_NONE) else: #value = True self.allowedEdit.Enable(not value) self.setListModified() self.resetButton.Enable(value) self.Sync.Enable(value) self.pubKeyFileEdit.Enable(value) self.pvtKeyFileEdit.Enable(value) self.pubBrowseButton.Enable(value) self.pvtBrowseButton.Enable(value) self.keySizeEdit.SetItems(keysizeList) self.keySizeEdit.SetValue(str(currentList.KeySize)) self.keySizeEdit.Enable(value) self.revocationCountLabel.Enable(value) self.allowedLabel.Enable(value) self.pvtKeyFileSel.Enable(value) self.pubKeyFileLabel.Enable(value) self.keySizeLabel.Enable(value) def onPubKeyFileEdit(self, event): """ onpubKeyFileEdit - update the key file""" currentList = self.pdef.getCurrentListObject() currentList.PubKeyFile = event.GetString() self.setListModified() # once the entire file name is entered, verify it, else clear it if(currentList.PubKeyFile.endswith(".pem")): if currentList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']: type = DEFINES.KEY_FILE_TYPE['PUBLIC_RSASSA'] elif currentList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['ECDSA']: type = DEFINES.KEY_FILE_TYPE['PUBLIC_ECDSA'] if(utilities.verifyKeyFile(currentList.PubKeyFile, type, currentList) == False): self.pubKeyFileEdit.ChangeValue("") def onPvtKeyFileSel(self, event): """ onPvtKeyFileEdit - update the key file""" currentList = self.pdef.getCurrentListObject() selectionString = event.GetString() if selectionString == "Private Key": currentList.PvtKeyFileIsSignature = False else: currentList.PvtKeyFileIsSignature = True def onPvtKeyFileEdit(self, event): """ onPvtKeyFileEdit - update the key file""" currentList = self.pdef.getCurrentListObject() currentList.PvtKeyFile = event.GetString() self.setListModified() # once the entire file name is entered, verify it, else clear it if((currentList.PvtKeyFile.endswith(".pem")) or (currentList.PvtKeyFile.endswith(".key"))): if(utilities.verifyKeyFile(currentList.PvtKeyFile, KEY_FILE_TYPE_PRIVATE, currentList) == False): self.pvtKeyFileEdit.ChangeValue("") def onKeySizeEdit(self, event): """ onKeySizeEdit - update the key size""" currentList = self.pdef.getCurrentListObject() currentList.KeySize = event.GetString() self.setListModified() self.StatusBar.SetStatusText("") # clear any previous error messages #if key file was all rdy specified, verify its size is correct file = self.pubKeyFileEdit.GetValue() if(file != ""): if(utilities.verifyKeyFile(file, KEY_FILE_TYPE_PUBLIC, currentList) == False): self.pubKeyFileEdit.ChangeValue("") currentList.PubKeyFile = "" file = self.pvtKeyFileEdit.GetValue() if(file != ""): if(utilities.verifyKeyFile(file, KEY_FILE_TYPE_PRIVATE, currentList) == False): self.pvtKeyFileEdit.ChangeValue("") currentList.PvtKeyFile = "" def onPvtBrowseButtonClick(self, event): """ onPvtBrowseButtonClick - browse to an existing PDEF file""" #self.StatusBar.SetStatusText("You clicked the Browse button") #TODO: Bill: handle .pems that have both the public and private keys? #TODO: Bill: handle .pems with password protected private keys? currentList = self.pdef.getCurrentListObject() #accept .key as well as pem files for private keys? dirname = '' # current working directory workdir = self.pdef.WorkingDirectory if currentList.PvtKeyFileIsSignature: title = "Choose the Signature file" wildcard = "All Files (*.*)|*.*|" \ "Key file (*.sig)|*.sig|" else: title = "Choose the Private Key file" wildcard = "Key file (*.pem)|*.pem|" \ "Key file (*.key)|*.key|" \ "All Files (*.*)|*.*" dlg = wx.FileDialog(self.parent, title, workdir, "", wildcard, wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() self.pvtKeyFileEdit.ChangeValue(filename) currentList.PvtKeyFile = filename self.setListModified() if currentList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']: filetype = DEFINES.KEY_FILE_TYPE['PRIVATE_RSASSA'] else: filetype = DEFINES.KEY_FILE_TYPE['PRIVATE_ECDSA'] if currentList.PvtKeyFileIsSignature: #copy signature file to the current working directory pass else: # Verify Private Key file if(utilities.verifyKeyFile(os.path.join(dirname, currentList.PvtKeyFile), filetype, currentList) == False): self.pvtKeyFileEdit.ChangeValue("") currentList.PvtKeyFile = "" elif (dirname != workdir): if (os.path.exists(os.path.join(workdir, filename))) : confdlg = wx.MessageDialog(self.parent, filename+" already exists in working directory\nOverwrite file in working directory?", "Confirm Copy", wx.OK|wx.CANCEL|wx.ICON_QUESTION) abortFlag = False if (confdlg.ShowModal() == wx.ID_OK): shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) else: abortFlag = True confdlg.Destroy() if(abortFlag == True): if(utilities.verifyKeyFile(os.path.join(workdir, currentList.PvtKeyFile), filetype, currentList) == False): # don't change self.pvtKeyFileEdit.ChangeValue("") currentList.PvtKeyFile = "" self.StatusBar.SetStatusText( "Copy cancelled, using exiting key" ) else: shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) dlg.Destroy() #print("onPvtBrowseButtonClick: %s" % (currentList.PvtKeyFile)) # DBGDBG def onPubBrowseButtonClick(self, event): """ onPubBrowseButtonClick - browse to an existing PDEF file""" #self.StatusBar.SetStatusText("You clicked the Browse button") dirname = '' # current working directory workdir = self.pdef.WorkingDirectory wildcard = "Key file (*.pem)|*.pem|" \ "All Files (*.*)| *.*" dlg = wx.FileDialog(self.parent, "Choose the Public Key file", workdir, "", wildcard, wx.FD_OPEN) currentList = self.pdef.getCurrentListObject() if currentList.SigAlgorithm == DEFINES.TPM_ALG_SIGN['RSASSA']: filetype = DEFINES.KEY_FILE_TYPE['PUBLIC_RSASSA'] else: # treat SM2 as ECDSA key filetype = DEFINES.KEY_FILE_TYPE['PUBLIC_ECDSA'] if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() self.pubKeyFileEdit.ChangeValue(filename) currentList.PubKeyFile = filename self.setListModified() if(utilities.verifyKeyFile(os.path.join(dirname, currentList.PubKeyFile), filetype, currentList) == False): self.pubKeyFileEdit.ChangeValue("") currentList.PubKeyFile = "" elif (dirname != workdir): if (os.path.exists(os.path.join(workdir, filename))) : confdlg = wx.MessageDialog(self.parent, filename+" already exists in working directory\nOverwrite file in working directory?", "Confirm Copy", wx.OK|wx.CANCEL|wx.ICON_QUESTION) abortFlag = False if (confdlg.ShowModal() == wx.ID_OK): shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) else: abortFlag = True confdlg.Destroy() if(abortFlag == True): # verify the existing file if(utilities.verifyKeyFile(os.path.join(workdir, currentList.PubKeyFile), filetype, currentList) == False): self.pubKeyFileEdit.ChangeValue("") currentList.PubKeyFile = "" self.StatusBar.SetStatusText( "Copy cancelled, using exiting key" ) else: shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) dlg.Destroy() #print("onPubBrowseButtonClick: %s" % (currentList.PubKeyFile)) # DBGDBG def onAlgorithmEdit(self, event): """ onAlgorithmEdit - select the algorithm""" func = "onAlgorithmEdit" currentList = self.pdef.getCurrentListObject() selectionString = event.GetString() algName = selectionString.split('/') if len(algName) == 2: sigAlg = algName[0].split(' ')[0] hashAlg = algName[1] # Check for valid signature algorithm name try: sigAlgName = (key for key in DEFINES.TPM_ALG_SIGN.keys() if (sigAlg in key)).next() except StopIteration: self.StatusBar.SetStatusText("Signature algorithm name mismatch") print("%s - Signature algorithm name mismatch" % (func)) # DBGDBG return # Check for valid algorithm name try: hashAlgName = (key for key in DEFINES.TPM_ALG_HASH.keys() if (hashAlg in key)).next() except StopIteration: self.StatusBar.SetStatusText("Hash algotithm name mismatch") print("%s - Hash algorithm name mismatch" % (func)) # DBGDBG return currentList.SigAlgorithm = DEFINES.TPM_ALG_SIGN[sigAlgName] currentList.sigAlgorithmHash = DEFINES.TPM_ALG_HASH[hashAlgName] if currentList.KeySize not in DEFINES.SIGNATURE_KEY_SIZE[selectionString]: currentList.KeySize = DEFINES.SIGNATURE_KEY_SIZE[selectionString][0] self.enableDisableSigned(True, selectionString) else: currentList.SigAlgorithm = DEFINES.TPM_ALG_SIGN['NULL'] self.enableDisableSigned(False) def onAddElementClick(self, event): """onAddElementClick""" func = "onAddElementClick" # ask user to select the type of element and its hash algorithm if(self.pdef.Rules == DEFINES.PsRules): addElementChoices = self.addElementChoicesPs elif(self.pdef.Rules == DEFINES.PoRules): addElementChoices = self.addElementChoicesPo else: print("%s - invalid pdef.Rules=%d" % (func, self.pdef.Rules)) return message = "Select the type of element and its hash algorithm" title = "Add Element Selections" dialog = wx.SingleChoiceDialog(None, message, title, addElementChoices) if dialog.ShowModal() == wx.ID_OK: requestedElement = dialog.GetStringSelection() else: dialog.Destroy() return # cancel out dialog.Destroy() self.StatusBar.SetStatusText("Adding a %s element to this LIST" % (requestedElement)) print("%s: adding %s" % (func, requestedElement)) # DBGDBG self.deleteElementButton.Enable( True ) currentListObject = self.pdef.getCurrentListObject() self.selectElementEdit.Enable( True ) currentElementsCnt = int(self.numberElementsEdit.GetValue()) currentElementsCnt += 1 self.numberElementsEdit.ChangeValue(str(currentElementsCnt)) # if an element is being shown, hide it. Then show the new one if(currentListObject.CurrentElementView != DEFINES.ELEMENT_NAME_NONE): self.hideThisPanel(currentListObject.CurrentElementView) currentListObject.CurrentElementView = requestedElement self.selectElementEdit.Append(requestedElement) currentSelection = self.selectElementEdit.GetSelection() #print("%s: currentSelection=%d newSelection=%d" % (func, currentSelection, currentSelection+1)) # DBGDBG self.selectElementEdit.SetSelection(currentSelection + 1) self.selectElementEdit.SetValue(requestedElement) self.updateAddElementChoicesAfterAdd(requestedElement) self.visibleElement = requestedElement # Create a new element of selected spec and populate into currentListObject.MleDefData elementType, hashAlg = requestedElement.split('-') if hashAlg == 'LEGACY': if elementType == 'SBIOS': element = SBIOSLegacy() defdata = SBIOSLEGACY_DEF() elif elementType == 'MLE': element = MLELegacy() defdata = MLELEGACY_DEF() elif elementType == 'PCONF': element = PCONFLegacy() defdata = PCONFLEGACY_DEF() else: print ("ERROR: invalid element") else: if elementType == 'SBIOS': element = SBIOS(DEFINES.TPM_ALG_HASH[hashAlg]) # GUI panel defdata = SBIOS_DEF(DEFINES.TPM_ALG_HASH[hashAlg]) # Element defined in pdef.py elif elementType == 'STM': element = STM(DEFINES.TPM_ALG_HASH[hashAlg]) defdata = STM_DEF(DEFINES.TPM_ALG_HASH[hashAlg]) elif elementType == 'MLE': element = MLE(DEFINES.TPM_ALG_HASH[hashAlg]) defdata = MLE_DEF(DEFINES.TPM_ALG_HASH[hashAlg]) elif elementType == 'PCONF': element = PCONF(DEFINES.TPM_ALG_HASH[hashAlg]) defdata = PCONF_DEF(DEFINES.TPM_ALG_HASH[hashAlg]) else: print ("ERROR: invalid element") currentListObject.ElementDefData.append(defdata) element.createOrShowPanel(wx, self, self.parent, self.pdef, self.StatusBar) self.includedElements.append(element) # Note - panels were constructed with the correct hashAlg, so no need to pass that thru here # Note - iterators not used here since need to update the pdef's xxxDefData.IncludeXXX not the array's self.selectElementEdit.Enable(True) self.parent.Layout() def syncVersion(self, rule): currentList = self.pdef.getCurrentListObject() listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) self.versionEdit.ChangeValue(listversion) if rule == DEFINES.PoRules: enable = True else: enable = False for element in self.includedElements: element.restorePanel(currentList, self.pdef.MaxHashes) element.enableDisableOverridePsPolicy(enable) def checkListModified(self, pdef): """checkListModified - return True if any list has been modified, else False""" # pdef.PolListInfo is a dictionary of 8 PLIST_DEF's from '0' to '7' # or None if that list was not added # i.e. {'0':PLIST_DEF or None, ... '7':PLIST_DEF or None} # i = '0' while(i<'8'): #print("checkListModified list %s" % (i)) # DBGDBG if(pdef.PolListInfo[i] != None): # if list exists if(pdef.PolListInfo[i].ListModified == True): print("checkListModified Return - list %s was modified" % (i)) # DBGDBG return True i = str(int(i) + 1) return False def setListModified(self): """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" currentList = self.pdef.getCurrentListObject() #also set pdef.Modified for saving file\ self.pdef.Modified = True #print("setListModified - ListModified=%s" % (currentList.ListModified)) # DBGDBG if(currentList.ListModified == False): currentList.RevocationCounter += 1 self.resetButton.Enable(True) self.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI currentList.ListModified = True def rebuildSelectElementChoices(self): """rebuildSelectElementChoices - rebuild selectElementEdit's choices list for the elements existing in this view""" func = 'rebuildSelectElementChoices' self.selectElementEdit.Clear() self.selectElementEdit.Append('None') # For each existing element in this list (ie IncludeXXXX==True) currentList = self.pdef.getCurrentListObject() for element in currentList.ElementDefData: self.selectElementEdit.Append(element.Name) # remove the added element from the add element selection list def updateAddElementChoicesAfterAdd(self, requestedElement): """updateAddElementChoicesAfterAdd""" func = 'updateAddElementChoicesAfterAdd' if(self.pdef.Rules == DEFINES.PoRules): self.addElementChoicesPo.remove(requestedElement) if(len(self.addElementChoicesPo) == 0): self.addElementButton.Enable(False) if(self.pdef.Rules == DEFINES.PsRules): self.addElementChoicesPs.remove(requestedElement) if(len(self.addElementChoicesPs) == 0): self.addElementButton.Enable(False) # append the deleted element to the add element selection list def updateAddElementChoicesAfterDelete(self, deletedElement): """updateAddElementChoicesAfterDelete""" func='updateAddElementChoicesAfterDelete' # append the deleted element to the add element selection list self.addElementChoicesPs.append(deletedElement) self.addElementChoicesPo.append(deletedElement) # rebuild the add element selection list to include all the elements that don't exist def rebuildAddElementChoices(self): """rebuildAddElementChoices""" self.rebuildAddElementChoicesForPoRules() self.rebuildAddElementChoicesForPsRules() # if a PO rules element doesn't exist, add it to the selections list def rebuildAddElementChoicesForPoRules(self): """rebuildAddElementChoicesForPoRules""" func='rebuildAddElementChoicesForPoRules' #Element = DEFINES.ELEMENT_PO_RULES self.addElementChoicesPo = [] self.addElementChoicesPo += DEFINES.ELEMENT_PO_RULES currentList = self.pdef.getCurrentListObject() for element in currentList.ElementDefData: if element.Name in self.addElementChoicesPo: self.addElementChoicesPo.remove(element.Name) else: print ("Element Name %s not found in Elements for PO rule" %(element.Name)) if len(currentList.ElementDefData) >= 8 or len(self.addElementChoicesPs) == 0: flag = False else: flag = True self.addElementButton.Enable(flag) #print("%s - addElementChoicesPo=%s" % (func, self.addElementChoicesPo)) #DBGDBG # if a PS rules element doesn't exist, add it to the selections list def rebuildAddElementChoicesForPsRules(self): """rebuildAddElementChoicesForPsRules""" func='rebuildAddElementChoicesForPsRules' #Element = DEFINES.ELEMENT # gets all the elements i.e. = PS rules self.addElementChoicesPs = [] self.addElementChoicesPs += DEFINES.ELEMENT # gets all the elements i.e. = PS rules currentList = self.pdef.getCurrentListObject() for element in currentList.ElementDefData: if element.Name in self.addElementChoicesPs: self.addElementChoicesPs.remove(element.Name) else: print ("Element Name %s not found in Elements for PS rule" %(element.Name)) if len(currentList.ElementDefData) >= 8 or len(self.addElementChoicesPs) == 0: flag = False else: flag = True self.addElementButton.Enable(flag) #print("%s - addElementChoicesPs=%s" % (func, self.addElementChoicesPs)) #DBGDBG def loadAndDisplayPlistDefFile(self, file, wx, pdef, statusBar, parent): """ loadAndDisplayPlistDefFile - get a saved plistDef object from a PDEF file and update the list panel""" func = 'loadAndDisplayPlistDefFile' self.pdef = pdef self.StatusBar = statusBar self.parent = parent print("%s load plistDef %d, NumLists=%d" % (func, pdef.CurrentListView, pdef.NumLists)) # DBGDBG currentListObject = self.pdef.getCurrentListObject() # If this list is to be the displayed list panel[ie pdef.CurrentListView] # then restore the list panel & enable/disable the AddElement buttons # restore the list's element panels that exist but hide them # only show & restore the specified element [ie list.CurrentElementView] # print("%s thisListNum=%d, CurrentListView=%d" % (func, pdef.CurrentListView, pdef.CurrentListView)) # DBGDBG if(self.listPanelWidgets == []): self.createListPanel(wx, parent, pdef.CurrentListView, pdef, statusBar) else: # in case list or element panels all ready exist ... self.hideListPanel() for i in self.listPanelWidgets: i.Show() self.setListPanelToCurrentListView() #currentListObject.ListModified = False def printPlistDefs(self, pdef, f): """printPlistDefs - write all created PLIST_DEFs to the specified human readable text file for printing""" # pdef.PolListInfo is a dictionary of 8 PLIST_DEF's from '0' to '7' # or None if that list was not added # i.e. {'0':PLIST_DEF or None, ... '7':PLIST_DEF or None} # i = '0' # i is 0 based index for loop control cnt = '1' # cnt is 1 based 'i' for printing while(i<'8'): print("PlistInfo", cnt, " = ", pdef.PolListInfo[i], file=f) if(pdef.PolListInfo[i] != None): self.printPlistDef(pdef.PolListInfo[i], f) # write this PolListInfo[] i = str(int(i) + 1) cnt = str(int(cnt) + 1) def printPlistDef(self, plistDef, f): """printPlistDef - write this PLIST_DEF to the specified human readable text file for printing""" #print("printPlistDef - PLIST_DEF object: %s" % (plistDef)) # DBGDBG print("LdefSize", " = ", plistDef.LdefSize, file=f) print("Tag", " = ", plistDef.Tag, file=f) print("ListVersion", " = ", plistDef.ListVersionMajor, ".", plistDef.ListVersionMinor, sep='', file=f) print("ListValid", " = ", plistDef.ListValid, file=f) print("ListModified", " = ", plistDef.ListModified, file=f) print("SigAlgorithm", " = ", hex(plistDef.SigAlgorithm), file=f) print("sigAlgorithmHash", " = ", hex(plistDef.sigAlgorithmHash), file=f) print("PolicyElementSize", " = ", plistDef.PolicyElementSize, file=f) print("CurrentElementView", " = ", plistDef.CurrentElementView, file=f) print("SyncRevCount", " = ", plistDef.SyncRevCount, file=f) print("AllowedCounter", " = ", plistDef.RevokeCounter, file=f) print("RevocationCounter", " = ", plistDef.RevocationCounter, file=f) print("KeySize", " = ", plistDef.KeySize, file=f) print("PubKeyFile", " = ", plistDef.PubKeyFile, file=f) print("PvtKeyFile", " = ", plistDef.PvtKeyFile, file=f) currentListObject = plistDef # print the element summary showing which elements were created # Lists always contain all elements, even if they haven't been added # so need to check if they should be included for element in plistDef.ElementDefData: print("%s DefData[Index]"% (element.Name), " = ", element, file=f) element.printDef(f) print("\n", file=f) # for readability # def enablePconfOverridePsPolicyCheckbox(self, value): # """enablePconfOverridePsPolicyCheckbox - if current list has a PCONF element, enable its OverridePsPolicy checkbox""" # # currentList = self.pdef.getCurrentListObject() # if(currentList.PconfDefData[DEFINES.DEFDATA_INDEX['SHA256']].IncludeInList == True): # pconf256.enablePconfOverridePsPolicyCheckbox(value) # if(currentList.PconfDefData[DEFINES.DEFDATA_INDEX['SHA1']].IncludeInList == True): # pconf1.enablePconfOverridePsPolicyCheckbox(value) # if(currentList.PconfLegacyDefData[DEFINES.DEFDATA_INDEX['SHA1']].IncludeInList == True): # pconf0.enablePconfOverridePsPolicyCheckbox(value) def hideAllPanels( self ): """hideAllPanels - hide all the element panels""" for element in self.includedElements: element.hidePanel() def hideThisPanel( self, panelToHide ): """hideThisPanel""" for element in self.includedElements: found = element.isElementType(panelToHide) if found: element.hidePanel() print("hideThisPanel: %s" % (panelToHide)) # DBGDBG # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcp-gen2/mle.py0000644000000000000000000004757514210363175013635 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import MLE_DEF from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # TXT Policy Generator Tool # MLE Class - Policy Definition File Lists # class MLE( ElementGui ): CONST_TITLE = "Choose Hash File" CONST_WILDCARD = "Hash file (*.hash)|*.hash|" \ "All Files (*.*)|*.*" """__init__() - MLE class constructor""" def __init__( self, hashAlg): self.mlePanelWidgets = [] self.panelCreated = False try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print("MLE::__init__ - invalid hashAlg=%d" % (hashAlg)) return self.myIndex = DEFINES.DEFDATA_INDEX[hashAlgName] #if( hashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA256 #elif( hashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA1 #else: # print("MLE::__init__ - invalid hashAlg=%d" % (hashAlg)) self.myHashAlg = hashAlg # # create the MLE Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createPanel - create the List Panel""" #print("createOrShowMlePanel hashAlg=%d, panelCreated == %s" % (self.myHashAlg, self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() # Get the list corresponds to this element. currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the Mle Panel sizers #self.mlePanelSizer = wx.BoxSizer(wx.VERTICAL) self.mleGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #self.mleHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.mlePanel = wx.Panel(parent, -1) self.mlePanel.SetSizer(self.mleGridSizer) mleLabelText1 = "MLE" mleLabelText2 = "Element" mleLabel1 = wx.StaticText(self.mlePanel, -1, mleLabelText1) mleLabel2 = wx.StaticText(self.mlePanel, -1, mleLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) mleLabel1.SetFont( font ) self.mleGridSizer.Add( mleLabel1, pos=(0, 3)) self.mlePanelWidgets.append(mleLabel1) mleLabel2.SetFont( font ) self.mleGridSizer.Add( mleLabel2, pos=(0, 4)) self.mlePanelWidgets.append(mleLabel2) typeLabel = wx.StaticText(self.mlePanel, label="Type") self.mleGridSizer.Add( typeLabel, pos=(1,3)) self.mlePanelWidgets.append(typeLabel) typeEdit = wx.TextCtrl( self.mlePanel, value="MLE", size=(40, -1)) typeEdit.Enable( False ) self.mleGridSizer.Add( typeEdit, pos=(1,4)) self.mlePanelWidgets.append(typeEdit) contolOptionsLabel = wx.StaticText(self.mlePanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) contolOptionsLabel.SetFont( font ) # override PS policy bit is applicable only if PO policy rules self.overridePsPolicy = wx.CheckBox(self.mlePanel, label="Override PS Policy") if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) self.mleGridSizer.Add(contolOptionsLabel, pos=(0,9), span=(1,2), flag=wx.BOTTOM, border=5) self.mleGridSizer.Add(self.overridePsPolicy, pos=(1,9), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) self.mlePanelWidgets.append(contolOptionsLabel) self.mlePanelWidgets.append(self.overridePsPolicy) # STPM is required bit ElementPolicyControl[1] #self.stmIsRequired = wx.CheckBox(self.mlePanel, label="STM is required") #self.mleGridSizer.Add(self.stmIsRequired, pos=(2,9), span=(1,2), flag=wx.BOTTOM, border=5) #self.stmIsRequired.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) # TODO: add function to handle event. #self.mlePanelWidgets.append(self.stmIsRequired) try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == self.myHashAlg)).next() except StopIteration: print("createOrShowMlePanel - invalid myHashAlg=%d" % (self.myHashAlg)) #if(self.myHashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # hashAlgStr = "SHA256" #elif(self.myHashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # hashAlgStr = "SHA1" #else: # print("createOrShowMlePanel - invalid myHashAlg=%d" % (self.myHashAlg)) hashAlgLabel = wx.StaticText(self.mlePanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) hashAlgLabel.SetFont( font ) self.mleGridSizer.Add(hashAlgLabel, pos=(0,20)) self.mlePanelWidgets.append(hashAlgLabel) hashAlgEdit = wx.TextCtrl( self.mlePanel, size=(75, -1), value=hashAlgStr ) hashAlgEdit.Enable(False) self.mleGridSizer.Add(hashAlgEdit, pos=(1,20)) self.mlePanelWidgets.append(hashAlgEdit) minSinitVersionLabel = wx.StaticText(self.mlePanel, label="Min SINIT Version: ") self.mleGridSizer.Add(minSinitVersionLabel, pos=(2,4)) self.mlePanelWidgets.append(minSinitVersionLabel) minSinitVersion = pdef.SinitMinVersion # get current value #currentList.MleDefData[self.myIndex].SinitMinVersion = minSinitVersion currentList.ElementDefData[self.myIndex].SinitMinVersion = minSinitVersion self.minSinitVersionEdit = wx.TextCtrl( self.mlePanel, value=str(minSinitVersion), size=(30, -1)) self.mleGridSizer.Add( self.minSinitVersionEdit, pos=(2,5)) self.minSinitVersionEdit.Bind(wx.EVT_TEXT, self.onMinSinitVersion) self.mlePanelWidgets.append(self.minSinitVersionEdit) self.addButton = wx.Button( self.mlePanel, -1, label=" Add ") self.mleGridSizer.Add( self.addButton, pos=(4,3)) self.mlePanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick) self.removeButton = wx.Button( self.mlePanel, -1, label=" Remove ") self.removeButton.Enable(False) self.mleGridSizer.Add( self.removeButton, pos=(4,5)) self.mlePanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick) hashListLabel = wx.StaticText(self.mlePanel, label=" Hash File List") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) hashListLabel.SetFont( font ) self.mleGridSizer.Add( hashListLabel, pos=(3,4)) self.mlePanelWidgets.append(hashListLabel) fileCntLabel = wx.StaticText(self.mlePanel, label="Number of Files") self.mleGridSizer.Add( fileCntLabel, pos=(5,3)) self.mlePanelWidgets.append(fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.mlePanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) self.mleGridSizer.Add( self.fileCntEdit, pos=(5,4)) self.mlePanelWidgets.append(self.fileCntEdit) hashFileList = [''] self.hashListBox = wx.TextCtrl( self.mlePanel, value="", size=(150, 120), style = wx.TE_MULTILINE) # Note: add |wx.HSCROLL to get a horiz scroll bar # hashListBox must be enabled so can select items to remove self.hashListBox.Bind(wx.EVT_TEXT, self.onHashListBoxEdit) self.hashListBox.SetInsertionPoint(0) self.mleGridSizer.Add( self.hashListBox, pos=(4,4)) self.mlePanelWidgets.append(self.hashListBox) #print("MLE createPanel - len(Widgets)=%d" % (len(self.mlePanelWidgets))) #DBGDBG #self.mleHorizSizer.Add(self.mleGridSizer, 0, wx.ALL, 5) #self.mlePanelSizer.Add(self.mleHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.mlePanelSizer) self.mlePanelWidgets.append(self.mlePanel) parentSizer.Add(self.mlePanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) print("parent sizer type = %s size = %d, %d" %(type(parentSizer).__name__, w, h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(currentList, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the Mle panel""" #print("MLE hidePanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.mlePanelWidgets))) #DBGDBG for i in self.mlePanelWidgets: i.Hide() def showPanel(self): """showPanel - show the mle panel""" #print("MLE showPanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.mlePanelWidgets))) #DBGDBG if self.panelCreated: for i in self.mlePanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - MLE""" currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = self.myHashAlg currentList.ElementDefData[self.myIndex].SinitMinVersion = 0 currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].HashFiles = [] def onOverridePsPolicy(self, event): currentList = self.pdef.getCurrentListObject() self.setListModified() # set/clear bit 0 per MLE Dev Guide PolEltControl def if(event.Checked() == True): currentList.ElementDefData[self.myIndex].Control = 1 else: currentList.ElementDefData[self.myIndex].Control = 0 def onMinSinitVersion(self, event): value = event.GetString() currentList = self.pdef.getCurrentListObject() self.setListModified() currentList.ElementDefData[self.myIndex].SinitMinVersion = int(value) #print("MLE::onMinSinitVersion - SinitMinVersion = %d" % (currentList.ElementDefData[self.myIndex].SinitMinVersion)) # DBGDBG # only supports adding files with the add button, not entering the names directly def onHashListBoxEdit(self, event): """onHashListBoxEdit""" #print("in MLE::onHashListBoxEdit") # DBGDBG # tell the user to add button and clear the field self.StatusBar.SetStatusText("Please clear the entry, then use the Add button to add hash files to the list") #self.hashListBox.Undo() #TODO: wxPython: onHashListBoxEdit - Clear() and Undo() both generate an event causing: RuntimeError: maximum recursion depth exceeded def onAddButtonClick(self, event): """onAddButtonClick - add a hash file to the list""" filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # update the file count and enable the remove button lineCnt = currentList.ElementDefData[self.myIndex].NumbHashes #print("onAddButtonClick: was %i lines" % (lineCnt)) # DBGDBG lineCnt += 1 # MaxHashes = 0 means there is no limit on the number of hash files allowed if(self.pdef.MaxHashes != 0): if(lineCnt > self.pdef.MaxHashes): self.StatusBar.SetStatusText("Only %d files can be added." % (self.pdef.MaxHashes)) return #print("onAddButtonClick: now %i lines" % (lineCnt)) # DBGDBG self.fileCntEdit.ChangeValue(str(lineCnt)) self.removeButton.Enable(True) hashFileList = currentList.ElementDefData[self.myIndex].HashFiles hashFileList.append(filename) #print("new hashFileList = %s" % (hashFileList)) # DBGDBG # insert the new file into mle.HashFiles self.setListModified() currentList.ElementDefData[self.myIndex].HashFiles = hashFileList currentList.ElementDefData[self.myIndex].NumbHashes = lineCnt #print("ElementDefData[self.myIndex].NumbHashes=%i, HashFiles = %s" % # (currentList.ElementDefData[self.myIndex].NumbHashes, currentList.ElementDefData[self.myIndex].HashFiles)) # DBGDBG # since hashListBox.AppendText() generates an event to onHashListBoxEdit() # and since hashListBoxEdit has to be enabled so text can be selected for Remove # and direct text entry by the user into hashListBoxEdit is not supported due the complexity of validating it ... # # hashListBox.ChangeValue() doesn't generate an event but only takes a string, not a hashFileList which is a list ie '[]' # so form a single string containing everything in hashFileList and update hashListBox using ChangeValue(hashFileString) hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) self.hashListBox.ChangeValue(hashFileString) def onRemoveButtonClick(self, event): """onRemoveButtonClick - remove the selected entry from the hash file list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return selection = self.hashListBox.GetStringSelection() self.StatusBar.SetStatusText("Removed selection %s" % (selection)) # selection may not be a full line ... See if the selection is contianed in any of hashFileList's entries currentList = self.pdef.getCurrentListObject() hashFileList = currentList.ElementDefData[self.myIndex].HashFiles for entry in hashFileList: #print("entry=%s" % (entry)) # DBGDBG start = entry.find(selection) if(start != -1): # -1 means not found, else find returns the starting index of selection #print("Found: %s at %i" % (selection, start)) # DBGDBG # entry was found, but was it a partial selection? if(selection not in hashFileList): # is selection on the GUI in PDEF's hashFileList? # partial selection #print("Partial selection %s not found in %s." % (selection, hashFileList)) # DBGDBG self.StatusBar.SetStatusText("Please select the entire line") break else: # Full selection, so remove that entry # decr mle.NumbHashes & update NumberOfFiles widget fileCnt = int(self.fileCntEdit.GetValue()) fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt hashFileList.remove(selection) # remove the selection from the PDEF object #print("hashFileList=%s" % (hashFileList)) # DBGDBG if(fileCnt == 0): # disable REMOVE if no more files left self.removeButton.Enable(False) self.hashListBox.ChangeValue('') else: # rebuild the content of hashFileEdit from hashFileList and update the screen with ChangeValue # to avoid generating an event and to clear the previous LF hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) # DBGDBG self.hashListBox.ChangeValue(hashFileString) #print("hashListBox=%s" % (self.hashListBox.GetValue())) # DBGDBG self.setListModified() currentList.ElementDefData[self.myIndex].HashFiles = hashFileList break else: self.StatusBar.SetStatusText("Selection %s not found. Please select only a single line" % (selection)) # DBGDBG def writeMleDef(self, mleDefData, f): """writeMleDef - write the Mle Def to the specified file""" print("writeMleDef dump, hashAlg=%d" % (self.myHashAlg)) # DBGDBG pickle.dump(mleDefData, f) # write out the mleDefData object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to mle panel widgets""" self.minSinitVersionEdit.ChangeValue("0") self.addButton.Enable(True) self.removeButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.hashListBox.ChangeValue("") def restorePanel(self, currentList, maxHashes): """restorePanel - restore the MLE element panel from the specified PLIST_DEF""" print("restorePanel - MLE") # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) self.minSinitVersionEdit.ChangeValue(str(currentList.ElementDefData[self.myIndex].SinitMinVersion)) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # enable remove if >0 hashes flag = False if(numbHashes > 0): flag = True self.removeButton.Enable(flag) self.fileCntEdit.ChangeValue(str(numbHashes)) # form a string from hashFileList and update hashListBox string = utilities.formStringFromListOfStrings(currentList.ElementDefData[self.myIndex].HashFiles) self.hashListBox.ChangeValue(string) #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # #print("Mle setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True # self.pdef.Modified = True # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcp-gen2/mleLegacy.py0000644000000000000000000004440714210363175014751 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import MLELEGACY_DEF from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # TXT Policy Generator Tool # MLE Class - Policy Definition File Lists # class MLELegacy( ElementGui ): CONST_TITLE = "Choose Hash File" CONST_WILDCARD = "Hash file (*.hash)|*.hash|" \ "All Files (*.*)|*.*" """__init__() - MLE class constructor""" def __init__( self ): self.mlePanelWidgets = [] self.panelCreated = False # # create the MLE Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createMlePanel - create the List Panel""" #print("createOrShowPanel panelCreated == %s" % (self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the Mle Panel sizers #self.mlePanelSizer = wx.BoxSizer(wx.VERTICAL) self.mleGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #self.mleHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.mlePanel = wx.Panel(parent, -1) self.mlePanel.SetSizer(self.mleGridSizer) mleLabelText1 = "MLE" mleLabelText2 = "Element" mleLabel1 = wx.StaticText(self.mlePanel, -1, mleLabelText1) mleLabel2 = wx.StaticText(self.mlePanel, -1, mleLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) mleLabel1.SetFont( font ) self.mleGridSizer.Add( mleLabel1, pos=(0, 3)) self.mlePanelWidgets.append(mleLabel1) mleLabel2.SetFont( font ) self.mleGridSizer.Add( mleLabel2, pos=(0, 4)) self.mlePanelWidgets.append(mleLabel2) typeLabel = wx.StaticText(self.mlePanel, label="Type") self.mleGridSizer.Add( typeLabel, pos=(1,3)) self.mlePanelWidgets.append(typeLabel) typeEdit = wx.TextCtrl( self.mlePanel, value="MLE", size=(40, -1)) typeEdit.Enable( False ) self.mleGridSizer.Add( typeEdit, pos=(1,4)) self.mlePanelWidgets.append(typeEdit) contolOptionsLabel = wx.StaticText(self.mlePanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) contolOptionsLabel.SetFont( font ) # override PS policy bit is applicable only if PO policy rules self.overridePsPolicy = wx.CheckBox(self.mlePanel, label="Override PS Policy") if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) self.mleGridSizer.Add(contolOptionsLabel, pos=(0,9), span=(1,2), flag=wx.BOTTOM, border=5) self.mleGridSizer.Add(self.overridePsPolicy, pos=(1,9), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) self.mlePanelWidgets.append(contolOptionsLabel) self.mlePanelWidgets.append(self.overridePsPolicy) # STPM is required bit ElementPolicyControl[1] #self.stmIsRequired = wx.CheckBox(self.mlePanel, label="STM is required") #self.mleGridSizer.Add(self.stmIsRequired, pos=(2,9), span=(1,2), flag=wx.BOTTOM, border=5) #self.stmIsRequired.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) # TODO: add function to handle event. #self.mlePanelWidgets.append(self.stmIsRequired) hashList = ['SHA1'] hashAlgLabel = wx.StaticText(self.mlePanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) hashAlgLabel.SetFont( font ) self.mleGridSizer.Add(hashAlgLabel, pos=(0,20)) self.mlePanelWidgets.append(hashAlgLabel) hashAlgEdit = wx.ComboBox( self.mlePanel, size=(75, -1), value="SHA1", choices=hashList, style=wx.CB_DROPDOWN ) self.mleGridSizer.Add(hashAlgEdit, pos=(1,20)) self.mlePanelWidgets.append(hashAlgEdit) minSinitVersionLabel = wx.StaticText(self.mlePanel, label="Min SINIT Version: ") self.mleGridSizer.Add(minSinitVersionLabel, pos=(2,4)) self.mlePanelWidgets.append(minSinitVersionLabel) minSinitVersion = pdef.SinitMinVersion # get current value currentList.ElementDefData[self.myIndex].SinitMinVersion = minSinitVersion self.minSinitVersionEdit = wx.TextCtrl( self.mlePanel, value=str(minSinitVersion), size=(30, -1)) self.mleGridSizer.Add( self.minSinitVersionEdit, pos=(2,5)) self.minSinitVersionEdit.Bind(wx.EVT_TEXT, self.onMinSinitVersion) self.mlePanelWidgets.append(self.minSinitVersionEdit) self.addButton = wx.Button( self.mlePanel, -1, label=" Add ") self.mleGridSizer.Add( self.addButton, pos=(4,3)) self.mlePanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick) self.mlePanelWidgets.append(self.addButton) self.removeButton = wx.Button( self.mlePanel, -1, label=" Remove ") self.mleGridSizer.Add( self.removeButton, pos=(4,5)) self.mlePanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick) self.mlePanelWidgets.append(self.removeButton) self.hashListLabel = wx.StaticText(self.mlePanel, label=" Hash File List") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.hashListLabel.SetFont( font ) self.mleGridSizer.Add( self.hashListLabel, pos=(3,4)) self.mlePanelWidgets.append(self.hashListLabel) self.fileCntLabel = wx.StaticText(self.mlePanel, label="Number of Files") self.mleGridSizer.Add( self.fileCntLabel, pos=(5,3)) self.mlePanelWidgets.append(self.fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.mlePanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) self.mleGridSizer.Add( self.fileCntEdit, pos=(5,4)) self.mlePanelWidgets.append(self.fileCntEdit) hashFileList = [''] self.hashListBox = wx.TextCtrl( self.mlePanel, value="", size=(150, 120), style = wx.TE_MULTILINE) # Note: add |wx.HSCROLL to get a horiz scroll bar # hashListBox must be enabled so can select items to remove self.hashListBox.Bind(wx.EVT_TEXT, self.onHashListBoxEdit) self.hashListBox.SetInsertionPoint(0) self.mleGridSizer.Add( self.hashListBox, pos=(4,4)) self.mlePanelWidgets.append(self.hashListBox) self.mlePanelWidgets.append(self.mlePanel) #self.mleHorizSizer.Add(self.mleGridSizer, 0, wx.ALL, 5) #self.mlePanelSizer.Add(self.mleHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.mlePanelSizer) parentSizer.Add(self.mlePanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) print("parent sizer type = %s size = %d, %d" %(type(parentSizer).__name__, w, h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(currentList, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the Mle panel""" for i in self.mlePanelWidgets: i.Hide() def showPanel(self): """showPanel - show the mle panel""" if self.panelCreated: for i in self.mlePanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - MLE""" currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = 0 currentList.ElementDefData[self.myIndex].SinitMinVersion = 0 currentList.ElementDefData[self.myIndex].HashAlg = 0 currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].HashFiles = [] def onOverridePsPolicy(self, event): currentList = self.pdef.getCurrentListObject() self.setListModified() # set/clear bit 0 per MLE Dev Guide PolEltControl def if(event.Checked() == True): currentList.MleLegacyDefData[self.myIndex].Control = 1 else: currentList.MleLegacyDefData[self.myIndex].Control = 0 def onMinSinitVersion(self, event): value = event.GetString() currentList = self.pdef.getCurrentListObject() self.setListModified() currentList.ElementDefData[self.myIndex].SinitMinVersion = int(value) #print("MLE::onMinSinitVersion - SinitMinVersion = %d" % (currentList.ElementDefData[self.myIndex].SinitMinVersion)) # DBGDBG # only supports adding files with the add button, not entering the names directly def onHashListBoxEdit(self, event): """onHashListBoxEdit""" #print("in MLE::onHashListBoxEdit") # DBGDBG # tell the user to add button and clear the field self.StatusBar.SetStatusText("Please clear the entry, then use the Add button to add hash files to the list") #self.hashListBox.Undo() #TODO: wxPython: onHashListBoxEdit - Clear() and Undo() both generate an event causing: RuntimeError: maximum recursion depth exceeded def onAddButtonClick(self, event): """onAddButtonClick - add a hash file to the list""" workdir = self.pdef.WorkingDirectory filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # update the file count and enable the remove button lineCnt = currentList.ElementDefData[self.myIndex].NumbHashes #print("onAddButtonClick: was %i lines" % (lineCnt)) # DBGDBG lineCnt += 1 # MaxHashes = 0 means there is no limit on the number of hash files allowed if(self.pdef.MaxHashes != 0): if(lineCnt > self.pdef.MaxHashes): self.StatusBar.SetStatusText("Only %d files can be added." % (self.pdef.MaxHashes)) return #print("onAddButtonClick: now %i lines" % (lineCnt)) # DBGDBG self.fileCntEdit.ChangeValue(str(lineCnt)) self.removeButton.Enable(True) hashFileList = currentList.ElementDefData[self.myIndex].HashFiles hashFileList.append(filename) #print("new hashFileList = %s" % (hashFileList)) # DBGDBG # insert the new file into mle.HashFiles self.setListModified() currentList.ElementDefData[self.myIndex].HashFiles = hashFileList currentList.ElementDefData[self.myIndex].NumbHashes = lineCnt #print("MleLegacyDefData.NumbHashes=%i, HashFiles = %s" % (currentList.MleLegacyDefData[DEFINES.DEFDATA_INDEX['SHA1']].NumbHashes, currentList.MleLegacyDefData[DEFINES.DEFDATA_INDEX['SHA1']].HashFiles)) # DBGDBG # since hashListBox.AppendText() generates an event to onHashListBoxEdit() # and since hashListBoxEdit has to be enabled so text can be selected for Remove # and direct text entry by the user into hashListBoxEdit is not supported due the complexity of validating it ... # # hashListBox.ChangeValue() doesn't generate an event but only takes a string, not a hashFileList which is a list ie '[]' # so form a single string containing everything in hashFileList and update hashListBox using ChangeValue(hashFileString) hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) self.hashListBox.ChangeValue(hashFileString) def onRemoveButtonClick(self, event): """onRemoveButtonClick - remove the selected entry from the hash file list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return selection = self.hashListBox.GetStringSelection() self.StatusBar.SetStatusText("Removed selection %s" % (selection)) # selection may not be a full line ... See if the selection is contianed in any of hashFileList's entries currentList = self.pdef.getCurrentListObject() hashFileList = currentList.ElementDefData[self.myIndex].HashFiles for entry in hashFileList: #print("entry=%s" % (entry)) # DBGDBG start = entry.find(selection) if(start != -1): # -1 means not found, else find returns the starting index of selection #print("Found: %s at %i" % (selection, start)) # DBGDBG # entry was found, but was it a partial selection? if(selection not in hashFileList): # is selection on the GUI in PDEF's hashFileList? # partial selection #print("Partial selection %s not found in %s." % (selection, hashFileList)) # DBGDBG self.StatusBar.SetStatusText("Please select the entire line") break else: # Full selection, so remove that entry # decr mle.NumbHashes & update NumberOfFiles widget fileCnt = int(self.fileCntEdit.GetValue()) fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt hashFileList.remove(selection) # remove the selection from the PDEF object #print("hashFileList=%s" % (hashFileList)) # DBGDBG if(fileCnt == 0): # disable REMOVE if no more files left self.removeButton.Enable(False) self.hashListBox.ChangeValue('') else: # rebuild the content of hashFileEdit from hashFileList and update the screen with ChangeValue # to avoid generating an event and to clear the previous LF hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) # DBGDBG self.hashListBox.ChangeValue(hashFileString) #print("hashListBox=%s" % (self.hashListBox.GetValue())) # DBGDBG self.setListModified() currentList.ElementDefData[self.myIndex].HashFiles = hashFileList break else: self.StatusBar.SetStatusText("Selection %s not found. Please select only a single line" % (selection)) # DBGDBG def writeMleDef(self, mleDefData, f): """writeMleDef - write the Mle Def to the specified file""" #print("writeMleDef dump") # DBGDBG pickle.dump(mleDefData, f) # write out the mleDefData object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to mle panel widgets""" self.minSinitVersionEdit.ChangeValue("0") self.addButton.Enable(True) self.removeButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.hashListBox.ChangeValue("") def restorePanel(self, currentList, maxHashes): """restorePanel - restore the MLE element panel from the specified PLIST_DEF""" print("restorePanel - MLE") # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) self.minSinitVersionEdit.ChangeValue(str(currentList.ElementDefData[self.myIndex].SinitMinVersion)) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # enable remove if >0 hashes flag = True if(numbHashes > 0): flag = False self.removeButton.Enable(flag) self.fileCntEdit.ChangeValue(str(numbHashes)) # form a string from hashFileList and update hashListBox string = utilities.formStringFromListOfStrings(currentList.ElementDefData[self.myIndex].HashFiles) self.hashListBox.ChangeValue(string) #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # #print("Mle setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True tboot-1.10.5/lcp-gen2/pconf.py0000644000000000000000000007341014210363175014150 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import PCONF_DEF from pdef import PCONF_INFO from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # # TXT Policy Generator Tool # PCONF Class - Policy Definition File Lists # class PCONF( ElementGui ): CONST_TITLE = "Choose PCR File" CONST_WILDCARD = "Pcr file (*.pcr)|*.pcr|" \ "All Files (*.*)|*.*" """__init__() - PCONF class constructor""" def __init__( self, hashAlg ): self.pconfPanelWidgets = [] self.panelCreated = False try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print("PCONF::__init__ - invalid hashAlg=%d" % (hashAlg)) return self.myIndex = -1 # myIndex is set in createOrShowPanel() #if( hashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA256 #elif( hashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA1 #else: # print("PCONF::__init__ - invalid hashAlg=%d" % (hashAlg)) self.myHashAlg = hashAlg # # create the PCONF Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createOrShowPanel - create the List Panel""" #print("createOrShowPconfPanel hashAlg=%d, panelCreated == %s" % (self.myHashAlg, self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.pcrFileCombo.Clear() self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the PCONF Panel sizers #self.pconfPanelSizer = wx.BoxSizer(wx.VERTICAL) pconfGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #pconfHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.pconfPanel = wx.Panel(parent, -1) self.pconfPanel.SetSizer(pconfGridSizer) pconfLabelText1 = "PCONF" pconfLabelText2 = "Element" pconfLabel1 = wx.StaticText(self.pconfPanel, -1, pconfLabelText1) pconfLabel2 = wx.StaticText(self.pconfPanel, -1, pconfLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) pconfLabel1.SetFont( font ) pconfGridSizer.Add( pconfLabel1, pos=(0, 3)) self.pconfPanelWidgets.append(pconfLabel1) pconfLabel2.SetFont( font ) pconfGridSizer.Add( pconfLabel2, pos=(0, 4)) self.pconfPanelWidgets.append(pconfLabel2) self.typeLabel = wx.StaticText(self.pconfPanel, label="Type") pconfGridSizer.Add( self.typeLabel, pos=(1,3)) self.pconfPanelWidgets.append(self.typeLabel) self.typeEdit = wx.TextCtrl( self.pconfPanel, value="PCONF", size=(40, -1)) self.typeEdit.Enable( False ) pconfGridSizer.Add( self.typeEdit, pos=(1,4)) self.pconfPanelWidgets.append(self.typeEdit) self.contolOptionsLabel = wx.StaticText(self.pconfPanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.contolOptionsLabel.SetFont( font ) # override PS policy bit is applicable only if PO policy rules self.overridePsPolicy = wx.CheckBox(self.pconfPanel, label="Override PS Policy") if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) pconfGridSizer.Add(self.contolOptionsLabel, pos=(0,8), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy, self.overridePsPolicy) pconfGridSizer.Add(self.overridePsPolicy, pos=(1,8), span=(1,2), flag=wx.BOTTOM, border=5) self.pconfPanelWidgets.append(self.contolOptionsLabel) self.pconfPanelWidgets.append(self.overridePsPolicy) hashAlgStr = self.getHashAlgName() if hashAlgStr == None: print("createOrShowPconfPanel - invalid myHashAlg=%d" % (self.myHashAlg)) self.hashAlgLabel = wx.StaticText(self.pconfPanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.hashAlgLabel.SetFont( font ) pconfGridSizer.Add(self.hashAlgLabel, pos=(0,20)) self.pconfPanelWidgets.append(self.hashAlgLabel) self.hashAlgEdit = wx.TextCtrl( self.pconfPanel, size=(75, -1), value=hashAlgStr ) self.hashAlgEdit.Enable(False) pconfGridSizer.Add(self.hashAlgEdit, pos=(1,20)) self.pconfPanelWidgets.append(self.hashAlgEdit) pcrFile = "" self.pcrFileFileLabel = wx.StaticText(self.pconfPanel, label="PCR File") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.pcrFileFileLabel.SetFont( font ) pconfGridSizer.Add( self.pcrFileFileLabel, pos=(2,3)) self.pconfPanelWidgets.append(self.pcrFileFileLabel) self.pcrFileCombo = wx.ComboBox( self.pconfPanel, value=pcrFile, size=(200, -1), choices=pcrFile, style=wx.CB_DROPDOWN) self.pcrFileCombo.Enable( False ) # prevent selection since pulldown is empty self.pcrFileCombo.Bind(wx.EVT_TEXT, self.onPcrFileCombo, self.pcrFileCombo) pconfGridSizer.Add( self.pcrFileCombo, pos=(2,4)) self.pconfPanelWidgets.append(self.pcrFileCombo) self.fileSelectionLabel = wx.StaticText(self.pconfPanel, label="Selected File") pconfGridSizer.Add( self.fileSelectionLabel, pos=(7,3)) self.pconfPanelWidgets.append(self.fileSelectionLabel) self.fileSelectionEdit = wx.TextCtrl( self.pconfPanel, value=" ", size=(40, -1)) self.fileSelectionEdit.Enable( False ) pconfGridSizer.Add( self.fileSelectionEdit, pos=(7,4)) self.pconfPanelWidgets.append(self.fileSelectionEdit) self.fileCntLabel = wx.StaticText(self.pconfPanel, label="Number of Files") pconfGridSizer.Add( self.fileCntLabel, pos=(8,3)) self.pconfPanelWidgets.append(self.fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.pconfPanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) pconfGridSizer.Add( self.fileCntEdit, pos=(8,4)) self.pconfPanelWidgets.append(self.fileCntEdit) self.updateButton = wx.Button( self.pconfPanel, -1, label="Apply PCR Selection") self.updateButton.Enable( False ) pconfGridSizer.Add( self.updateButton, pos=(7,8)) self.pconfPanelWidgets.append(self.updateButton) self.updateButton.Bind(wx.EVT_BUTTON, self.onUpdateButtonClick, self.updateButton) self.addButton = wx.Button( self.pconfPanel, -1, label=" Add ") pconfGridSizer.Add( self.addButton, pos=(3,4)) self.pconfPanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick, self.addButton) self.removeButton = wx.Button( self.pconfPanel, -1, label=" Remove ") self.removeButton.Enable( False ) pconfGridSizer.Add( self.removeButton, pos=(4,4)) self.pconfPanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick, self.removeButton) #self.pcrSelectionLabel = wx.StaticText(self.pconfPanel, -1, "PCR Selection") #font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) #self.pcrSelectionLabel.SetFont( font ) self.pcrSelectionLabel1 = wx.StaticText(self.pconfPanel, -1, "PCR ") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.pcrSelectionLabel1.SetFont( font ) self.pcrSelectionLabel2 = wx.StaticText(self.pconfPanel, -1, "Selection") self.pcrSelectionLabel2.SetFont( font ) self.pcr0 = wx.CheckBox(self.pconfPanel, label="0") self.pcr1 = wx.CheckBox(self.pconfPanel, label="1") self.pcr2 = wx.CheckBox(self.pconfPanel, label="2") self.pcr3 = wx.CheckBox(self.pconfPanel, label="3") self.pcr4 = wx.CheckBox(self.pconfPanel, label="4") self.pcr5 = wx.CheckBox(self.pconfPanel, label="5") self.pcr6 = wx.CheckBox(self.pconfPanel, label="6") self.pcr7 = wx.CheckBox(self.pconfPanel, label="7") self.pcrSelectionCheckboxes =[self.pcr7, self.pcr6, self.pcr5, self.pcr4, self.pcr3, self.pcr2, self.pcr1, self.pcr0] self.enableDisablePcrSelectionCheckBoxes(False) # disable the check boxes til the 1st file is added #pconfGridSizer.Add(self.pcrSelectionLabel, pos=(2,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcrSelectionLabel1, pos=(2,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcrSelectionLabel2, pos=(2,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr7, pos=(3,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr6, pos=(4,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr5, pos=(5,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr4, pos=(6,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr3, pos=(3,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr2, pos=(4,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr1, pos=(5,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr0, pos=(6,8), span=(1,2), flag=wx.BOTTOM, border=5) #self.pconfPanelWidgets.append(self.pcrSelectionLabel) self.pconfPanelWidgets.append(self.pcrSelectionLabel1) self.pconfPanelWidgets.append(self.pcrSelectionLabel2) self.pconfPanelWidgets.append(self.pcr0) self.pconfPanelWidgets.append(self.pcr1) self.pconfPanelWidgets.append(self.pcr2) self.pconfPanelWidgets.append(self.pcr3) self.pconfPanelWidgets.append(self.pcr4) self.pconfPanelWidgets.append(self.pcr5) self.pconfPanelWidgets.append(self.pcr6) self.pconfPanelWidgets.append(self.pcr7) self.pconfPanelWidgets.append(self.pconfPanel) #print("PCONF createPanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.pconfPanelWidgets))) #DBGDBG #pconfHorizSizer.Add(pconfGridSizer, 0, wx.ALL, 5) #self.pconfPanelSizer.Add(pconfHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.pconfPanelSizer) parentSizer.Add(self.pconfPanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) print("parent sizer type = %s size = %d, %d" %(type(parentSizer).__name__, w, h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(currentList, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the Pconf panel""" #print("PCONF hidePanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.pconfPanelWidgets))) #DBGDBG for i in self.pconfPanelWidgets: i.Hide() def showPanel(self): """showPanel - show the Pconf panel""" #print("PCONF showPanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.pconfPanelWidgets))) #DBGDBG if self.panelCreated: for i in self.pconfPanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - PCONF""" self.pcrFileCombo.SetValue(' ') self.clearPcrCheckBoxes() currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = self.myHashAlg currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].PcrInfoSrc = [] def onOverridePsPolicy(self, event): """onOverridePsPolicy - update the Control field""" # set/clear bit 0 per MLE Dev Guide PolEltControl def currentList = self.pdef.getCurrentListObject() self.setListModified() currentList.ElementDefData[self.myIndex].Control = event.Checked() #print("onOverridePsPolicy Control=%d Event=%d" % (currentList.ElementDefData[self.myIndex].Control , event.IsChecked())) def onPcrFileCombo(self, event): """onPcrFileCombo - update which PCR file is selected""" # Get the PcrInfo entry selected by the user and save it in CurrentView currentSelection = self.pcrFileCombo.GetSelection() currentList = self.pdef.getCurrentListObject() self.setListModified() currentList.ElementDefData[self.myIndex].CurrentView = currentSelection #print("onPcrFileCombo: currentSelection=%d, NumbHashes=%d" % (currentSelection, currentList.ElementDefData[self.myIndex].NumbHashes)) #DBGDBG # set the checkboxes to match the current selection and show which element is selected self.showSelection(currentSelection) pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentSelection] pcrSelection = pconf_info.pcrSelect[0] self.setPcrSelectionCheckboxes(pcrSelection) def onUpdateButtonClick(self, event): """onUpdateButtonClick - update the PCR select per the PCR0-7 checkboxes for the current file""" self.updatePcrFileCombo() def updatePcrFileCombo(self): # update the selected PcrInfoSrc[i].pcrSelect[0] with the PCR Selection info set by the user # where i = currentList.ElementDefData[self.myIndex].CurrentView = user's current selection # this indicates which PCRs in the file are evaluated bit = 0 byte = 0 for eachCheckbox in self.pcrSelectionCheckboxes: if(eachCheckbox.IsChecked() == True): x = 1 << (7-bit) #print("updatePcrFileCombo - bit %x is checked, x=%x" % (bit, x)) #DBGDBG else: x = 0 bit += 1 byte |= x #print("updatePcrFileCombo - byte=%x" % (byte)) #DBGDBG newPcrSelection = self.makeListWithEntryForEachBitInByte(byte) currentList = self.pdef.getCurrentListObject() self.setListModified() #currentEntrySelected = self.pcrFileCombo.GetSelection() currentEntrySelected = currentList.ElementDefData[self.myIndex].CurrentView #print("updatePcrFileCombo - currentEntrySelected=%x*****" % (currentEntrySelected)) #DBGDBG pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentEntrySelected] pconf_info.pcrSelect[0] = newPcrSelection #print("updatePcrFileCombo -currentEntrySelected=%d=%s newPcrSelection=%s" % (currentEntrySelected, pconf_info, newPcrSelection)) #DBGDBG filename = pconf_info.pcrFile value = str(newPcrSelection) + " " + filename # replace the selection # update the choices list #TODO: wxPython: updatePcrFileCombo - ComboBox.Replace doesn't work so doing .Clear() .Append's - better way? # XXXXXXX self.pcrFileCombo.Replace( currentEntrySelected, value ) XXXXXXXXXX # Since ComboBox.Replace doesn't work, # Use .Clear() to clear the choices then iterate thru and reconstruct the choices with .Append(eachChoice) self.pcrFileCombo.Clear() self.pcrFileCombo.SetValue( value ) fileCnt = currentList.ElementDefData[self.myIndex].NumbHashes i = 0 #print("updatePcrFileCombo: NumbHashes=%d**StartOfWhile**" % (fileCnt)) #DBGDBG while(i < fileCnt): pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[i] #print("Update: Pconf_info%d=%s NumbHashes=%d, pcrFile=%s pcrSelect[0]=%s --start of loop--" % # (i, pconf_info, fileCnt, pconf_info.pcrFile, pconf_info.pcrSelect[0])) # DBGDBG bit = 0 byte = 0 for eachPcr in pconf_info.pcrSelect[0]: # pcrSelect[0] ordered 7:0, pcrSelectionCheckboxes ordered 0:7 if(eachPcr == 1): x = 1 << (7-bit) #print("updatePcrFileCombo: i=%d: bit %x is set, x=%x byte=%x" % (i, 7-bit, x, byte)) #DBGDBG else: x = 0 bit += 1 byte |= x #print("updatePcrFileCombo - byte=%x" % (byte)) #DBGDBG newPcrSelection = self.makeListWithEntryForEachBitInByte(byte) filename = pconf_info.pcrFile value = str(newPcrSelection) + " " + filename self.pcrFileCombo.Append(value) #print("updatePcrFileCombo: i=%d value=%s --end of loop--" % (i, value )) # DBGDBG i += 1 def onAddButtonClick(self, event): """onAddButtonClick - add a PCR file to the list""" # Present dialogue for user to select a PCR file # Leave PCR Selection checkboxes as is so same setting can be used on next file filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified PCR file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyPcrFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyPcrFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # incr currentList.ElementDefData[self.myIndex].NumbHashes and update NumberOfFiles widget self.setListModified() fileCnt = currentList.ElementDefData[self.myIndex].NumbHashes fileCnt += 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt # add a PCONF_INFO to PCONF_DEF.PcrInfoSrc[] for this PCR file pconf_info = PCONF_INFO() # create a PCONF_INFO currentList.ElementDefData[self.myIndex].PcrInfoSrc.append(pconf_info) #print("pconf_info: NumbHahses=%x pcrSelect[0]=%x, pcrFile=%s" % (fileCnt, pconf_info.pcrSelect[0], pconf_info.pcrFile)) # DBGDBG pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[fileCnt-1] # add the PCONF_INFO to PCONF_DEF # Set currentList.ElementDefData[self.myIndex].PcrInfoSrc[i].pcrSelect[0] = 0 # Set currentList.ElementDefData[self.myIndex].PcrInfoSrc[i].pcrFile = the selected file # where i = currentList.ElementDefData[self.myIndex].CurrentView = user's current selection # Concatenate "PcrInfoSrc[i].pcrSelect" and "PcrInfoSrc[i].pcrFile" per fig 9 # display/append that concatenated value to the comboBox. ex: "00000000 PlatformA_BiosD28.pcr" pconf_info.pcrFile = filename pcrSelectBits = [0,0,0,0,0,0,0,0] # list of each bit in pcrSelect[0] = 00000000 pconf_info.pcrSelect[0] = pcrSelectBits currentList.ElementDefData[self.myIndex].CurrentView = fileCnt-1 print("Add: Pconf_info%d=%s NumbHashes=%d, pcrFile=%s pcrSelect[0]=%s" % (fileCnt-1, pconf_info, fileCnt, pconf_info.pcrFile, pconf_info.pcrSelect[0])) # DBGDBG value = str(pcrSelectBits) + " " + filename self.pcrFileCombo.SetValue( value ) self.pcrFileCombo.Append( value ) # disable ADD button if NumbHashes now > MaxHashes, unless MaxHashes is 0 indicating no limit on the number of files if(self.pdef.MaxHashes != 0): if(fileCnt > self.pdef.MaxHashes): self.addButton.Enable( False ) # enable REMOVE and UPDATE buttons and PCR File combo box ifNumbHashes > 1 if(fileCnt > 0): self.updateButton.Enable( True ) self.removeButton.Enable( True ) self.pcrFileCombo.Enable( True ) self.enableDisablePcrSelectionCheckBoxes(True) self.showSelection(currentList.ElementDefData[self.myIndex].CurrentView) def onRemoveButtonClick(self, event): """onRemoveButtonClick - Remove the current PCR file from the list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected PCR file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return # remove the selected PCRInfoSrc entry from the comboBox, ie entry: currentList.ElementDefData[self.myIndex].CurrentView currentList = self.pdef.getCurrentListObject() self.setListModified() currentSelection = currentList.ElementDefData[self.myIndex].CurrentView self.pcrFileCombo.Delete(currentSelection) # show entry 0 newView = 0 self.pcrFileCombo.SetSelection(newView) currentList.ElementDefData[self.myIndex].CurrentView = newView # also remove the entry from ElementDefData[] del currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentSelection] # decr currentList.ElementDefData[self.myIndex].NumbHashes and update currentList.ElementDefData[self.myIndex].CurrentView # decr currentList.ElementDefData[self.myIndex].NumbHashes and update NumberOfFiles widget fileCnt = currentList.ElementDefData[self.myIndex].NumbHashes fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt # DBGDBG print("onRemoveButtonClick - removed %d, NumbHashes=%d currentSelection=%d" % (currentSelection, fileCnt, currentSelection)) #DBGDBG if(fileCnt > 0): # DBGDBG - verify ElementDefData vs. Add's prints i=0 # DBGDBG while(i < fileCnt): # DBGDBG pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[i] # DBGDBG print("Remove: Pconf_info%d=%s, pcrFile=%s pcrSelect[0]=%s" % (i, pconf_info, pconf_info.pcrFile, pconf_info.pcrSelect[0])) # DBGDBG i += 1 # DBGDBG # DBGDBG if(response == wx.ID_YES): if(fileCnt > 0): self.showSelection(newView) # update the PCR Selection checkboxes to match the new selection pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[newView] pcrSelection = pconf_info.pcrSelect[0] self.setPcrSelectionCheckboxes(pcrSelection) else: # no more files, disable Remove & Update self.updateButton.Enable( False ) self.removeButton.Enable( False ) self.pcrFileCombo.Enable( False ) self.enableDisablePcrSelectionCheckBoxes(False) self.fileSelectionEdit.ChangeValue("") self.clearPcrCheckBoxes() self.StatusBar.SetStatusText( "PCR file removed" ) # reenable ADD button if NumbHashes is now < MaxHashes if(self.pdef.MaxHashes != 0): if(fileCnt < self.pdef.MaxHashes): self.addButton.Enable( True ) def clearPcrCheckBoxes(self): """clearPcrCheckBoxes - clear the PCR check boxes""" for eachBox in self.pcrSelectionCheckboxes: eachBox.SetValue(False) # # Form an 8 entry list where each member represents the value of each bit in the specified byte # ordered from bit 7 to bit 0 # Example: if byte = 0x35 Output is [0,0,1,1,0,1,0,1] # def makeListWithEntryForEachBitInByte(self, byte): """makeListWithEntryForEachBitInByte - Form an 8 entry list where each member represents the value of each bit in the specified byte """ bit = 0x80 cnt = 0 pcrSelectBits = [0, 1, 2, 3, 4, 5, 6, 7] # initial values will be overwritten #print("Bits=%s pcrSelectBits[cnt]=%x cnt=%x bit=%x byte=%x" % (pcrSelectBits, pcrSelectBits[cnt], cnt, bit, byte)) #DBGDBG while(bit >= 0x01): # check each bit from bit 7 thru bit 0 if(byte & bit != 0): pcrSelectBits[cnt] = 1 else: pcrSelectBits[cnt] = 0 #print("Bits=%s, pcrSelectBits[cnt]=%x, cnt=%x bit=%x byte=%x" % (pcrSelectBits, pcrSelectBits[cnt], cnt, bit, byte)) #DBGDBG bit >>= 1 cnt += 1 return(pcrSelectBits) # show current selection and prompt user to select PCRs and click UPDATE for selected file def showSelection(self, currentSelection): """showSelection - show user which element is selected""" self.StatusBar.SetStatusText("PCR File %d is selected. To change PCR Selections, Set the PCR[0-7] check boxes, and click Apply PCR Selection" % (currentSelection+1) ) self.fileSelectionEdit.ChangeValue(str(currentSelection+1)) def enableDisablePcrSelectionCheckBoxes(self, value): """setPcrSelectionCheckBoxes - enable/disable the PCR Selection check boxes """ for eachBox in self.pcrSelectionCheckboxes: eachBox.Enable(value) def setPcrSelectionCheckboxes(self, pcrSelection): """setPcrSelectionCheckboxes - set the PCR selection checkboxes per the pcrSelection list""" i=0 for eachCheckbox in self.pcrSelectionCheckboxes: if(pcrSelection[i] == 1): eachCheckbox.SetValue(True) else: eachCheckbox.SetValue(False) i += 1 def writePconfDef(self, pconfDefData, f): """writePconfDef - write the PCONF_DEF to the specified file""" print("writePconfDef dump pconfDefData, hashAlg=%d" % (self.myHashAlg)) # DBGDBG pickle.dump(pconfDefData, f) # write out the pconfDefData object i = 0 for eachPconfInfo in pconfDefData.PcrInfoSrc: #print("writePconfDef: pconfInfo %x" % (i)) # for readability self.writePconfInfo(eachPconfInfo, i, f) i += 1 def writePconfInfo(self, pconfInfo, index, f): """writePconfInfo - write the PCONF_INFO to the specified file""" print("writePconfInfo dump pconfInfo") # DBGDBG pickle.dump(pconfInfo, f) # write out the pconfInfo object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to pconf panel widgets""" self.overridePsPolicy.SetValue(0) self.pcrFileCombo.SetValue("") self.addButton.Enable(True) self.removeButton.Enable(False) self.updateButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.fileSelectionEdit.ChangeValue("") self.enableDisablePcrSelectionCheckBoxes(False) self.clearPcrCheckBoxes() def restorePanel(self, currentList, maxHashes): """restorePanel - restore the PCONF element panel from the specified PLIST_DEF""" print("restorePanel - Rules=%d, PCONF Control=%d" % (self.pdef.Rules, currentList.ElementDefData[self.myIndex].Control)) # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # if >0 hashes # enable remove and update # select 1st file and set SelectedFile flag = False if(numbHashes > 0): flag = True self.pcrFileCombo.SetSelection(0) self.pcrFileCombo.Enable(True) self.fileSelectionEdit.ChangeValue("1") self.removeButton.Enable(flag) self.updateButton.Enable(flag) # set Number of Files self.fileCntEdit.ChangeValue(str(numbHashes)) # update PCR Selection checkboxes for selected file currentEntrySelected = currentList.ElementDefData[self.myIndex].CurrentView print("restorePanel - PCONF currentEntrySelected=%d numbHashes=%d" % (currentEntrySelected, numbHashes)) # DBGDBG if(numbHashes > 0): self.showSelection(currentEntrySelected) pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentEntrySelected] pcrSelection = pconf_info.pcrSelect[0] self.setPcrSelectionCheckboxes(pcrSelection) self.pcrFileCombo.SetSelection(currentEntrySelected) self.pcr0.Enable(True) self.pcr1.Enable(True) self.pcr2.Enable(True) self.pcr3.Enable(True) self.pcr4.Enable(True) self.pcr5.Enable(True) self.pcr6.Enable(True) self.pcr7.Enable(True) # Now form PCR File combo selection and choices list # ***Note that this code requires that the PCR Selection checkboxes have # been updated all ready******************************************** self.updatePcrFileCombo() #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # # #print("PCONF setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcp-gen2/pconfLegacy.py0000644000000000000000000007073014210363175015277 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import PCONFLEGACY_DEF from pdef import PCONF_INFO from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # # TXT Policy Generator Tool # PCONF Class - Policy Definition File Lists # class PCONFLegacy( ElementGui ): CONST_TITLE = "Choose PCR File" CONST_WILDCARD = "Pcr file (*.pcr)|*.pcr|" \ "All Files (*.*)|*.*" """__init__() - PCONF class constructor""" def __init__( self ): self.pconfPanelWidgets = [] self.panelCreated = False # # create the PCONF Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createPanel - create the List Panel""" print("createOrShowPanel panelCreated == %s" % (self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.pcrFileCombo.Clear() self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() # Get the list corresponds to this element. currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the PCONF Panel sizers #self.pconfPanelSizer = wx.BoxSizer(wx.VERTICAL) pconfGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #pconfHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.pconfPanel = wx.Panel(parent, -1) self.pconfPanel.SetSizer(pconfGridSizer) pconfLabelText1 = "PCONF" pconfLabelText2 = "Element" pconfLabel1 = wx.StaticText(self.pconfPanel, -1, pconfLabelText1) pconfLabel2 = wx.StaticText(self.pconfPanel, -1, pconfLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) pconfLabel1.SetFont( font ) pconfGridSizer.Add( pconfLabel1, pos=(0, 3)) self.pconfPanelWidgets.append(pconfLabel1) pconfLabel2.SetFont( font ) pconfGridSizer.Add( pconfLabel2, pos=(0, 4)) self.pconfPanelWidgets.append(pconfLabel2) self.typeLabel = wx.StaticText(self.pconfPanel, label="Type") pconfGridSizer.Add( self.typeLabel, pos=(1,3)) self.pconfPanelWidgets.append(self.typeLabel) self.typeEdit = wx.TextCtrl( self.pconfPanel, value="PCONF", size=(40, -1)) self.typeEdit.Enable( False ) pconfGridSizer.Add( self.typeEdit, pos=(1,4)) self.pconfPanelWidgets.append(self.typeEdit) self.contolOptionsLabel = wx.StaticText(self.pconfPanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.contolOptionsLabel.SetFont( font ) # override PS policy bit is applicable only if PO policy rules self.overridePsPolicy = wx.CheckBox(self.pconfPanel, label="Override PS Policy") if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) pconfGridSizer.Add(self.contolOptionsLabel, pos=(0,8), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy, self.overridePsPolicy) pconfGridSizer.Add(self.overridePsPolicy, pos=(1,8), span=(1,2), flag=wx.BOTTOM, border=5) self.pconfPanelWidgets.append(self.contolOptionsLabel) self.pconfPanelWidgets.append(self.overridePsPolicy) hashList = ['SHA1'] self.hashAlgLabel = wx.StaticText(self.pconfPanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.hashAlgLabel.SetFont( font ) pconfGridSizer.Add(self.hashAlgLabel, pos=(0,20)) self.pconfPanelWidgets.append(self.hashAlgLabel) # Style=wx.CB_READONLY same as wx.CB_DROPDOWN, # Except only the strings specified as the combobox choices can be selected hashAlgEdit = wx.ComboBox( self.pconfPanel, size=(75, -1), value="SHA1", choices=hashList, style=wx.CB_DROPDOWN ) pconfGridSizer.Add(hashAlgEdit, pos=(1,20)) self.pconfPanelWidgets.append(hashAlgEdit) pcrFile = "" self.pcrFileFileLabel = wx.StaticText(self.pconfPanel, label="PCR File") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.pcrFileFileLabel.SetFont( font ) pconfGridSizer.Add( self.pcrFileFileLabel, pos=(2,3)) self.pconfPanelWidgets.append(self.pcrFileFileLabel) self.pcrFileCombo = wx.ComboBox( self.pconfPanel, value=pcrFile, size=(200, -1), choices=pcrFile, style=wx.CB_DROPDOWN) self.pcrFileCombo.Enable( False ) # prevent selection since pulldown is empty self.pcrFileCombo.Bind(wx.EVT_TEXT, self.onPcrFileCombo, self.pcrFileCombo) pconfGridSizer.Add( self.pcrFileCombo, pos=(2,4)) self.pconfPanelWidgets.append(self.pcrFileCombo) self.fileSelectionLabel = wx.StaticText(self.pconfPanel, label="Selected File") pconfGridSizer.Add( self.fileSelectionLabel, pos=(7,3)) self.pconfPanelWidgets.append(self.fileSelectionLabel) self.fileSelectionEdit = wx.TextCtrl( self.pconfPanel, value=" ", size=(40, -1)) self.fileSelectionEdit.Enable( False ) pconfGridSizer.Add( self.fileSelectionEdit, pos=(7,4)) self.pconfPanelWidgets.append(self.fileSelectionEdit) self.fileCntLabel = wx.StaticText(self.pconfPanel, label="Number of Files") pconfGridSizer.Add( self.fileCntLabel, pos=(8,3)) self.pconfPanelWidgets.append(self.fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.pconfPanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) pconfGridSizer.Add( self.fileCntEdit, pos=(8,4)) self.pconfPanelWidgets.append(self.fileCntEdit) self.updateButton = wx.Button( self.pconfPanel, -1, label="Apply PCR Selection") self.updateButton.Enable( False ) pconfGridSizer.Add( self.updateButton, pos=(7,8)) self.pconfPanelWidgets.append(self.updateButton) self.updateButton.Bind(wx.EVT_BUTTON, self.onUpdateButtonClick) self.pconfPanelWidgets.append(self.updateButton) self.addButton = wx.Button( self.pconfPanel, -1, label=" Add ") pconfGridSizer.Add( self.addButton, pos=(3,4)) self.pconfPanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick) self.pconfPanelWidgets.append(self.addButton) self.removeButton = wx.Button( self.pconfPanel, -1, label=" Remove ") self.removeButton.Enable( False ) pconfGridSizer.Add( self.removeButton, pos=(4,4)) self.pconfPanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick) self.pconfPanelWidgets.append(self.removeButton) #self.pcrSelectionLabel = wx.StaticText(self.pconfPanel, -1, "PCR Selection") #font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) #self.pcrSelectionLabel.SetFont( font ) self.pcrSelectionLabel1 = wx.StaticText(self.pconfPanel, -1, "PCR ") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.pcrSelectionLabel1.SetFont( font ) self.pcrSelectionLabel2 = wx.StaticText(self.pconfPanel, -1, "Selection") self.pcrSelectionLabel2.SetFont( font ) self.pcr0 = wx.CheckBox(self.pconfPanel, label="0") self.pcr1 = wx.CheckBox(self.pconfPanel, label="1") self.pcr2 = wx.CheckBox(self.pconfPanel, label="2") self.pcr3 = wx.CheckBox(self.pconfPanel, label="3") self.pcr4 = wx.CheckBox(self.pconfPanel, label="4") self.pcr5 = wx.CheckBox(self.pconfPanel, label="5") self.pcr6 = wx.CheckBox(self.pconfPanel, label="6") self.pcr7 = wx.CheckBox(self.pconfPanel, label="7") self.pcrSelectionCheckboxes =[self.pcr7, self.pcr6, self.pcr5, self.pcr4, self.pcr3, self.pcr2, self.pcr1, self.pcr0] self.enableDisablePcrSelectionCheckBoxes(False) # disable the check boxes til the 1st file is added #pconfGridSizer.Add(self.pcrSelectionLabel, pos=(2,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcrSelectionLabel1, pos=(2,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcrSelectionLabel2, pos=(2,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr7, pos=(3,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr6, pos=(4,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr5, pos=(5,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr4, pos=(6,6), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr3, pos=(3,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr2, pos=(4,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr1, pos=(5,8), span=(1,2), flag=wx.BOTTOM, border=5) pconfGridSizer.Add(self.pcr0, pos=(6,8), span=(1,2), flag=wx.BOTTOM, border=5) #self.pconfPanelWidgets.append(self.pcrSelectionLabel) self.pconfPanelWidgets.append(self.pcrSelectionLabel1) self.pconfPanelWidgets.append(self.pcrSelectionLabel2) self.pconfPanelWidgets.append(self.pcr0) self.pconfPanelWidgets.append(self.pcr1) self.pconfPanelWidgets.append(self.pcr2) self.pconfPanelWidgets.append(self.pcr3) self.pconfPanelWidgets.append(self.pcr4) self.pconfPanelWidgets.append(self.pcr5) self.pconfPanelWidgets.append(self.pcr6) self.pconfPanelWidgets.append(self.pcr7) self.pconfPanelWidgets.append(self.pconfPanel) #pconfHorizSizer.Add(pconfGridSizer, 0, wx.ALL, 5) #self.pconfPanelSizer.Add(pconfHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.pconfPanelSizer) parentSizer.Add(self.pconfPanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(restorePanel, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the Pconf panel""" for i in self.pconfPanelWidgets: i.Hide() def showPanel(self): """showPanel - show the Pconf panel""" if self.panelCreated: for i in self.pconfPanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - PCONF""" self.pcrFileCombo.SetValue(' ') self.clearPcrCheckBoxes() currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = 0 currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].PcrInfoSrc = [] def onOverridePsPolicy(self, event): """onOverridePsPolicy - update the Control field""" # set/clear bit 0 per MLE Dev Guide PolEltControl def currentList = self.pdef.getCurrentListObject() self.setListModified() currentList.ElementDefData[self.myIndex].Control = event.Checked() #print("onOverridePsPolicy Control=%d Event=%d" % (currentList.ElementDefData[self.myIndex].Control , event.IsChecked())) def onPcrFileCombo(self, event): """onPcrFileCombo - update which PCR file is selected""" # Get the PcrInfo entry selected by the user and save it in CurrentView currentSelection = self.pcrFileCombo.GetSelection() currentList = self.pdef.getCurrentListObject() self.setListModified() currentList.ElementDefData[self.myIndex].CurrentView = currentSelection #print("onPcrFileCombo: currentSelection=%d, NumbHashes=%d" % (currentSelection, currentList.ElementDefData[self.myIndex].NumbHashes)) #DBGDBG # set the checkboxes to match the current selection and show which element is selected self.showSelection(currentSelection) pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentSelection] pcrSelection = pconf_info.pcrSelect[0] self.setPcrSelectionCheckboxes(pcrSelection) def onUpdateButtonClick(self, event): """onUpdateButtonClick - update the PCR select per the PCR0-7 checkboxes for the current file""" self.updatePcrFileCombo() def updatePcrFileCombo(self): # update the selected PcrInfoSrc[i].pcrSelect[0] with the PCR Selection info set by the user # where i = currentList.ElementDefData[self.myIndex].CurrentView = user's current selection # this indicates which PCRs in the file are evaluated bit = 0 byte = 0 for eachCheckbox in self.pcrSelectionCheckboxes: if(eachCheckbox.IsChecked() == True): x = 1 << (7-bit) #print("updatePcrFileCombo - bit %x is checked, x=%x" % (bit, x)) #DBGDBG else: x = 0 bit += 1 byte |= x #print("updatePcrFileCombo - byte=%x" % (byte)) #DBGDBG newPcrSelection = self.makeListWithEntryForEachBitInByte(byte) currentList = self.pdef.getCurrentListObject() self.setListModified() #currentEntrySelected = self.pcrFileCombo.GetSelection() currentEntrySelected = currentList.ElementDefData[self.myIndex].CurrentView #print("updatePcrFileCombo - currentEntrySelected=%x*****" % (currentEntrySelected)) #DBGDBG pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentEntrySelected] pconf_info.pcrSelect[0] = newPcrSelection #print("updatePcrFileCombo -currentEntrySelected=%d=%s newPcrSelection=%s" % (currentEntrySelected, pconf_info, newPcrSelection)) #DBGDBG filename = pconf_info.pcrFile value = str(newPcrSelection) + " " + filename # replace the selection # update the choices list #TODO: wxPython: updatePcrFileCombo - ComboBox.Replace doesn't work so doing .Clear() .Append's - better way? # XXXXXXX self.pcrFileCombo.Replace( currentEntrySelected, value ) XXXXXXXXXX # Since ComboBox.Replace doesn't work, # Use .Clear() to clear the choices then iterate thru and reconstruct the choices with .Append(eachChoice) self.pcrFileCombo.Clear() self.pcrFileCombo.SetValue( value ) fileCnt = currentList.ElementDefData[self.myIndex].NumbHashes i = 0 #print("updatePcrFileCombo: NumbHashes=%d**StartOfWhile**" % (fileCnt)) #DBGDBG while(i < fileCnt): pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[i] #print("Update: Pconf_info%d=%s NumbHashes=%d, pcrFile=%s pcrSelect[0]=%s --start of loop--" % # (i, pconf_info, fileCnt, pconf_info.pcrFile, pconf_info.pcrSelect[0])) # DBGDBG bit = 0 byte = 0 for eachPcr in pconf_info.pcrSelect[0]: # pcrSelect[0] ordered 7:0, pcrSelectionCheckboxes ordered 0:7 if(eachPcr == 1): x = 1 << (7-bit) #print("updatePcrFileCombo: i=%d: bit %x is set, x=%x byte=%x" % (i, 7-bit, x, byte)) #DBGDBG else: x = 0 bit += 1 byte |= x #print("updatePcrFileCombo - byte=%x" % (byte)) #DBGDBG newPcrSelection = self.makeListWithEntryForEachBitInByte(byte) filename = pconf_info.pcrFile value = str(newPcrSelection) + " " + filename self.pcrFileCombo.Append(value) #print("updatePcrFileCombo: i=%d value=%s --end of loop--" % (i, value )) # DBGDBG i += 1 def onAddButtonClick(self, event): """onAddButtonClick - add a PCR file to the list""" # Present dialogue for user to select a PCR file # Leave PCR Selection checkboxes as is so same setting can be used on next file filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified PCR file is properly formatted result = utilities.verifyPcrFile(os.path.join(filepath, filename), DEFINES.TPM_ALG_HASH['SHA1']) if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # incr currentList.ElementDefData[self.myIndex].NumbHashes and update NumberOfFiles widget currentList = self.pdef.getCurrentListObject() self.setListModified() fileCnt = currentList.ElementDefData[self.myIndex].NumbHashes fileCnt += 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt # add a PCONF_INFO to PCONF_DEF.PcrInfoSrc[] for this PCR file pconf_info = PCONF_INFO() # create a PCONF_INFO currentList.ElementDefData[self.myIndex].PcrInfoSrc.append(pconf_info) #print("pconf_info: NumbHahses=%x pcrSelect[0]=%x, pcrFile=%s" % (fileCnt, pconf_info.pcrSelect[0], pconf_info.pcrFile)) # DBGDBG pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[fileCnt-1] # add the PCONF_INFO to PCONF_DEF # Set currentList.ElementDefData[self.myIndex].PcrInfoSrc[i].pcrSelect[0] = 0 # Set currentList.ElementDefData[self.myIndex].PcrInfoSrc[i].pcrFile = the selected file # where i = currentList.ElementDefData[self.myIndex].CurrentView = user's current selection # Concatenate "PcrInfoSrc[i].pcrSelect" and "PcrInfoSrc[i].pcrFile" per fig 9 # display/append that concatenated value to the comboBox. ex: "00000000 PlatformA_BiosD28.pcr" pconf_info.pcrFile = filename pcrSelectBits = [0,0,0,0,0,0,0,0] # list of each bit in pcrSelect[0] = 00000000 pconf_info.pcrSelect[0] = pcrSelectBits currentList.ElementDefData[self.myIndex].CurrentView = fileCnt-1 print("Add: Pconf_info%d=%s NumbHashes=%d, pcrFile=%s pcrSelect[0]=%s" % (fileCnt-1, pconf_info, fileCnt, pconf_info.pcrFile, pconf_info.pcrSelect[0])) # DBGDBG value = str(pcrSelectBits) + " " + filename self.pcrFileCombo.SetValue( value ) self.pcrFileCombo.Append( value ) # disable ADD button if NumbHashes now > MaxHashes, unless MaxHashes is 0 indicating no limit on the number of files if(self.pdef.MaxHashes != 0): if(fileCnt > self.pdef.MaxHashes): self.addButton.Enable( False ) # enable REMOVE and UPDATE buttons and PCR File combo box ifNumbHashes > 1 if(fileCnt > 0): self.updateButton.Enable( True ) self.removeButton.Enable( True ) self.pcrFileCombo.Enable( True ) self.enableDisablePcrSelectionCheckBoxes(True) self.showSelection(currentList.ElementDefData[self.myIndex].CurrentView) def onRemoveButtonClick(self, event): """onRemoveButtonClick - Remove the current PCR file from the list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected PCR file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return # remove the selected PCRInfoSrc entry from the comboBox, ie entry: currentList.ElementDefData[self.myIndex].CurrentView currentList = self.pdef.getCurrentListObject() self.setListModified() currentSelection = currentList.ElementDefData[self.myIndex].CurrentView self.pcrFileCombo.Delete(currentSelection) # show entry 0 newView = 0 self.pcrFileCombo.SetSelection(newView) currentList.ElementDefData[self.myIndex].CurrentView = newView # also remove the entry from PconfDefData[] del currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentSelection] # decr currentList.ElementDefData[self.myIndex].NumbHashes and update currentList.ElementDefData[self.myIndex].CurrentView # decr currentList.ElementDefData[self.myIndex].NumbHashes and update NumberOfFiles widget fileCnt = currentList.ElementDefData[self.myIndex].NumbHashes fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt # DBGDBG print("onRemoveButtonClick - removed %d, NumbHashes=%d currentSelection=%d" % (currentSelection, fileCnt, currentSelection)) #DBGDBG if(fileCnt > 0): # DBGDBG - verify PconfDefData vs. Add's prints i=0 # DBGDBG while(i < fileCnt): # DBGDBG pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[i] # DBGDBG print("Remove: Pconf_info%d=%s, pcrFile=%s pcrSelect[0]=%s" % (i, pconf_info, pconf_info.pcrFile, pconf_info.pcrSelect[0])) # DBGDBG i += 1 # DBGDBG # DBGDBG if(response == wx.ID_YES): if(fileCnt > 0): self.showSelection(newView) # update the PCR Selection checkboxes to match the new selection pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[newView] pcrSelection = pconf_info.pcrSelect[0] self.setPcrSelectionCheckboxes(pcrSelection) else: # no more files, disable Remove & Update self.updateButton.Enable( False ) self.removeButton.Enable( False ) self.pcrFileCombo.Enable( False ) self.enableDisablePcrSelectionCheckBoxes(False) self.fileSelectionEdit.ChangeValue("") self.clearPcrCheckBoxes() self.StatusBar.SetStatusText( "PCR file removed" ) # reenable ADD button if NumbHashes is now < MaxHashes if(self.pdef.MaxHashes != 0): if(fileCnt < self.pdef.MaxHashes): self.addButton.Enable( True ) def clearPcrCheckBoxes(self): """clearPcrCheckBoxes - clear the PCR check boxes""" for eachBox in self.pcrSelectionCheckboxes: eachBox.SetValue(False) # # Form an 8 entry list where each member represents the value of each bit in the specified byte # ordered from bit 7 to bit 0 # Example: if byte = 0x35 Output is [0,0,1,1,0,1,0,1] # def makeListWithEntryForEachBitInByte(self, byte): """makeListWithEntryForEachBitInByte - Form an 8 entry list where each member represents the value of each bit in the specified byte """ bit = 0x80 cnt = 0 pcrSelectBits = [0, 1, 2, 3, 4, 5, 6, 7] # initial values will be overwritten #print("Bits=%s pcrSelectBits[cnt]=%x cnt=%x bit=%x byte=%x" % (pcrSelectBits, pcrSelectBits[cnt], cnt, bit, byte)) #DBGDBG while(bit >= 0x01): # check each bit from bit 7 thru bit 0 if(byte & bit != 0): pcrSelectBits[cnt] = 1 else: pcrSelectBits[cnt] = 0 #print("Bits=%s, pcrSelectBits[cnt]=%x, cnt=%x bit=%x byte=%x" % (pcrSelectBits, pcrSelectBits[cnt], cnt, bit, byte)) #DBGDBG bit >>= 1 cnt += 1 return(pcrSelectBits) # show current selection and prompt user to select PCRs and click UPDATE for selected file def showSelection(self, currentSelection): """showSelection - show user which element is selected""" self.StatusBar.SetStatusText("PCR File %d is selected. To change PCR Selections, Set the PCR[0-7] check boxes, and click Apply PCR Selection" % (currentSelection+1) ) self.fileSelectionEdit.ChangeValue(str(currentSelection+1)) def enableDisablePcrSelectionCheckBoxes(self, value): """setPcrSelectionCheckBoxes - enable/disable the PCR Selection check boxes """ for eachBox in self.pcrSelectionCheckboxes: eachBox.Enable(value) def setPcrSelectionCheckboxes(self, pcrSelection): """setPcrSelectionCheckboxes - set the PCR selection checkboxes per the pcrSelection list""" i=0 for eachCheckbox in self.pcrSelectionCheckboxes: if(pcrSelection[i] == 1): eachCheckbox.SetValue(True) else: eachCheckbox.SetValue(False) i += 1 def writePconfDef(self, pconfDefData, f): """writePconfDef - write the PCONF_DEF to the specified file""" #print("writePconfDef dump") # DBGDBG pickle.dump(pconfDefData, f) # write out the pconfDefData object i = 0 for eachPconfInfo in pconfDefData.PcrInfoSrc: #print("writePconfDef: pconfInfo %x" % (i)) # for readability self.writePconfInfo(eachPconfInfo, i, f) i += 1 def writePconfInfo(self, pconfInfo, index, f): """writePconfInfo - write the PCONF_INFO to the specified file""" #print("writePconfInfo dump") # DBGDBG pickle.dump(pconfInfo, f) # write out the pconfInfo object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to pconf panel widgets""" self.overridePsPolicy.SetValue(0) self.pcrFileCombo.SetValue("") self.addButton.Enable(True) self.removeButton.Enable(False) self.updateButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.fileSelectionEdit.ChangeValue("") self.enableDisablePcrSelectionCheckBoxes(False) self.clearPcrCheckBoxes() def restorePanel(self, currentList, maxHashes): """restorePanel - restore the PCONF element panel from the specified PLIST_DEF""" print("restorePanel - Rules=%d, PCONF Control=%d" % (self.pdef.Rules, currentList.ElementDefData[self.myIndex].Control)) # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # if >0 hashes # enable remove and update # select 1st file and set SelectedFile flag = False if(numbHashes > 0): flag = True self.pcrFileCombo.SetSelection(0) self.pcrFileCombo.Enable(True) self.fileSelectionEdit.ChangeValue("1") self.removeButton.Enable(flag) self.updateButton.Enable(flag) # set Number of Files self.fileCntEdit.ChangeValue(str(numbHashes)) # update PCR Selection checkboxes for selected file currentEntrySelected = currentList.ElementDefData[self.myIndex].CurrentView print("restorePanel - PCONF currentEntrySelected=%d numbHashes=%d" % (currentEntrySelected, numbHashes)) # DBGDBG if(numbHashes > 0): self.showSelection(currentEntrySelected) pconf_info = currentList.ElementDefData[self.myIndex].PcrInfoSrc[currentEntrySelected] pcrSelection = pconf_info.pcrSelect[0] self.setPcrSelectionCheckboxes(pcrSelection) self.pcrFileCombo.SetSelection(currentEntrySelected) self.pcr0.Enable(True) self.pcr1.Enable(True) self.pcr2.Enable(True) self.pcr3.Enable(True) self.pcr4.Enable(True) self.pcr5.Enable(True) self.pcr6.Enable(True) self.pcr7.Enable(True) # Now form PCR File combo selection and choices list # ***Note that this code requires that the PCR Selection checkboxes have # been updated all ready******************************************** self.updatePcrFileCombo() #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # # #print("PCONF setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True tboot-1.10.5/lcp-gen2/pdef.py0000644000000000000000000014422414210363175013763 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function import os import time from defines import DEFINES from LcpPolicy import * from util import UTILS utilities = UTILS() _GlobalHashData = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] PCONF_ELEMENT2_HDR_SIZE = 16 # size of LCP_PCONF_ELEMENT2's fields except PcrInfo's # i.e. sizeof(ElementSize+ElementType+ # PolEltControl+HashAlg+NumPCRInfos) PCR_INFO2_HDR_SIZE = 12 # size of TPMS_QUOTE_INFO's fileds except buffer # i.e. sizeof(count+hash+sizeOfSelect+pcrSelect+size) SHA1_PCR_INFO_SIZE = 26 # for PconfLegacyElement # TXT Policy Generator Tool # PDEF Class - Policy Definition File Structure # class PDEF( object ): """ PDEF Class""" def __init__( self ): """__init__() - PDEF class constructor""" self.WorkingDirectory = "" self.FileTypeSignature = "TXT Policy Definition v2" # CHAR8 array[24] self.DefCompany = "Intel" # CHAR8 array[16] self.StructVersion = 2 # incremented for any change to structure # # Structure capacity - can change without incrementing StructVersion # self.MaxLists = 8 # UINT8 MAX_LISTS = 8 - Max lists per policy #self.MaxElements = 4 # UINT8 MAX_ELEMENTS = 4 - Max elements per list per element self.MaxElements = 2 # only support SHA1 & SHA256 so far, not yet SHA384 & SHA512 self.MaxHashSize = 64 # UINT8 MAX_HASH_SIZE = 64 - Max allowed HASH size self.MaxHashes = 16 # UINT16 MAX_HASHES = 16 - Max hashes per element, 0=unlimited self.MaxFileNameSize = 32 # UINT8 MAX_FILENAME_SIZE 32 - Max size for a filename # ReservedCap[6] 0, # UINT8 - reserved for future definition # # Start of variable data whose content can be changed by the tool # self.ToolDate = time.strftime("%Y%m%d") # UINT32 YYYYMMDD - Build date of the tool #self.ToolVersion = 0x0200 # UINT16 Version of the tool self.ToolVersionMajor = 02 self.ToolVersionMinor = 00 self.Rules = 1 # UINT8 Type of rules: 0=PS, 1=PO self.Modified = 0 # BOOLEAN, True =changed since last 'BUILD' # ReservedTool # UINT16 # # Start of Policy Definition - same as NV Policy Structure # #self.PolVersion = 0x0301 # UINT16 self.PolVersionMajor = 03 self.PolVersionMinor = 01 self.HashAlg = DEFINES.TPM_ALG_HASH['SHA256'] # UINT16 TPM_ALG_XXXX self.PolicyType = 1 # UINT8 0=LIST, 1=ANY self.SinitMinVersion = 0 # UINT8 self.DataRevocationCounters = [0,0,0,0,0,0,0,0] # UINT16 DataRevocationCounters[MAX_LISTS] Default is 0's self.PolicyControl = 0 # UINT32 Encoding of (NPW, PCR17, Force PO) self.MaxSinitMinVersion = 255 # UINT8 reserved in PS Policy self.MaxBiosMinVersion = 255 # UINT8 reserved in PS Policy # HashAlg is already defined above # LcpHashAlgMask should be the content of CheckListBox self.LcpHashAlgMask = DEFINES.TPM_ALG_HASH_MASK['SHA256'] # UINT16 TPM_ALG_HASH_MASK_XXXXX # Should AuxHashAlgMask be renamed to ApAlg? self.AuxHashAlgMask = DEFINES.TPM_ALG_HASH_MASK['SHA256'] # UINT16 TPM_ALG_HASH_MASK_XXXXX self.LcpSignAlgMask = DEFINES.TPM_ALG_HASH_MASK['SHA256'] # UINT32 TPM_ALG_SIGN_MASK_XXXXX # save both the raw and hex formatted versions of the SHA1 and SHA256 hashes #self.PolicyHashSha1 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 0,0,0,0] # MAX_HASH = 20 for SHA1, #self.PolicyHashSha1Hex = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 0,0,0,0] #self.PolicyHashSha256 = [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] # MAX_HASH = 32 for SHA256 #self.PolicyHashSha256Hex = [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] # For Python, don't need multiple variable of different size to store hash values. # Going forward, there will be more hash algorithms. self.PolicyHash = [] self.PolicyHashHex = [] # # Start of Policy Data Structure Definition # #self.LastBuildDateStamp = 20000101 # UINT32 - YYYYMMDD - date of last build self.LastBuildDateStampYear = 2000 # UINT16 - YYYY - year of last build self.LastBuildDateStampMonth = 01 # UINT8 - MM - Month of last build self.LastBuildDateStampDay = 01 # UINT8 - DD - Day of last build #self.LastBuildTimeStamp = 00000000 # UINT32 - HHMMSS00 - time of last build self.LastBuildTimeStampHour = 00 # UINT8 - HH - hour of last build self.LastBuildTimeStampMinute = 00 # UINT8 - MM - minute of last build self.LastBuildTimeStampSecond = 00 # UINT8 - SS - second of last build self.LastBuildTimeStampLowByte = 00 # UINT8 - 00 - read only # Reserved3 # UINT16 self.CurrentListView = 0 # UINT8 - saves user state, indicates list to display self.NumLists = 0 # UINT8 - Actual number of lists # PLIST_DEF PolListInfo[0-7] # PLIST_DEF - dictionary containing policy is populated in addPlistDef self.PolListInfo = {'0':None, '1':None, '2':None, '3':None, '4':None, '5':None, '6':None, '7':None} # # add PolListInfo[0-7] to the PDEF # def addPlistDef(self, listNumber): """ addPlistDef - add a PLIST_DEF to the PDEF""" print("PLIST_DEF::addPlistDef - list %i" % (listNumber)) if(listNumber > self.MaxLists): # should never get here if caller checked MAX_LISTS correctly ... print("PLIST_DEF::addPlistDef - list %i > MAX=%i" % (listNumber, self.MaxLists)) else: self.PolListInfo[str(listNumber-1)] = PLIST_DEF() #self.PolListInfo[str(listNumber-1)].append(PLIST_DEF()) self.PolListInfo[str(listNumber-1)].ListValid = True #print("addPlistDef %d = %s" % (listNumber, self.PolListInfo[str(listNumber-1)])) # DBGDBG # at the time when adding the list to policy, sync policy version number to list version number policyversion = str(self.PolVersionMajor)+'.'+str(self.PolVersionMinor) listversion = DEFINES.SUPPORTED_LCP_VERSION[policyversion] majorstring, minorstring = listversion.split('.') self.PolListInfo[str(listNumber-1)].ListVersionMajor = int(majorstring) self.PolListInfo[str(listNumber-1)].ListVersionMinor = int(minorstring) def getCurrentListObject(self): """getCurrentListObject - return the current list object per CurrentListView""" listNumber = self.CurrentListView #print("getCurrentListObject - CurrentListView = %i" % (listNumber)) if(listNumber > self.MaxLists): # should never get here if CurrentListView was set correctly ... print("PLIST_DEF::getCurrentListObject - list %i > MAX_LISTS" % (listNumber)) elif(listNumber <= 0): return self.PolListInfo[str(0)] else: return self.PolListInfo[str(listNumber-1)] class PLIST_DEF( object ): """PLIST_DEF class""" def __init__(self): """___init__() = PLIST_DEF class constructor""" #print("constructing a PLIST_DEF") self.LdefSize = 128 # UINT32 - number of bytes in this LIST def self.Tag = "LIST" # UINT32 - confirms this is a LIST def struct #self.ListVersion = 0x0201 # UINT16 - version 2.1 self.ListVersionMajor = 02 self.ListVersionMinor = 01 self.ListValid = False # BOOLEAN - indicates if this list is to be included self.ListModified = False # BOOLEAN - indicates if this list has changed since last build; only clear when building policy. # Reserved[3] = 0 # UINT8 self.SigAlgorithm = DEFINES.TPM_ALG_SIGN['NULL'] # UINT8 - USER: 0=Not signed, 1 = PSA PKCS15 self.sigAlgorithmHash = DEFINES.TPM_ALG_HASH['SHA1'] # corresponds to 1 self.PolicyElementSize = 0 # UINT32 - total size of all elements in this list self.CurrentElementView = "None" # UINT8 - saves user state: 0=MLE, 1=PCONF, 3=SBIOS, 0xFF=None # Reserved2[3] = 0 # UINT8 # start of signature self.SyncRevCount = True # BOOLEAN - if true, updates Policy with RevocationCounter value # Reserved3[3] = 0 # UINT8 self.RevokeCounter = 0 # UINT16 - value to be populated in PDEF.RevocationCounter[n] self.RevocationCounter = 0 # UINT16 self.KeySize = 2048 # UINT16 - 1024, 2048 or 3072, default = 2048 self.PubKeyFile = "" # CHAR16[MAX_FILENAME_SIZE=32] - filename of signing key self.PvtKeyFile = "" self.PubKeyData = "" # PubKeyData[KeySize] for RSA - as a binary string # Not creating a separate class because the GUI will create and destroy when selecting between RSA and ECC signature algs self.PubKeyQx = "" # PubKeyData[KeySize] for ECC x coord - as binary string self.PubKeyQy = "" # PubKeyData[KeySize] for ECC y coord - as binary string self.PvtKeyFileIsSignature = False # False: PvtKeyFile is a key file; True: PvtKeyFile is signature file # using one collection(list) to store all element definition data # Python list guarantees the order. self.ElementDefData = [] # MLE Element definition - TYPE=0 class MLE_DEF( object ): """MLE_DEF class""" def __init__(self, hashAlg): """__init__() = MLE_DEF class constructor""" #print("constructing a MLE_DEF") try: hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() except StopIteration: hashAlgname = "" print("MLE_DEF::__init__ - invalid hashAlg=%d" % (hashAlg)) self.Name = "MLE-"+hashAlgName # String - Name used for GUI identification self.InfoSize = 24 # UINT32 - number of bytes in this structure self.Tag = "MLE_" # UINT32 - confirms this is a MLE_DEF self.IncludeInList = False # BOOLEAN - indicates this LIST includes an MLE element #Reserved3[5] = 0 # UINT8 self.SinitMinVersion = 0 # UINT8 - USER self.HashAlg = hashAlg # UINT16 - TPM_ALG_SHAXXXXX self.Control = 0 # UINT32 - USER: Bit0: Ignore PS MLE elements self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in MleHashFiles[] self.CurrentView = 0 # UINT16 - User state: last MleHashFiles[] selected self.HashFiles = [] # variable size array containing filenames of hashes # Build the MLE element and return its size # thisPdefList - is the list's source data from pdef.PolListInfo[list] # policyElement - is the destination LCP POLICY element # Return the elementSize built, or 0 if an error occurs # def build(self, thisPdefList, policyElements, cwd): """buildMleElement - build the MLE element""" func = 'buildMleElement' print("%s" %(func )) # DBGDBG elementSize = 18 # size all fields except Hashes[] in bytes # build the element's data #mleDefData = thisPdefList.MleDefData[index] policyElement = LCP_MLE_ELEMENT2() policyElement.PolEltControl = self.Control policyElement.SINITMinVersion = self.SinitMinVersion policyElement.HashAlg = self.HashAlg policyElement.NumHashes = self.NumbHashes print("%s - PolEltControl=%d, SINITMinVersion=%d from %d" % (func, policyElement.PolEltControl, policyElement.SINITMinVersion, self.SinitMinVersion)) # DBGDBG hashAlg = self.HashAlg try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print ("HashAlg=%d is not supported, aborting build" % (hashAlg)) return 0 # Build the hashes from each HashFiles[] for file in self.HashFiles: hashdata = utilities.getHashFromFile(os.path.join(cwd, file), self.HashAlg) if(len(hashdata) != DEFINES.DIGEST_SIZE[hashAlgName]): #self.StatusBar.SetStatusText("Invalid hash file %s, aborting build" % (file)) return 0 #policyElement.Hashes += _GlobalHashData # the hash data from the file policyElement.Hashes.append(hashdata) print("%s - policyElement.Hashes size=0x%x" % (func, len(policyElement.Hashes))) # DBGDBG # update elementSize elementSize += DEFINES.DIGEST_SIZE[hashAlgName] * self.NumbHashes # ElementSize = 16 +HashSize* (PDEF.PolListInfo[i].MleDefData[index].NumbHashes) # if HashAlg == SHA-1, HashSize=20 policyElement.ElementSize = elementSize print("%s - done, size=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printDef - write the Mle Def to the specified human readable text file for printing""" #print("printMleDef - object: %s" % (mleDefData)) # DBGDBG print("***MLE_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) #print("IncludeInList", " = ", self.IncludeInList, file=f) print("SinitMinVersion", " = ", self.SinitMinVersion, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) print("HashFiles", " = ", self.HashFiles, file=f) class MLELEGACY_DEF( object ): """MLELEGACY_DEF class""" def __init__(self): """__init__() = MLELEGACY_DEF class constructor""" #print("constructing a MLELEGACY_DEF") self.Name = DEFINES.ELEMENT_NAME_MLE_LEGACY # String - Name used for GUI identification self.InfoSize = 24 # UINT32 - number of bytes in this structure self.Tag = "MLE_" # UINT32 - confirms this is a MLE_DEF self.IncludeInList = False # BOOLEAN - indicates this LIST includes an MLE element #Reserved3[5] = 0 # UINT8 self.SinitMinVersion = 0 # UINT8 - USER self.HashAlg = 0 # UINT8 - SHA1 self.Control = 0 # UINT32 - USER: Bit0: Ignore PS MLE elements self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in MleHashFiles[] self.CurrentView = 0 # UINT16 - User state: last MleHashFiles[] selected self.HashFiles = [] # variable size array containing filenames of hashes # Build the MLE element and return its size # thisPdefList - is the list's source data from pdef.PolListInfo[list] # policyElement - is the destination LCP POLICY element # Return the elementSize built, or 0 if an error occurs # def build(self, thisPdefList, policyElements, cwd): """buildMleLegacyElement - build the MLE element""" func = "buildMleLegacyElement" print("%s" %(func)) # DBGDBG elementSize = 16 # size all fields except Hashes[] in bytes # build the element's data #mleDefData = thisPdefList.MleLegacyDefData[DEFINES.DEFDATA_INDEX['SHA1']] policyElement = LCP_MLE_ELEMENT() policyElement.PolEltControl = self.Control policyElement.SINITMinVersion = self.SinitMinVersion policyElement.HashAlg = self.HashAlg policyElement.NumHashes = self.NumbHashes print("%s - PolEltControl=%d, SINITMinVersion=%d from %d" % (func, policyElement.PolEltControl, policyElement.SINITMinVersion, self.SinitMinVersion)) # DBGDBG # Build the hashes from each HashFiles[] for file in self.HashFiles: hashdata = utilities.getHashFromFile(os.path.join(cwd, file), DEFINES.TPM_ALG_HASH['SHA1']) if(len(hashdata) != DEFINES.DIGEST_SIZE['SHA1']): print ("Invalid hash file %s, aborting build" % (file)) return 0 policyElement.Hashes.append(hashdata) # the hash data from the file print("%s - policyElement.Hashes size=0x%x" % (func, len(policyElement.Hashes))) # DBGDBG if(self.HashAlg == DEFINES.TPM_ALG_HASH['SHA1_LEGACY']): # update elementSize elementSize += DEFINES.DIGEST_SIZE['SHA1'] * self.NumbHashes else: print ("HashAlg=%d is not supported, aborting build" % (thisPdefList.HashAlg)) return 0 # ElementSize = 16 +HashSize* (PDEF.PolListInfo[i].MleDefData.NumbHashes) # if HashAlg == SHA-1, HashSize=20 policyElement.ElementSize = elementSize print("%s - done, size=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printMleDef - write the Mle Def to the specified human readable text file for printing""" #print("printMleDef - object: %s" % (mleDefData)) # DBGDBG print("***MLELEGACY_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) #print("IncludeInList", " = ", self.IncludeInList, file=f) print("SinitMinVersion", " = ", self.SinitMinVersion, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) print("HashFiles", " = ", self.HashFiles, file=f) # STM Element definition - TYPE=0 class STM_DEF( object ): """STM_DEF class""" def __init__(self, hashAlg): """__init__() = STM_DEF class constructor""" #print("constructing a STM_DEF") try: hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() except StopIteration: hashAlgname = "" print("STM_DEF::__init__ - invalid hashAlg=%d" % (hashAlg)) self.Name = "STM-"+hashAlgName # String - Name used for GUI identification self.InfoSize = 24 # UINT32 - number of bytes in this structure self.Tag = "STM_" # UINT32 - confirms this is a MLE_DEF self.IncludeInList = False # BOOLEAN - indicates this LIST includes an MLE element #Reserved3[5] = 0 # UINT8 self.HashAlg = hashAlg # UINT16 - TPM_ALG_SHAXXXXX self.Control = 0 # UINT32 - USER: Bit0: Ignore PS MLE elements self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in MleHashFiles[] self.CurrentView = 0 # UINT16 - User state: last MleHashFiles[] selected self.HashFiles = [] def build(self, thisPdefList, policyElements, cwd): """buildStmElement - build the STM element""" func='buildStmElement' print("%s" % (func)) # DBGDBG elementSize = 16 # size all fieds except Hashes[] in bytes # build the element's data #stmDefData = thisPdefList.StmDefData[index] policyElement = LCP_STM_ELEMENT2() policyElement.PolEltControl = self.Control policyElement.HashAlg = self.HashAlg policyElement.NumHashes = self.NumbHashes print("%s - PolEltControl=%d" % (func, policyElement.PolEltControl)) # DBGDBG hashAlg = self.HashAlg try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print ("HashAlg=%d is not supported, aborting build" % (hashAlg)) return 0 # Build the hashes from each HashFiles[] for file in self.HashFiles: hashdata = utilities.getHashFromFile(os.path.join(cwd, file), self.HashAlg) if(len(hashdata) != DEFINES.DIGEST_SIZE[hashAlgName]): #self.StatusBar.SetStatusText("Invalid hash file %s, aborting build" % (file)) return 0 #policyElement.Hashes += _GlobalHashData # the hash data from the file policyElement.Hashes.append(hashdata) print("%s - policyElement.Hashes size=0x%x" % (func, len(policyElement.Hashes))) # DBGDBG # update elementSize elementSize += DEFINES.DIGEST_SIZE[hashAlgName] * self.NumbHashes # ElementSize = 16 +HashSize* (PDEF.PolListInfo[i].StmDefData[index].NumbHashes) # if HashAlg == SHA-1, HashSize=20 policyElement.ElementSize = elementSize print("%s - done, size=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printDef - write the Stm Def to the specified human readable text file for printing""" #print("printStmDef - object: %s" % (stmDefData)) # DBGDBG print("***STM_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) #print("IncludeInList", " = ", self.IncludeInList, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) print("HashFiles", " = ", self.HashFiles, file=f) class PCONF_INFO( object ): """PCONF_INFO definition""" def __init__(self): """__init__() PCONF_INFO constructor""" self.pcrSelect = [1, 0, 0] # UINT8 - pcrSelect[0]=1 => pcr0-7 #reserved = 0 # UINT8 self.pcrFile = "myPcrFile.pcr" self.PCR0_BIT = 0x01 self.PCR1_BIT = 0x02 self.PCR2_BIT = 0x04 self.PCR3_BIT = 0x08 self.PCR4_BIT = 0x10 self.PCR5_BIT = 0x20 self.PCR6_BIT = 0x40 self.PCR7_BIT = 0x80 class PCONF_DEF( object ): """PCONF_DEF class""" def __init__(self, hashAlg): """__init__() PCONF_DEF constructor""" #print("constructing a PCONF_DEF") hashAlgName = "" try: hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() except StopIteration: print("PCONF_DEF::__init__ - invalid hashAlg=%d" % (hashAlg)) self.Name = "PCONF-"+hashAlgName # String - Name used for GUI identification self.InfoSize = 24 # UINT32 - number of bytes in this struct self.Tag = "PCON" # UINT32 - confirms that this is a PCONF policy defintion element self.IncludeInList = False # BOOLEAN - indicates this LIST includes a PCONF element # Reserved5[6] = 0 # UINT8 self.HashAlg = hashAlg # UINT16 - TPM_ALG_SHAXXXX ... self.Control = 0 # UINT32 - USER: Bit0: Ignore PS PCONF elements self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in PconfFiles[] self.CurrentView = 0 # UINT16 - User state: last PconfFiles[] selected #PCONF_INFO PcrInfoSrc[] # array of PCR selection and PCR dump file names self.PcrInfoSrc = [] # Build the PCONF element and return its size # thisPdefList - is the list's source data from pdef.PolListInfo[list] # policyElement - is the destination LCP POLICY element # listCnt - is the current list # def build(self, thisPdefList, policyElements, cwd): """buildPconfElement - build the PCONF element""" func = "buildPconfElement" print("%s" %(func)) # DBGDBG # build the element's data elementSize = PCONF_ELEMENT2_HDR_SIZE # size of all fields except PcrInfo's #pconfDefData = thisPdefList.PconfDefData[index] policyElement = LCP_PCONF_ELEMENT2() policyElement.PolEltControl = self.Control policyElement.HashAlg = self.HashAlg policyElement.NumPCRInfos = self.NumbHashes # really number TPMS_QUOTE_INFO's # Build each policyElement.PCRInfos' TPMS_QUOTE_INFO # for each pcr i = 0 # number of PcrInfoSrc's in LCP_PCONF_ELEMENT for pdefPcrInfo in self.PcrInfoSrc: thisTpmsQuoteInfo = TPMS_QUOTE_INFO() policyElement.PCRInfos.append(thisTpmsQuoteInfo) thisTpmsQuoteInfo = policyElement.PCRInfos[i] thisTpmlPcrSelection = thisTpmsQuoteInfo.pcrSelect # TPML_PCR_SELECTION() thisTpm2bDigest = thisTpmsQuoteInfo.pcrDigest # TPM2B_DIGEST() # Set pcrSelections (which is type: TPMS_PCR_SELECTION) in a TPML_PCR_SELECTION to indicate the selected PCRs. # Hash is the same algorithm ID as HashAlg in LCP_PCONF_ELEMENT2 since TPML_PCR_SELECTION's count=1 # Size of Select is always 3 # (because the TPM has 24 PCRs and thus requires 24-bits to indicate which PCR) # However the 2nd and 3rd bytes of pcrSelect[] are always 0x00 because the policy # only selects between the first 8 PCRs. # pcrSelect[0] is a bit mask formed from thisPdefList.PconfDefData[index].PcrInfoSrc[i].pcrSelect[0] # which is an 8 element list corresponding to each selected pcr from 0-7 # thisTpmlPcrSelection.count = 1 # So 1 TPMS_PCR_SELECTION and HashAlg per PCONF, see Spec A.2.2.4 p31 thisTpmsPcrSelection = thisTpmlPcrSelection.pcrSelections thisTpmsPcrSelection.hash = policyElement.HashAlg thisTpmsPcrSelection.sizeOfSelect = 0x0003 pcr0to7SelectionBitMask = 0 numSelectedPcrs = 0 thisBit = 0x80 pcr0to7SelectionList = pdefPcrInfo.pcrSelect[0] for eachBit in pcr0to7SelectionList: if(eachBit == 1): pcr0to7SelectionBitMask |= thisBit numSelectedPcrs += 1 thisBit >>= 1 thisTpmsPcrSelection.pcrSelect[0] = pcr0to7SelectionBitMask thisTpmsPcrSelection.pcrSelect[1] = 0 thisTpmsPcrSelection.pcrSelect[2] = 0 print("%s - PCRInfos[%d], pcrSelect[0]=0x%x, numSelectedPcrs=%d" % (func, i, thisTpmsPcrSelection.pcrSelect[0], numSelectedPcrs)) # DBGDBG i += 1 # determine if pcrFile is a PCRD or PCR2 formatted file file = pdefPcrInfo.pcrFile file = os.path.join(cwd, file) result = utilities.verifyPcrFile(file, policyElement.HashAlg) fileType = result[1] if(result[0] == False): print("%s - verifyPcrFile says PCR file %s is invalid!!!" % (func, file)) # Should NEVER get here return 0 # calculate thisTpm2bDigest.size and build TPM2B_DIGEST.buffer from the PCR data # in this pdef list's selected pcrFiles hashAlg = self.HashAlg try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print ("HashAlg=%d is not supported, aborting build" % (hashAlg)) return 0 hashSize = DEFINES.DIGEST_SIZE[hashAlgName] # verify that the pcfFile contains numHashes PCR values. These checks weren't done by verifyPcrFile() result = utilities.verifyPcrInfoNumHashes(file, fileType, hashAlg, pcr0to7SelectionBitMask) if(result == False): print("%s - verifyPcrInfoNumHashes says PCR file %s is invalid!!!" % (func, file)) return 0 elementSize += PCR_INFO2_HDR_SIZE # includes thisTpm2bDigest.size but not buffer if(pcr0to7SelectionBitMask == 0): # no pcr's selected thisTpm2bDigest.size = 0 # buffer is empty else: #thisTpm2bDigest.size = numSelectedPcrs * hashSize # sizeof(buffer) thisTpm2bDigest.size = hashSize # There's only one composite hash # for each selected PCR from 0 to 7 if(pcr0to7SelectionBitMask != 0): # Build tpmPcrSelection.digestAtRelease from the PCR data in this pdef list's selected pcrFiles hashdata = utilities.hashPcrInfoFromFile(os.path.join(cwd, file), pcr0to7SelectionBitMask, numSelectedPcrs) if(len(hashdata) != hashSize): print("%s - Invalid PCR file %s, aborting build" % (func, file)) return 0 tempbuf = array('B') tempbuf.fromstring(hashdata) #thisTpm2bDigest.buffer += _GlobalPcrHash thisTpm2bDigest.buffer += tempbuf elementSize += thisTpm2bDigest.size else: print ("%s - Nothing to hash: pcr0to7SelectionBitMask=0" %(func)) # DBGDBG print ("Note: No PCR was selected. If desired, select PCR's and click Update") #print("buildPconfElement - next pcrInfo i=%d" % (i)) # DBGDBG # end of pcrInfo for loop # update this element's size policyElement.ElementSize = elementSize print("%s - done, elementSize=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printDef - write the PCONF_DEF to the specified file""" #print("printPconfDef - object: %s" % (pconfDefData)) # DBGDBG print("***PCONF_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) #print("IncludeInList", " = ", self.IncludeInList, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) i = 0 for eachPconfInfo in self.PcrInfoSrc: print("\n", file=f) # for readability self.printPconfInfo(eachPconfInfo, i, f) i += 1 def printPconfInfo(self, pconfInfo, index, f): """printPconfInfo - write the PCONF_INFO to the specified human readable text file for printing""" #print("printPconfInfo %d object: %s" % (index, pconfInfo)) # DBGDBG print("***PCONF_INFO", index, "***", file=f) print("InfoSize", " = ", pconfInfo.pcrSelect, file=f) print("Tag", " = ", pconfInfo.pcrFile, file=f) class PCONFLEGACY_DEF( object ): """PCONFLEGACY_DEF class""" def __init__(self): """__init__() PCONFLEGACY_DEF constructor""" #print("constructing a PCONFLEGACY_DEF") self.Name = DEFINES.ELEMENT_NAME_PCONF_LEGACY # String - Name used for GUI identification self.InfoSize = 24 # UINT32 - number of bytes in this struct self.Tag = "PCON" # UINT32 - confirms that this is a PCONF policy defintion element self.IncludeInList = False # BOOLEAN - indicates this LIST includes a PCONF element # Reserved5[6] = 0 # UINT8 self.HashAlg = 0 # UINT8 - 0 = SHA1, others reserved for future use ... self.Control = 0 # UINT32 - USER: Bit0: Ignore PS PCONF elements self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in PconfFiles[] self.CurrentView = 0 # UINT16 - User state: last PconfFiles[] selected #PCONF_INFO PcrInfoSrc[] # array of PCR selection and PCR dump file names self.PcrInfoSrc = [] # Build the PCONF element and return its size # thisPdefList - is the list's source data from pdef.PolListInfo[list] # policyElement - is the destination LCP POLICY element # def build(self, thisPdefList, policyElements, cwd): """buildPconfLegacyElement - build the PCONF Legacy element""" func = "buildPconfLegacyElement" print("%s" %(func)) # DBGDBG elementSize = 14 # size of all fields except PcrInfo's # build the element's data #pconfDefData = thisPdefList.PconfLegacyDefData policyElement = LCP_PCONF_ELEMENT() policyElement.PolEltControl = self.Control policyElement.NumPCRInfos = self.NumbHashes # Build each policyElement.PCRInfos[NumPCRInfos] # for each hash to NumbHashes-1 i.e. to NumPCRInfos-1 # i = 0 # number of PcrInfoSrc's in LCP_PCONF_ELEMENT for pdefPcrInfo in self.PcrInfoSrc: thisTpmPcrInfoShort = TPM_PCR_INFO_SHORT() policyElement.PCRInfos.append(thisTpmPcrInfoShort) thisTpmPcrInfoShort = policyElement.PCRInfos[i] thisTpmPcrInfoShort.localityAtRelease = 0x1f # any locality # Set pcrSelection (which is type: TPM_PCR_SELECTION) to indicate the selected PCRs. # Size of Select is always 3 # (because the TPM has 24 PCRs and thus requires 24-bits to indicate which PCR) # However the 2nd and 3rd bytes of pcrSelect[] are always 0x00 because the policy # only selects between the first 8 PCRs. # pcrSelect[0] is a bit mask formed from thisPdefList.PconfLegacyDefData[index].PcrInfoSrc[i].pcrSelect[0] # which is an 8 element list corresponding to each selected pcr from 0-7 # thisTpmPcrSelection = thisTpmPcrInfoShort.pcrSelection thisTpmPcrSelection.sizeOfSelect = 0x0003 pcr0to7SelectionBitMask = 0 numSelectedPcrs = 0 thisBit = 0x80 pcr0to7SelectionList = pdefPcrInfo.pcrSelect[0] for eachBit in pcr0to7SelectionList: if(eachBit == 1): pcr0to7SelectionBitMask |= thisBit numSelectedPcrs += 1 thisBit >>= 1 thisTpmPcrSelection.pcrSelect[0] = pcr0to7SelectionBitMask thisTpmPcrSelection.pcrSelect[1] = 0 thisTpmPcrSelection.pcrSelect[2] = 0 print("%s - PCRInfos[%d], pcrSelect[0]=0x%x" % (func, i, thisTpmPcrSelection.pcrSelect[0])) # DBGDBG i += 1 # Build tpmPcrSelection.digestAtRelease from the PCR data in this pdef list's selected pcrFiles file = pdefPcrInfo.pcrFile hashdata = utilities.hashPcrInfoFromFile(os.path.join(cwd, file), pcr0to7SelectionBitMask, numSelectedPcrs) if(len(hashdata) != DEFINES.DIGEST_SIZE['SHA1']): print("%s - Invalid PCR file %s, aborting build" % (func, file)) return 0 thisTpmPcrInfoShort.digestAtRelease = hashdata # hash of the selected PCR data from the file #print("buildPconfElement - digestAtRelease=%s, _GlobalPcrHash=%s" % ( thisTpmPcrInfoShort.digestAtRelease, _GlobalPcrHash)) if(self.HashAlg == DEFINES.TPM_ALG_HASH['SHA1_LEGACY']): # ElementSize = 14 +PcrInfoSize* (PDEF.PolListInfo[i].PconfDefData[index].NumbHashes) # if HashAlg == SHA-1, PcrInfoSize=26 elementSize += SHA1_PCR_INFO_SIZE * self.NumbHashes else: print ("HashAlg=%d is not supported, aborting build" % (thisPdefList.HashAlg)) return 0 # update this element's size policyElement.ElementSize = elementSize print("%s - done, size=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printPconfDef - write the PCONF_DEF to the specified file""" #print("printPconfDef - object: %s" % (pconfDefData)) # DBGDBG print("***PCONFLegacy_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) print("IncludeInList", " = ", self.IncludeInList, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) i = 0 for eachPconfInfo in self.PcrInfoSrc: print("\n", file=f) # for readability self.printPconfInfo(eachPconfInfo, i, f) i += 1 def printPconfInfo(self, pconfInfo, index, f): """printPconfInfo - write the PCONF_INFO to the specified human readable text file for printing""" #print("printPconfInfo %d object: %s" % (index, pconfInfo)) # DBGDBG print("***PCONF_INFO", index, "***", file=f) print("InfoSize", " = ", pconfInfo.pcrSelect, file=f) print("Tag", " = ", pconfInfo.pcrFile, file=f) class SBIOS_DEF( object ): """SBIOS_DEF class""" def __init__(self, hashAlg): """__init__() SBIOS_DEF constructor""" #print("constructing a SBIOS_DEF") hashAlgName = "" try: hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() except StopIteration: print("SBIOS_DEF::__init__ - invalid hashAlg=%d" % (hashAlg)) self.Name = "SBIOS-"+hashAlgName # String - Name used for GUI identification self.InfoSize = 56 # UINT32 - number of bytes in this struct self.Tag = "SBIO" # UINT32 - confirms that this is a SBIOS policy defintion element self.IncludeInList = False # BOOLEAN - indicates this LIST includes a SBIOS element # Reserved5[6] = 0 # UINT8 self.HashAlg = hashAlg # UINT16 - TPM_ALG_SHAXXXXX self.FallBackHashFile = "" # FILEName - user - filename containing the fallback hash self.Control = 0 # UINT32 - USER: There are no defined controls at this time self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in SbiosFiles[] self.CurrentView = 0 # UINT16 - User state: last PconfFiles[] selected self.SbiosFiles = [] # variable size array containing filenames of hashes # Build the SBIOS element and return its size # thisPdefList - is the list's source data from pdef.PolListInfo[list] # policyElement - is the destination LCP POLICY element # Return the elementSize built, or 0 if an error occurs # def build(self, thisPdefList, policyElements, cwd): """buildSbiosElement - build the SBIOS element""" func = "buildSbiosElement" print("%s"%(func)) # DBGDBG elementSize = 20 # build the element's data #sbiosDefData = thisPdefList.SbiosDefData[index] policyElement = LCP_SBIOS_ELEMENT2() policyElement.PolEltControl = self.Control policyElement.HashAlg = self.HashAlg invalidMsg = "Invalid fallbackhash file, aborting build" noneMsg = "No fallbackhash file was specified, aborting build" hashAlg = self.HashAlg try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print ("HashAlg=%d is not supported, aborting build" % (hashAlg)) return 0 # open the FallbackHash file and get the hash data file = self.FallBackHashFile if(file != ""): hashdata = utilities.getHashFromFile(os.path.join(cwd, file), self.HashAlg) if(len(hashdata) != DEFINES.DIGEST_SIZE[hashAlgName]): print("%s" % (invalidMsg)) # also show in output window return 0 else: print("%s" % (noneMsg)) # also show in output window return 0 # if there was no fallback hash file specified, then hash 0's [the init value of _GlobalHashData # otherwise use the value from that file #policyElement.FallbackHash = _GlobalHashData # the hash data from the file policyElement.FallbackHash = hashdata policyElement.NumHashes = self.NumbHashes # print("buildSbiosElement: type=%d, Alg=%d, Fallback=%s, GlobalHash=%s, NumbHashes=%d" % # (policyElement.ElementType, policyElement.HashAlg , # policyElement.FallbackHash, _GlobalHashData, policyElement.NumHashes)) # DBGDBG # Build the hashes from each SbiosFiles[] for file in self.SbiosFiles: hashdata = utilities.getHashFromFile(os.path.join(cwd, file), self.HashAlg) if(len(hashdata) != DEFINES.DIGEST_SIZE[hashAlgName]): #self.StatusBar.SetStatusText("Invalid hash file %s, aborting build" % (file)) return 0 #policyElement.Hashes += _GlobalHashData # the hash data from the file policyElement.Hashes.append(hashdata) print("%s - policyElement.Hashes size=0x%x" % (func,len(policyElement.Hashes))) # DBGDBG # update elementSize elementSize += DEFINES.DIGEST_SIZE[hashAlgName] * (self.NumbHashes+1) # +1 for fallback hash # ElementSize = 20 +HashSize* (1+PDEF.PolListInfo[i].SbiosDefData[index].NumbHashes) # if HashAlg == SHA-1, HashSize=20 policyElement.ElementSize = elementSize print("%s - done, size=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printDef - write the Sbios Def to the specified human readable text file for printing""" #print("printSbiosDef - object: %s" % (sbiosDefData)) # DBGDBG print("***SBIOS_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) #print("IncludeInList", " = ", self.IncludeInList, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("FallBackHashFile", " = ", self.FallBackHashFile, file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) print("SbiosFiles", " = ", self.SbiosFiles, file=f) class SBIOSLEGACY_DEF( object ): """SBIOS_DEF class""" def __init__(self): """__init__() SBIOSLEGACY_DEF constructor""" #print("constructing a SBIOSLEGACY_DEF") self.Name = DEFINES.ELEMENT_NAME_SBIOS_LEGACY # String - Name used for GUI identification self.InfoSize = 56 # UINT32 - number of bytes in this struct self.Tag = "SBIO" # UINT32 - confirms that this is a SBIOS policy defintion element self.IncludeInList = False # BOOLEAN - indicates this LIST includes a SBIOS element # Reserved5[6] = 0 # UINT8 self.HashAlg = 0 # UINT8 - 0 = SHA1, others reserved for future use ... self.FallBackHashFile = "" # FILEName - user - filename containing the fallback hash self.Control = 0 # UINT32 - USER: There are no defined controls at this time self.NumbHashes = 0 # UINT16 - Tracks number of valid entries in SbiosFiles[] self.CurrentView = 0 # UINT16 - User state: last PconfFiles[] selected self.SbiosFiles = [] # variable size array containing filenames of hashes # Build the SBIOS element and return its size # thisPdefList - is the list's source data from pdef.PolListInfo[list] # policyElement - is the destination LCP POLICY element # Return the elementSize built, or 0 if an error occurs # def build(self, thisPdefList, policyElements, cwd): """buildSbiosElement - build the SBIOS element""" func = "buildSbiosLegacyElement" print("%s" %(func)) elementSize = 20 # build the element's data #sbiosDefData = thisPdefList.SbiosLegacyDefData[DEFINES.DEFDATA_INDEX_SHA1] policyElement = LCP_SBIOS_ELEMENT() policyElement.PolEltControl = self.Control policyElement.HashAlg = self.HashAlg invalidMsg = "Invalid fallbackhash file, aborting build" noneMsg = "No fallbackhash file was specified, aborting build" # open the FallbackHash file and get the hash data file = self.FallBackHashFile if(file != ""): hashdata = utilities.getHashFromFile(os.path.join(cwd, file), DEFINES.TPM_ALG_HASH['SHA1']) if(len(hashdata) != DEFINES.DIGEST_SIZE['SHA1']): print("%s" % (invalidMsg)) # also show in output window return 0 else: print("%s" % (noneMsg)) # also show in output window return 0 # if there was no fallback hash file specified, then hash 0's [the init value of _GlobalHashData # otherwise use the value from that file policyElement.FallbackHash = hashdata # the hash data from the file #policyElement.Hashes.append(hashdata) # print("buildSbiosElement: type=%d, Alg=%d, Fallback=%s, GlobalHash=%s, NumbHashes=%d" % # (policyElement.ElementType, policyElement.HashAlg , # policyElement.FallbackHash, _GlobalHashData, policyElement.NumHashes)) # DBGDBG policyElement.NumHashes = self.NumbHashes # Build the hashes from each SbiosFiles[] for file in self.SbiosFiles: hashdata = utilities.getHashFromFile(os.path.join(cwd, file), DEFINES.TPM_ALG_HASH['SHA1']) if(len(hashdata) != DEFINES.DIGEST_SIZE['SHA1']): print ("Invalid hash file %s, aborting build" % (file)) return 0 policyElement.Hashes.append(hashdata) # the hash data from the file print("%s - policyElement.Hashes size=0x%x" % (func, len(policyElement.Hashes))) # DBGDBG if(self.HashAlg == DEFINES.TPM_ALG_HASH['SHA1_LEGACY']): # update elementSize elementSize += DEFINES.DIGEST_SIZE['SHA1'] * (self.NumbHashes+1) # +1 for fallback hash else: print("%s - HashAlg=%d is not supported, aborting build" % (func, thisPdefList.HashAlg)) return 0 # ElementSize = 20 +HashSize* (1+PDEF.PolListInfo[i].SbiosDefData.NumbHashes) # if HashAlg == SHA-1, HashSize=20 policyElement.ElementSize = elementSize print("%s - done, size=0x%x" % (func, elementSize)) policyElements.append(policyElement) return(elementSize) def printDef(self, f): """printSbiosDef - write the Sbios Def to the specified human readable text file for printing""" #print("printSbiosDef - object: %s" % (sbiosDefData)) # DBGDBG print("***SBIOSLEGACY_DEF***", file=f) print("InfoSize", " = ", self.InfoSize, file=f) print("Tag", " = ", self.Tag, file=f) #print("IncludeInList", " = ", self.IncludeInList, file=f) print("HashAlg", " = ", hex(self.HashAlg), file=f) print("FallBackHashFile", " = ", self.FallBackHashFile, file=f) print("Control", " = ", self.Control, file=f) print("NumbHashes", " = ", self.NumbHashes, file=f) print("CurrentView", " = ", self.CurrentView, file=f) print("SbiosFiles", " = ", self.SbiosFiles, file=f) tboot-1.10.5/lcp-gen2/sbios.py0000644000000000000000000005471314210363175014167 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import SBIOS_DEF from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # TXT Policy Generator Tool # SBIOS Class - Policy Definition File Lists # class SBIOS( ElementGui ): CONST_TITLE = "Choose Hash File" CONST_WILDCARD = "Hash file (*.hash)|*.hash|" \ "All Files (*.*)|*.*" """__init__() - SBIOS class constructor""" def __init__( self, hashAlg ): self.sbiosPanelWidgets = [] self.panelCreated = False try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print("SBIOS::__init__ - invalid hashAlg=%d" % (hashAlg)) return self.myIndex = DEFINES.DEFDATA_INDEX[hashAlgName] #if( hashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA256 #elif( hashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA1 #else: # print("SBIOS::__init__ - invalid hashAlg=%d" % (hashAlg)) self.myHashAlg = hashAlg # # create the SBIOS Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createOrShowPanel - create the SBIOS Panel""" #print("createOrShowSbiosPanel hashAlg=%d, panelCreated == %s" % (self.myHashAlg, self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() # Get the list corresponds to this element. currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the Sbios Panel sizers #self.sbiosPanelSizer = wx.BoxSizer(wx.VERTICAL) sbiosGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #sbiosHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.sbiosPanel = wx.Panel(parent, -1) self.sbiosPanel.SetSizer(sbiosGridSizer) sbiosLabelText1 = "SBIOS" sbiosLabelText2 = "Element" sbiosLabel1 = wx.StaticText(self.sbiosPanel, -1, sbiosLabelText1) sbiosLabel2 = wx.StaticText(self.sbiosPanel, -1, sbiosLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) sbiosLabel1.SetFont( font ) sbiosGridSizer.Add( sbiosLabel1, pos=(0, 3)) self.sbiosPanelWidgets.append(sbiosLabel1) sbiosLabel2.SetFont( font ) sbiosGridSizer.Add( sbiosLabel2, pos=(0, 4)) self.sbiosPanelWidgets.append(sbiosLabel2) self.typeLabel = wx.StaticText(self.sbiosPanel, label="Type") sbiosGridSizer.Add( self.typeLabel, pos=(1,3)) self.sbiosPanelWidgets.append(self.typeLabel) self.typeEdit = wx.TextCtrl( self.sbiosPanel, value="SBIOS", size=(40, -1)) self.typeEdit.Enable( False ) sbiosGridSizer.Add( self.typeEdit, pos=(1,4)) self.sbiosPanelWidgets.append(self.typeEdit) self.contolOptionsLabel = wx.StaticText(self.sbiosPanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.contolOptionsLabel.SetFont( font ) self.overridePsPolicy = wx.CheckBox(self.sbiosPanel, label="Override PS Policy") self.overridePsPolicy.Enable( False ) #Note: overridePsPolicy - control always disabled since there are no SBIOS specific controls - p12 sbiosGridSizer.Add(self.contolOptionsLabel, pos=(0,14), span=(1,2), flag=wx.BOTTOM, border=5) sbiosGridSizer.Add(self.overridePsPolicy, pos=(1,14), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) self.sbiosPanelWidgets.append(self.contolOptionsLabel) self.sbiosPanelWidgets.append(self.overridePsPolicy) hashAlgStr = self.getHashAlgName() if(hashAlgStr == None): print("createOrShowSbiosPanel - invalid myHashAlg=%d" % (self.myHashAlg)) self.hashAlgLabel = wx.StaticText(self.sbiosPanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.hashAlgLabel.SetFont( font ) sbiosGridSizer.Add(self.hashAlgLabel, pos=(0,20)) self.sbiosPanelWidgets.append(self.hashAlgLabel) self.hashAlgEdit = wx.TextCtrl( self.sbiosPanel, size=(75, -1), value=hashAlgStr ) self.hashAlgEdit.Enable(False) sbiosGridSizer.Add(self.hashAlgEdit, pos=(1,20)) self.sbiosPanelWidgets.append(self.hashAlgEdit) self.fallbackFileLabel = wx.StaticText(self.sbiosPanel, label="Fallback\nHash") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.fallbackFileLabel.SetFont( font ) sbiosGridSizer.Add( self.fallbackFileLabel, pos=(2,3)) self.sbiosPanelWidgets.append(self.fallbackFileLabel) self.fallbackFileEdit = wx.TextCtrl( self.sbiosPanel, value="", size=(150, -1)) self.fallbackFileEdit.Enable(False) # must use BROWSE to locate the fallback file fallbackFile = currentList.ElementDefData[self.myIndex].FallBackHashFile if (fallbackFile == "" or fallbackFile == None): fallbackFile = "FallbackDflt" + hashAlgStr + ".hash" #if(hashAlgStr == "SHA256"): # fallbackFile = "FallbackDfltSha256.hash" #elif(hashAlgStr == "SHA1"): # fallbackFile = "FallbackDfltSha1.hash" #else: # print("Warning - unexpected hashAlgStr found when setting fallbackFile") self.fallbackFileEdit.AppendText(fallbackFile) sbiosGridSizer.Add( self.fallbackFileEdit, pos=(2,4)) self.sbiosPanelWidgets.append(self.fallbackFileEdit) currentList.ElementDefData[self.myIndex].FallBackHashFile = fallbackFile self.browseButton = wx.Button( self.sbiosPanel, -1, label="Browse") sbiosGridSizer.Add( self.browseButton, pos=(2,5)) self.sbiosPanelWidgets.append(self.browseButton) self.browseButton.Bind(wx.EVT_BUTTON, self.onBrowseButtonClick) self.fallbackRemoveButton = wx.Button( self.sbiosPanel, -1, label="Remove") sbiosGridSizer.Add( self.fallbackRemoveButton, pos=(1,5)) self.sbiosPanelWidgets.append(self.fallbackRemoveButton) self.fallbackRemoveButton.Bind(wx.EVT_BUTTON, self.onFallbackRemoveButtonClick) self.fallbackRemoveButton.Enable(True) self.addButton = wx.Button( self.sbiosPanel, -1, label=" Add ") sbiosGridSizer.Add( self.addButton, pos=(4,3)) self.sbiosPanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick) self.removeButton = wx.Button( self.sbiosPanel, -1, label=" Remove ") self.removeButton.Enable(False) # disable since nothing to remove yet sbiosGridSizer.Add( self.removeButton, pos=(4,5)) self.sbiosPanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick) self.hashListLabel = wx.StaticText(self.sbiosPanel, label=" Hash File List") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.hashListLabel.SetFont( font ) sbiosGridSizer.Add( self.hashListLabel, pos=(3,4)) self.sbiosPanelWidgets.append(self.hashListLabel) self.fileCntLabel = wx.StaticText(self.sbiosPanel, label="Number of Files") sbiosGridSizer.Add( self.fileCntLabel, pos=(5,3)) self.sbiosPanelWidgets.append(self.fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.sbiosPanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) sbiosGridSizer.Add( self.fileCntEdit, pos=(5,4)) self.sbiosPanelWidgets.append(self.fileCntEdit) self.hashListBox = wx.TextCtrl( self.sbiosPanel, value="", size=(150, 120), style = wx.TE_MULTILINE) # Note: add |wx.HSCROLL to get a horiz scroll bar # hashListBox must be enabled so can select items to remove self.hashListBox.Bind(wx.EVT_TEXT, self.onHashListBoxEdit) self.hashListBox.SetInsertionPoint(0) sbiosGridSizer.Add( self.hashListBox, pos=(4,4)) self.sbiosPanelWidgets.append(self.hashListBox) self.sbiosPanelWidgets.append(self.sbiosPanel) #sbiosHorizSizer.Add(sbiosGridSizer, 0, wx.ALL, 5) #self.sbiosPanelSizer.Add(sbiosHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.sbiosPanelSizer) parentSizer.Add(self.sbiosPanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(currentList, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the sbios panel""" #print("SBIOS hidePanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.sbiosPanelWidgets))) #DBGDBG for i in self.sbiosPanelWidgets: i.Hide() def showPanel(self): """showPanel - show the sbios panel""" #print("SBIOS showPanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.sbiosPanelWidgets))) #DBGDBG if self.panelCreated: for i in self.sbiosPanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - SBIOS_DEF""" currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = DEFINES.TPM_ALG_HASH['SHA256'] currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].FallBackHashFile = "" currentList.ElementDefData[self.myIndex].SbiosFiles = [] def onBrowseButtonClick(self, event): """onBrowseButtonClick - browse to a fallback hash file""" #self.StatusBar.SetStatusText("You clicked the Browse button") #fileName = '' #workdir = self.pdef.WorkingDirectory #wildcard = "Hash file (*.hash) | *.hash|" \ # "All Files (*.*) | *.*" #dlg = wx.FileDialog(self.parent, "Choose the fallback hash file", workdir, "", wildcard, wx.OPEN) # #abortFlag = False # Set to True if Add dialogue doidn't complete successfully #if dlg.ShowModal() == wx.ID_OK: # filename = dlg.GetFilename() # dirname = dlg.GetDirectory() #else: # abortFlag = True # abort after destroying the dialogue # #if(filename != ''): # # validate that the specified hash file is properly formatted # currentList = self.pdef.getCurrentListObject() # result = utilities.verifyHashFile(os.path.join(dirname, filename), currentList.ElementDefData[self.myIndex].HashAlg) # # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here # if( result[0] == True): # # Copy file into working directory # if (dirname != workdir): # if (os.path.exists(os.path.join(workdir, filename))) : # cdlg = wx.MessageDialog(self.parent, filename+" already exists in working directory\nOverwrite file in working directory?", "Confirm Copy", wx.OK|wx.CANCEL|wx.ICON_QUESTION) # if (cdlg.ShowModal() == wx.ID_OK): # shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) # else: # self.StatusBar.SetStatusText( "Add cancelled" ) # cdlg.Destroy() # else: # shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) self.fallbackFileEdit.ChangeValue(filename) currentList.ElementDefData[self.myIndex].FallBackHashFile = filename self.setListModified() self.fallbackRemoveButton.Enable(True) dlg.Destroy() def onFallbackRemoveButtonClick(self, event): """onFallbackRemoveButtonClick - delete the fallback hash file""" self.StatusBar.SetStatusText("Fallback hash file %s removed." % (self.fallbackFileEdit.GetValue())) self.fallbackFileEdit.ChangeValue("") currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].FallBackHashFile = "" self.setListModified() self.fallbackRemoveButton.Enable(False) # only supports adding files with the add button, not entering the names directly def onHashListBoxEdit(self, event): """onHashListBoxEdit""" print("in SBIOS::onHashListBoxEdit") # DBGDBG # tell the user to add button and clear the field self.StatusBar.SetStatusText("Please clear the entry, then use the Add button to add hash files to the list") #self.hashListBox.Undo() #TODO: wxPython: onHashListBoxEdit - Clear() and Undo() both generate an event causing: RuntimeError: maximum recursion depth exceeded def onAddButtonClick(self, event): """onAddButtonClick - add a hash file to the list""" filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # update the file count and enable the remove button lineCnt = currentList.ElementDefData[self.myIndex].NumbHashes #print("onAddButtonClick: was %i lines" % (lineCnt)) # DBGDBG lineCnt += 1 # MaxHashes = 0 means there is no limit on the number of hash files allowed if(self.pdef.MaxHashes != 0): if(lineCnt > self.pdef.MaxHashes): self.StatusBar.SetStatusText("Only %d files can be added." % (self.pdef.MaxHashes)) return #print("onAddButtonClick: now %i lines" % (lineCnt)) # DBGDBG self.fileCntEdit.ChangeValue(str(lineCnt)) self.removeButton.Enable(True) #print("new hashFileList = %s" % (hashFileList)) # DBGDBG # insert the new file into sbios.SbiosFiles self.setListModified() currentList.ElementDefData[self.myIndex].SbiosFiles.append(filename) currentList.ElementDefData[self.myIndex].NumbHashes = lineCnt #print("ElementDefData[self.myIndex].NumbHashes=%i, SbiosFiles = %s" % (currentList.ElementDefData[self.myIndex].NumbHashes, currentList.ElementDefData[self.myIndex].SbiosFiles)) # DBGDBG # since hashListBox.AppendText() generates an event to onHashListBoxEdit() # and since hashListBoxEdit has to be enabled so text can be selected for Remove # and direct text entry by the user into hashListBoxEdit is not supported due the complexity of validating it ... # # hashListBox.ChangeValue() doesn't generate an event but only takes a string, not a hashFileList which is a list ie '[]' # so form a single string containing everything in hashFileList and update hashListBox using ChangeValue(hashFileString) string = utilities.formStringFromListOfStrings(currentList.ElementDefData[self.myIndex].SbiosFiles) self.hashListBox.ChangeValue(string) def onRemoveButtonClick(self, event): """onRemoveButtonClick - remove the selected entry from the hash file list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return selection = self.hashListBox.GetStringSelection() self.StatusBar.SetStatusText("Removed selection %s" % (selection)) # selection may not be a full line ... See if the selection is contianed in any of hashFileList's entries currentList = self.pdef.getCurrentListObject() hashFileList = currentList.ElementDefData[self.myIndex].SbiosFiles for entry in hashFileList: #print("entry=%s" % (entry)) # DBGDBG start = entry.find(selection) if(start != -1): # -1 means not found, else find returns the starting index of selection #print("Found: %s at %i" % (selection, start)) # DBGDBG # entry was found, but was it a partial selection? if(selection not in hashFileList): # is selection on the GUI in PDEF's hashFileList? # partial selection #print("Partial selection %s not found in %s." % (selection, hashFileList)) # DBGDBG self.StatusBar.SetStatusText("Please select the entire line") break else: # Full selection, so remove that entry # decr sbios.NumbHashes & update NumberOfFiles widget fileCnt = int(self.fileCntEdit.GetValue()) fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt hashFileList.remove(selection) # remove the selection from the PDEF object #print("hashFileList=%s" % (hashFileList)) # DBGDBG if(fileCnt == 0): # disable REMOVE if no more files left self.removeButton.Enable(False) self.hashListBox.ChangeValue('') else: # rebuild the content of hashFileEdit from hashFileList and update the screen with ChangeValue # to avoid generating an event and to clear the previous LF hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) # DBGDBG self.hashListBox.ChangeValue(hashFileString) #print("hashListBox=%s" % (self.hashListBox.GetValue())) # DBGDBG self.setListModified() currentList.ElementDefData[self.myIndex].SbiosFiles = hashFileList break else: self.StatusBar.SetStatusText("Selection %s not found. Please select only a single line" % (selection)) # DBGDBG def onOverridePsPolicy(self, event): currentList = self.pdef.getCurrentListObject() self.setListModified() if(event.Checked() == True): currentList.ElementDefData[self.myIndex].Control = 1 else: currentList.ElementDefData[self.myIndex].Control = 0 def writeSbiosDef(self, sbiosDefData, f): """writeSbiosDef - write the Sbios Def to the specified file""" print("writeSbiosDef dump, hashAlg=%d" % (self.myHashAlg)) # DBGDBG pickle.dump(sbiosDefData, f) # write out the sbiosDefData object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to sbios panel widgets""" self.fallbackFileEdit.ChangeValue("") self.addButton.Enable(True) self.removeButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.hashListBox.ChangeValue("") def restorePanel(self, currentList, maxHashes): """restorePanel - restore the SBIOS element panel from the specified PLIST_DEF""" print("restorePanel - SBIOS") # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) self.fallbackFileEdit.ChangeValue(currentList.ElementDefData[self.myIndex].FallBackHashFile) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # enable remove if >0 hashes if(numbHashes > 0): self.removeButton.Enable(True) self.fileCntEdit.ChangeValue(str(numbHashes)) # form a string from hashFileList and update hashListBox string = utilities.formStringFromListOfStrings(currentList.ElementDefData[self.myIndex].SbiosFiles) self.hashListBox.ChangeValue(string) #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # #print("Sbios setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcp-gen2/sbiosLegacy.py0000644000000000000000000005104214210363175015304 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import SBIOSLEGACY_DEF from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # TXT Policy Generator Tool # SBIOS Class - Policy Definition File Lists # class SBIOSLegacy( ElementGui ): CONST_TITLE = "Choose Hash File" CONST_WILDCARD = "Hash file (*.hash)|*.hash|" \ "All Files (*.*)|*.*" """__init__() - SBIOS class constructor""" def __init__( self ): self.sbiosPanelWidgets = [] self.panelCreated = False # # create the SBIOS Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createSbiosPanel - create the SBIOS Panel""" #print("createOrShowSbiosPanel panelCreated == %s" % (self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() # Get the list corresponds to this element. currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the Sbios Panel sizers #self.sbiosPanelSizer = wx.BoxSizer(wx.VERTICAL) sbiosGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #sbiosHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.sbiosPanel = wx.Panel(parent, -1) self.sbiosPanel.SetSizer(sbiosGridSizer) sbiosLabelText1 = "SBIOS" sbiosLabelText2 = "Element" sbiosLabel1 = wx.StaticText(self.sbiosPanel, -1, sbiosLabelText1) sbiosLabel2 = wx.StaticText(self.sbiosPanel, -1, sbiosLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) sbiosLabel1.SetFont( font ) sbiosGridSizer.Add( sbiosLabel1, pos=(0, 3)) self.sbiosPanelWidgets.append(sbiosLabel1) sbiosLabel2.SetFont( font ) sbiosGridSizer.Add( sbiosLabel2, pos=(0, 4)) self.sbiosPanelWidgets.append(sbiosLabel2) self.typeLabel = wx.StaticText(self.sbiosPanel, label="Type") sbiosGridSizer.Add( self.typeLabel, pos=(1,3)) self.sbiosPanelWidgets.append(self.typeLabel) self.typeEdit = wx.TextCtrl( self.sbiosPanel, value="SBIOS", size=(40, -1)) self.typeEdit.Enable( False ) sbiosGridSizer.Add( self.typeEdit, pos=(1,4)) self.sbiosPanelWidgets.append(self.typeEdit) self.contolOptionsLabel = wx.StaticText(self.sbiosPanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.contolOptionsLabel.SetFont( font ) self.overridePsPolicy = wx.CheckBox(self.sbiosPanel, label="Override PS Policy") self.overridePsPolicy.Enable( False ) #Note: overridePsPolicy - control always disabled since there are no SBIOS specific controls - p12 sbiosGridSizer.Add(self.contolOptionsLabel, pos=(0,14), span=(1,2), flag=wx.BOTTOM, border=5) sbiosGridSizer.Add(self.overridePsPolicy, pos=(1,14), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) self.sbiosPanelWidgets.append(self.contolOptionsLabel) self.sbiosPanelWidgets.append(self.overridePsPolicy) hashList = ['SHA1'] self.hashAlgLabel = wx.StaticText(self.sbiosPanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.hashAlgLabel.SetFont( font ) sbiosGridSizer.Add(self.hashAlgLabel, pos=(0,20)) self.sbiosPanelWidgets.append(self.hashAlgLabel) hashAlgEdit = wx.ComboBox( self.sbiosPanel, size=(75, -1), value="SHA1", choices=hashList, style=wx.CB_DROPDOWN ) sbiosGridSizer.Add(hashAlgEdit, pos=(1,20)) self.sbiosPanelWidgets.append(hashAlgEdit) self.fallbackFileLabel = wx.StaticText(self.sbiosPanel, label="Fallback\nHash") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.NORMAL) self.fallbackFileLabel.SetFont( font ) sbiosGridSizer.Add( self.fallbackFileLabel, pos=(2,3)) self.sbiosPanelWidgets.append(self.fallbackFileLabel) self.fallbackFileEdit = wx.TextCtrl( self.sbiosPanel, value="", size=(150, -1)) self.fallbackFileEdit.Enable(False) # must use BROWSE to locate the fallback file fallbackFile = currentList.ElementDefData[self.myIndex].FallBackHashFile if (fallbackFile == "" or fallbackFile == None): fallbackFile = "Fallback.hash" self.fallbackFileEdit.AppendText(fallbackFile) sbiosGridSizer.Add( self.fallbackFileEdit, pos=(2,4)) self.sbiosPanelWidgets.append(self.fallbackFileEdit) currentList.ElementDefData[self.myIndex].FallBackHashFile = fallbackFile self.browseButton = wx.Button( self.sbiosPanel, -1, label="Browse") sbiosGridSizer.Add( self.browseButton, pos=(2,5)) self.sbiosPanelWidgets.append(self.browseButton) self.browseButton.Bind(wx.EVT_BUTTON, self.onBrowseButtonClick) self.fallbackRemoveButton = wx.Button( self.sbiosPanel, -1, label="Remove") sbiosGridSizer.Add( self.fallbackRemoveButton, pos=(1,5)) self.sbiosPanelWidgets.append(self.fallbackRemoveButton) self.fallbackRemoveButton.Bind(wx.EVT_BUTTON, self.onFallbackRemoveButtonClick) self.fallbackRemoveButton.Enable(True) self.addButton = wx.Button( self.sbiosPanel, -1, label=" Add ") sbiosGridSizer.Add( self.addButton, pos=(4,3)) self.sbiosPanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick) self.sbiosPanelWidgets.append(self.addButton) self.removeButton = wx.Button( self.sbiosPanel, -1, label=" Remove ") self.removeButton.Enable(False) # disable since nothing to remove yet sbiosGridSizer.Add( self.removeButton, pos=(4,5)) self.sbiosPanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick) self.sbiosPanelWidgets.append(self.removeButton) self.hashListLabel = wx.StaticText(self.sbiosPanel, label=" Hash File List") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) self.hashListLabel.SetFont( font ) sbiosGridSizer.Add( self.hashListLabel, pos=(3,4)) self.sbiosPanelWidgets.append(self.hashListLabel) self.fileCntLabel = wx.StaticText(self.sbiosPanel, label="Number of Files") sbiosGridSizer.Add( self.fileCntLabel, pos=(5,3)) self.sbiosPanelWidgets.append(self.fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.sbiosPanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) sbiosGridSizer.Add( self.fileCntEdit, pos=(5,4)) self.sbiosPanelWidgets.append(self.fileCntEdit) self.hashListBox = wx.TextCtrl( self.sbiosPanel, value="", size=(150, 120), style = wx.TE_MULTILINE) # Note: add |wx.HSCROLL to get a horiz scroll bar # hashListBox must be enabled so can select items to remove self.hashListBox.Bind(wx.EVT_TEXT, self.onHashListBoxEdit) self.hashListBox.SetInsertionPoint(0) sbiosGridSizer.Add( self.hashListBox, pos=(4,4)) self.sbiosPanelWidgets.append(self.hashListBox) self.sbiosPanelWidgets.append(self.sbiosPanel) #sbiosHorizSizer.Add(sbiosGridSizer, 0, wx.ALL, 5) #self.sbiosPanelSizer.Add(sbiosHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.sbiosPanelSizer) parentSizer.Add(self.sbiosPanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(currentList, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the sbios panel""" for i in self.sbiosPanelWidgets: i.Hide() def showPanel(self): """showSbiosPanel - show the sbios panel""" if self.panelCreated: for i in self.sbiosPanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - SBIOS_DEF""" currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = 0 currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].FallBackHashFile = "" currentList.ElementDefData[self.myIndex].SbiosFiles = [] def onBrowseButtonClick(self, event): """onBrowseButtonClick - browse to a fallback hash file""" #self.StatusBar.SetStatusText("You clicked the Browse button") fileName = '' workdir = self.pdef.WorkingDirectory wildcard = "Hash file (*.hash)|*.hash|" \ "All Files (*.*)|*.*" dlg = wx.FileDialog(self.parent, "Choose the fallback hash file", workdir, "", wildcard, wx.OPEN) abortFlag = False # Set to True if Add dialogue doidn't complete successfully if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() else: abortFlag = True # abort after destroying the dialogue if(filename != ''): # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(dirname, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == True): # Copy file into working directory if (dirname != workdir): if (os.path.exists(os.path.join(workdir, filename))) : cdlg = wx.MessageDialog(self.parent, filename+" already exists in working directory\nOverwrite file in working directory?", "Confirm Copy", wx.OK|wx.CANCEL|wx.ICON_QUESTION) if (cdlg.ShowModal() == wx.ID_OK): shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) else: self.StatusBar.SetStatusText( "Add cancelled" ) cdlg.Destroy() else: shutil.copyfile(os.path.join(dirname, filename), os.path.join(workdir, filename)) self.StatusBar.SetStatusText("Validated file %s." % (filename)) self.fallbackFileEdit.ChangeValue(filename) currentList.ElementDefData[self.myIndex].FallBackHashFile = filename self.setListModified() self.fallbackRemoveButton.Enable(True) dlg.Destroy() def onFallbackRemoveButtonClick(self, event): """onFallbackRemoveButtonClick - delete the fallback hash file""" self.StatusBar.SetStatusText("Fallback hash file %s removed." % (self.fallbackFileEdit.GetValue())) self.fallbackFileEdit.ChangeValue("") currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].FallBackHashFile = "" self.setListModified() self.fallbackRemoveButton.Enable(False) # only supports adding files with the add button, not entering the names directly def onHashListBoxEdit(self, event): """onHashListBoxEdit""" print("in SBIOS::onHashListBoxEdit") # DBGDBG # tell the user to add button and clear the field self.StatusBar.SetStatusText("Please clear the entry, then use the Add button to add hash files to the list") #self.hashListBox.Undo() #TODO: wxPython: onHashListBoxEdit - Clear() and Undo() both generate an event causing: RuntimeError: maximum recursion depth exceeded def onAddButtonClick(self, event): """onAddButtonClick - add a hash file to the list""" filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # update the file count and enable the remove button lineCnt = currentList.ElementDefData[self.myIndex].NumbHashes #print("onAddButtonClick: was %i lines" % (lineCnt)) # DBGDBG lineCnt += 1 # MaxHashes = 0 means there is no limit on the number of hash files allowed if(self.pdef.MaxHashes != 0): if(lineCnt > self.pdef.MaxHashes): self.StatusBar.SetStatusText("Only %d files can be added." % (self.pdef.MaxHashes)) return #print("onAddButtonClick: now %i lines" % (lineCnt)) # DBGDBG self.fileCntEdit.ChangeValue(str(lineCnt)) self.removeButton.Enable(True) hashFileList = currentList.ElementDefData[self.myIndex].SbiosFiles hashFileList.append(filename) #print("new hashFileList = %s" % (hashFileList)) # DBGDBG # insert the new file into sbios.SbiosFiles self.setListModified() currentList.ElementDefData[self.myIndex].SbiosFiles = hashFileList currentList.ElementDefData[self.myIndex].NumbHashes = lineCnt #print("ElementDefData[self.myIndex].NumbHashes=%i, SbiosFiles = %s" % (currentList.ElementDefData[self.myIndex].NumbHashes, currentList.ElementDefData[self.myIndex].SbiosFiles)) # DBGDBG # since hashListBox.AppendText() generates an event to onHashListBoxEdit() # and since hashListBoxEdit has to be enabled so text can be selected for Remove # and direct text entry by the user into hashListBoxEdit is not supported due the complexity of validating it ... # # hashListBox.ChangeValue() doesn't generate an event but only takes a string, not a hashFileList which is a list ie '[]' # so form a single string containing everything in hashFileList and update hashListBox using ChangeValue(hashFileString) string = utilities.formStringFromListOfStrings(hashFileList) self.hashListBox.ChangeValue(string) def onRemoveButtonClick(self, event): """onRemoveButtonClick - remove the selected entry from the hash file list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return selection = self.hashListBox.GetStringSelection() self.StatusBar.SetStatusText("Removed selection %s" % (selection)) # selection may not be a full line ... See if the selection is contianed in any of hashFileList's entries currentList = self.pdef.getCurrentListObject() hashFileList = currentList.ElementDefData[self.myIndex].SbiosFiles for entry in hashFileList: #print("entry=%s" % (entry)) # DBGDBG start = entry.find(selection) if(start != -1): # -1 means not found, else find returns the starting index of selection #print("Found: %s at %i" % (selection, start)) # DBGDBG # entry was found, but was it a partial selection? if(selection not in hashFileList): # is selection on the GUI in PDEF's hashFileList? # partial selection #print("Partial selection %s not found in %s." % (selection, hashFileList)) # DBGDBG self.StatusBar.SetStatusText("Please select the entire line") break else: # Full selection, so remove that entry # decr sbios.NumbHashes & update NumberOfFiles widget fileCnt = int(self.fileCntEdit.GetValue()) fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt hashFileList.remove(selection) # remove the selection from the PDEF object #print("hashFileList=%s" % (hashFileList)) # DBGDBG if(fileCnt == 0): # disable REMOVE if no more files left self.removeButton.Enable(False) self.hashListBox.ChangeValue('') else: # rebuild the content of hashFileEdit from hashFileList and update the screen with ChangeValue # to avoid generating an event and to clear the previous LF hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) # DBGDBG self.hashListBox.ChangeValue(hashFileString) #print("hashListBox=%s" % (self.hashListBox.GetValue())) # DBGDBG self.setListModified() currentList.ElementDefData[self.myIndex].SbiosFiles = hashFileList break else: self.StatusBar.SetStatusText("Selection %s not found. Please select only a single line" % (selection)) # DBGDBG def onOverridePsPolicy(self, event): currentList = self.pdef.getCurrentListObject() self.setListModified() if(event.Checked() == True): currentList.ElementDefData[self.myIndex].Control = 1 else: currentList.ElementDefData[self.myIndex].Control = 0 def writeSbiosDef(self, sbiosDefData, f): """writeSbiosDef - write the Sbios Def to the specified file""" #print("writeSbiosLegacyDef dump") # DBGDBG pickle.dump(sbiosDefData, f) # write out the sbiosDefData object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to sbios panel widgets""" self.fallbackFileEdit.ChangeValue("") self.addButton.Enable(True) self.removeButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.hashListBox.ChangeValue("") def restorePanel(self, currentList, maxHashes): """restorePanel - restore the SBIOS element panel from the specified PLIST_DEF""" print("restorePanel - SBIOS") # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) self.fallbackFileEdit.ChangeValue(currentList.ElementDefData[self.myIndex].FallBackHashFile) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # enable remove if >0 hashes if(numbHashes > 0): self.removeButton.Enable(False) self.fileCntEdit.ChangeValue(str(numbHashes)) # form a string from hashFileList and update hashListBox string = utilities.formStringFromListOfStrings(currentList.ElementDefData[self.myIndex].SbiosFiles) self.hashListBox.ChangeValue(string) #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # #print("Sbios setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True tboot-1.10.5/lcp-gen2/stm.py0000644000000000000000000004345214210363175013651 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function # # wxPython is not part of the standard Python distribution and has to be downloaded and installed separately. # Tell the user that wxPython is required but has not been found # try: import wx except ImportError: raise ImportError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os import shutil except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from pdef import STM_DEF from ElementGui import * from util import UTILS utilities = UTILS() try: import cPickle as pickle except ImportError: import pickle # fall back on Python version # TXT Policy Generator Tool # STM Class - Policy Definition File Lists # class STM( ElementGui ): CONST_TITLE = "Choose Hash File" CONST_WILDCARD = "Hash file (*.hash)|*.hash|" \ "All Files (*.*)|*.*" """__init__() - STM class constructor""" def __init__( self, hashAlg): self.stmPanelWidgets = [] self.panelCreated = False try: # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() except StopIteration: print("STM::__init__ - invalid hashAlg=%d" % (hashAlg)) return self.myIndex = DEFINES.DEFDATA_INDEX[hashAlgName] #if( hashAlg == DEFINES.TPM_ALG_HASH['SHA256']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA256 #elif( hashAlg == DEFINES.TPM_ALG_HASH['SHA1']): # self.myIndex = DEFINES.DEFDATA_INDEX_SHA1 #else: # print("STM::__init__ - invalid hashAlg=%d" % (hashAlg)) self.myHashAlg = hashAlg # # create the STM Panel # def createOrShowPanel(self, wx, listPanel, parent, pdef, statusBar): """createPanel - create the List Panel""" #print("createOrShowStmPanel hashAlg=%d, panelCreated == %s" % (self.myHashAlg, self.panelCreated)) # DBGDBG # 1st time, create the panel # nth time, show the panel if(self.panelCreated == True): self.showPanel() return self.pdef = pdef self.parent = parent self.listPanel = listPanel self.StatusBar = statusBar parentSizer = parent.GetSizer() # Get the list corresponds to this element. currentList = self.pdef.getCurrentListObject() self.myIndex = len(currentList.ElementDefData)-1 # Just added the element, the last one should be the one. # create the Stm Panel sizers #self.stmPanelSizer = wx.BoxSizer(wx.VERTICAL) self.stmGridSizer= wx.GridBagSizer(hgap=5, vgap=5) #self.stmHorizSizer = wx.BoxSizer(wx.HORIZONTAL) self.stmPanel = wx.Panel(parent, -1) self.stmPanel.SetSizer(self.stmGridSizer) stmLabelText1 = "STM" stmLabelText2 = "Element" stmLabel1 = wx.StaticText(self.stmPanel, -1, stmLabelText1) stmLabel2 = wx.StaticText(self.stmPanel, -1, stmLabelText2) font = wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) stmLabel1.SetFont( font ) self.stmGridSizer.Add( stmLabel1, pos=(0, 3)) self.stmPanelWidgets.append(stmLabel1) stmLabel2.SetFont( font ) self.stmGridSizer.Add( stmLabel2, pos=(0, 4)) self.stmPanelWidgets.append(stmLabel2) typeLabel = wx.StaticText(self.stmPanel, label="Type") self.stmGridSizer.Add( typeLabel, pos=(1,3)) self.stmPanelWidgets.append(typeLabel) typeEdit = wx.TextCtrl( self.stmPanel, value="STM", size=(40, -1)) typeEdit.Enable( False ) self.stmGridSizer.Add( typeEdit, pos=(1,4)) self.stmPanelWidgets.append(typeEdit) contolOptionsLabel = wx.StaticText(self.stmPanel, -1, "Control") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) contolOptionsLabel.SetFont( font ) # override PS policy bit is applicable only if PO policy rules self.overridePsPolicy = wx.CheckBox(self.stmPanel, label="Override PS Policy") if(self.pdef.Rules == DEFINES.PoRules): self.overridePsPolicy.Enable( True ) else: self.overridePsPolicy.Enable( False ) self.stmGridSizer.Add(contolOptionsLabel, pos=(0,9), span=(1,2), flag=wx.BOTTOM, border=5) self.stmGridSizer.Add(self.overridePsPolicy, pos=(1,9), span=(1,2), flag=wx.BOTTOM, border=5) self.overridePsPolicy.Bind(wx.EVT_CHECKBOX, self.onOverridePsPolicy) self.stmPanelWidgets.append(contolOptionsLabel) self.stmPanelWidgets.append(self.overridePsPolicy) hashAlgStr = self.getHashAlgName() if hashAlgStr == None: print("createOrShowStmPanel - invalid myHashAlg=%d" % (self.myHashAlg)) hashAlgLabel = wx.StaticText(self.stmPanel, label="Hash Algorithm") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) hashAlgLabel.SetFont( font ) self.stmGridSizer.Add(hashAlgLabel, pos=(0,20)) self.stmPanelWidgets.append(hashAlgLabel) hashAlgEdit = wx.TextCtrl( self.stmPanel, size=(75, -1), value=hashAlgStr ) hashAlgEdit.Enable(False) self.stmGridSizer.Add(hashAlgEdit, pos=(1,20)) self.stmPanelWidgets.append(hashAlgEdit) self.addButton = wx.Button( self.stmPanel, -1, label=" Add ") self.stmGridSizer.Add( self.addButton, pos=(4,3)) self.stmPanelWidgets.append(self.addButton) self.addButton.Bind(wx.EVT_BUTTON, self.onAddButtonClick) self.removeButton = wx.Button( self.stmPanel, -1, label=" Remove ") self.removeButton.Enable(False) self.stmGridSizer.Add( self.removeButton, pos=(4,5)) self.stmPanelWidgets.append(self.removeButton) self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButtonClick) hashListLabel = wx.StaticText(self.stmPanel, label=" Hash File List") font = wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.BOLD) hashListLabel.SetFont( font ) self.stmGridSizer.Add( hashListLabel, pos=(3,4)) self.stmPanelWidgets.append(hashListLabel) fileCntLabel = wx.StaticText(self.stmPanel, label="Number of Files") self.stmGridSizer.Add( fileCntLabel, pos=(5,3)) self.stmPanelWidgets.append(fileCntLabel) self.fileCntEdit = wx.TextCtrl( self.stmPanel, value="0", size=(40, -1)) self.fileCntEdit.Enable( False ) self.stmGridSizer.Add( self.fileCntEdit, pos=(5,4)) self.stmPanelWidgets.append(self.fileCntEdit) hashFileList = [''] self.hashListBox = wx.TextCtrl( self.stmPanel, value="", size=(150, 120), style = wx.TE_MULTILINE) # Note: add |wx.HSCROLL to get a horiz scroll bar # hashListBox must be enabled so can select items to remove self.hashListBox.Bind(wx.EVT_TEXT, self.onHashListBoxEdit) self.hashListBox.SetInsertionPoint(0) self.stmGridSizer.Add( self.hashListBox, pos=(4,4)) self.stmPanelWidgets.append(self.hashListBox) self.stmPanelWidgets.append(self.stmPanel) #print("STM createPanel - len(Widgets)=%d" % (len(self.stmPanelWidgets))) #DBGDBG #self.stmHorizSizer.Add(self.stmGridSizer, 0, wx.ALL, 5) #self.stmPanelSizer.Add(self.stmHorizSizer, 0, wx.ALL, 5) #parent.SetSizerAndFit(self.stmPanelSizer) parentSizer.Add(self.stmPanel) w,h = parentSizer.GetMinSize() parent.SetVirtualSize((w,h)) parent.Layout() # call restorePanel to sync data to GUI self.restorePanel(currentList, pdef.MaxHashes) self.panelCreated = True def hidePanel(self): """hidePanel - hide the Stm panel""" #print("STM hidePanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.stmPanelWidgets))) #DBGDBG for i in self.stmPanelWidgets: i.Hide() def showPanel(self): """showPanel - show the stm panel""" #print("STM showPanel - hashAlg=%d, len(Widgets)=%d" % (self.myHashAlg, len(self.stmPanelWidgets))) #DBGDBG if self.panelCreated: for i in self.stmPanelWidgets: i.Show() parentSizer = self.parent.GetSizer() w,h = parentSizer.GetMinSize() self.parent.SetVirtualSize((w,h)) def setElementToDefaults(self): """setElementToDefaults - STM""" currentList = self.pdef.getCurrentListObject() currentList.ElementDefData[self.myIndex].IncludeInList = False currentList.ElementDefData[self.myIndex].HashAlg = self.myHashAlg currentList.ElementDefData[self.myIndex].Control = 0 currentList.ElementDefData[self.myIndex].NumbHashes = 0 currentList.ElementDefData[self.myIndex].CurrentView = 0 currentList.ElementDefData[self.myIndex].HashFiles = [] def onOverridePsPolicy(self, event): currentList = self.pdef.getCurrentListObject() self.setListModified() # set/clear bit 0 per STM Dev Guide PolEltControl def if(event.Checked() == True): currentList.ElementDefData[self.myIndex].Control = 1 else: currentList.ElementDefData[self.myIndex].Control = 0 def onMinSinitVersion(self, event): value = event.GetString() currentList = self.pdef.getCurrentListObject() self.setListModified() # only supports adding files with the add button, not entering the names directly def onHashListBoxEdit(self, event): """onHashListBoxEdit""" #print("in STM::onHashListBoxEdit") # DBGDBG # tell the user to add button and clear the field self.StatusBar.SetStatusText("Please clear the entry, then use the Add button to add hash files to the list") #self.hashListBox.Undo() #TODO: wxPython: onHashListBoxEdit - Clear() and Undo() both generate an event causing: RuntimeError: maximum recursion depth exceeded def onAddButtonClick(self, event): """onAddButtonClick - add a hash file to the list""" filepath, filename = self.selectFile() if (filename == ''): # selectFile() operation has been cancelled. return # validate that the specified hash file is properly formatted currentList = self.pdef.getCurrentListObject() result = utilities.verifyHashFile(os.path.join(filepath, filename), currentList.ElementDefData[self.myIndex].HashAlg) # Note: verifyHashFile() returns [FileValid, FileType], but only FileValid is used here if( result[0] == False): return self.copyFile(filepath, filename) self.StatusBar.SetStatusText("Validated file %s." % (filename)) # update the file count and enable the remove button lineCnt = currentList.ElementDefData[self.myIndex].NumbHashes #print("onAddButtonClick: was %i lines" % (lineCnt)) # DBGDBG lineCnt += 1 # MaxHashes = 0 means there is no limit on the number of hash files allowed if(self.pdef.MaxHashes != 0): if(lineCnt > self.pdef.MaxHashes): self.StatusBar.SetStatusText("Only %d files can be added." % (self.pdef.MaxHashes)) return #print("onAddButtonClick: now %i lines" % (lineCnt)) # DBGDBG self.fileCntEdit.ChangeValue(str(lineCnt)) self.removeButton.Enable(True) hashFileList = currentList.ElementDefData[self.myIndex].HashFiles hashFileList.append(filename) #print("new hashFileList = %s" % (hashFileList)) # DBGDBG # insert the new file into stm.HashFiles self.setListModified() currentList.ElementDefData[self.myIndex].HashFiles = hashFileList currentList.ElementDefData[self.myIndex].NumbHashes = lineCnt #print("StmDefData[self.myIndex].NumbHashes=%i, HashFiles = %s" % # (currentList.ElementDefData[self.myIndex].NumbHashes, currentList.ElementDefData[self.myIndex].HashFiles)) # DBGDBG # since hashListBox.AppendText() generates an event to onHashListBoxEdit() # and since hashListBoxEdit has to be enabled so text can be selected for Remove # and direct text entry by the user into hashListBoxEdit is not supported due the complexity of validating it ... # # hashListBox.ChangeValue() doesn't generate an event but only takes a string, not a hashFileList which is a list ie '[]' # so form a single string containing everything in hashFileList and update hashListBox using ChangeValue(hashFileString) hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) self.hashListBox.ChangeValue(hashFileString) def onRemoveButtonClick(self, event): """onRemoveButtonClick - remove the selected entry from the hash file list""" # confirm the remove dlg = wx.MessageDialog(None, "Confirm removal of selected file?", 'Confirm Remove', wx.YES_NO | wx.ICON_QUESTION) response = dlg.ShowModal() dlg.Destroy() if(response == wx.ID_NO): self.StatusBar.SetStatusText( "Remove cancelled" ) return selection = self.hashListBox.GetStringSelection() self.StatusBar.SetStatusText("Removed selection %s" % (selection)) # selection may not be a full line ... See if the selection is contianed in any of hashFileList's entries currentList = self.pdef.getCurrentListObject() hashFileList = currentList.ElementDefData[self.myIndex].HashFiles for entry in hashFileList: #print("entry=%s" % (entry)) # DBGDBG start = entry.find(selection) if(start != -1): # -1 means not found, else find returns the starting index of selection #print("Found: %s at %i" % (selection, start)) # DBGDBG # entry was found, but was it a partial selection? if(selection not in hashFileList): # is selection on the GUI in PDEF's hashFileList? # partial selection #print("Partial selection %s not found in %s." % (selection, hashFileList)) # DBGDBG self.StatusBar.SetStatusText("Please select the entire line") break else: # Full selection, so remove that entry # decr stm.NumbHashes & update NumberOfFiles widget fileCnt = int(self.fileCntEdit.GetValue()) fileCnt -= 1 self.fileCntEdit.ChangeValue(str(fileCnt)) currentList.ElementDefData[self.myIndex].NumbHashes = fileCnt hashFileList.remove(selection) # remove the selection from the PDEF object #print("hashFileList=%s" % (hashFileList)) # DBGDBG if(fileCnt == 0): # disable REMOVE if no more files left self.removeButton.Enable(False) self.hashListBox.ChangeValue('') else: # rebuild the content of hashFileEdit from hashFileList and update the screen with ChangeValue # to avoid generating an event and to clear the previous LF hashFileString = '' index = 0 for eachString in hashFileList: if(index != 0): # if not the 1st entry, need a LF before the new entry hashFileString += "\n" hashFileString += eachString index += 1 #print("thisString=%s, hashFileString=%s" % (eachString, hashFileString)) # DBGDBG self.hashListBox.ChangeValue(hashFileString) #print("hashListBox=%s" % (self.hashListBox.GetValue())) # DBGDBG self.setListModified() currentList.ElementDefData[self.myIndex].HashFiles = hashFileList break else: self.StatusBar.SetStatusText("Selection %s not found. Please select only a single line" % (selection)) # DBGDBG def writeStmDef(self, stmDefData, f): """writeStmDef - write the Stm Def to the specified file""" print("writeStmDef dump, hashAlg=%d" % (self.myHashAlg)) # DBGDBG pickle.dump(stmDefData, f) # write out the stmDefData object def setPanelToDefaults(self): """setPanelToDefaults - restore defaults to stm panel widgets""" self.addButton.Enable(True) self.removeButton.Enable(False) self.fileCntEdit.ChangeValue("0") self.hashListBox.ChangeValue("") def restorePanel(self, currentList, maxHashes): """restorePanel - restore the STM element panel from the specified PLIST_DEF""" print("restorePanel - STM") # DBGDBG # update Override PS Policy checkbox self.overridePsPolicy.SetValue(currentList.ElementDefData[self.myIndex].Control) listversion = str(currentList.ListVersionMajor)+'.'+str(currentList.ListVersionMinor) if listversion == '2.0': self.showV20Gui(True) else: self.showV20Gui(False) # If MaxHashes not 0, Only enable Add if < MaxHashes files numbHashes = currentList.ElementDefData[self.myIndex].NumbHashes flag = True if(maxHashes != 0): if(numbHashes >= maxHashes): flag = False # don't enable add self.addButton.Enable(flag) # enable remove if >0 hashes flag = False if(numbHashes > 0): flag = True self.removeButton.Enable(flag) self.fileCntEdit.ChangeValue(str(numbHashes)) # form a string from hashFileList and update hashListBox string = utilities.formStringFromListOfStrings(currentList.ElementDefData[self.myIndex].HashFiles) self.hashListBox.ChangeValue(string) #def setListModified(self): # """setListModified - if list not modified yet, increment its rev cnt and set it to modified""" # # currentList = self.pdef.getCurrentListObject() # #print("Stm setListModified - ListModified was %s" % (currentList.ListModified)) # DBGDBG # if(currentList.ListModified == False): # currentList.RevocationCounter += 1 # self.listPanel.revocationCountEdit.ChangeValue(str(currentList.RevocationCounter)) # update the GUI # currentList.ListModified = True # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcp-gen2/tools.py0000644000000000000000000001645614210363175014212 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # TXT Policy Generator Tool - tools invoked from tools menu # Hash image # Insert policy into image # using print() built infunction, disable print statement from __future__ import print_function try: import wx except ImportWxError: raise ImportWxError, "Please download the appropriate version of wxPython from www.wxpython.org" try: import os except ImportOsError: raise ImportOsError, "import OS failed" import array import M2Crypto import struct # Pycrypto module from: https://www.dlitz.net/software/pycrypto/ is required #try: # from Crypto.Hash import SHA # SHA1 # from Crypto.Hash import SHA256 # SHA256 #except ImportError: # raise ImportError, "PyCrypto import failed. Please install PyCrypto ..." from defines import DEFINES from util import UTILS utilities = UTILS() class TOOLS(object): # hash a bios image 'file' [i.e. base.bin] from 'startOffset' for 'offsetSize' bytes, # and write the hash to base.hash, as a LCP2 raw hash file, and base.dat as an 'ascii coded binary' # I.e. if the image's hash starts with: 0xB0, 0x61, 0x52, ... # then the .hash file starts with: B0 61 52 ... (i.e. the raw binary hash) # and the .dat file starts with: 42 30 20 36 31 20 35 32 20 # (i.e. each hex digit is represented by its ascii equivalent with an ascii space after each hex pair # Parameters # biosFileName - name of the bios file to be hashed # startOffset - offset into the file to start hashing from, aka base # offsetSize - size to hash from startOffset # hashAlg - hash algorithm to use, TPM_ALG_XXXX where XXXX is SHA1 or SHA256 # Return True on success or # False on any error # def hashImage(self, biosFileName, startOffsetStr, offsetSizeStr, hashAlgStr): """hashImage - generate the hash of the specified file from start address for size bytes""" function = 'hashImage' biosPath = os.path.abspath(os.path.normpath(biosFileName)) startOffset = int(startOffsetStr, 16) offsetSize = int(offsetSizeStr, 16) hashAlg = int(hashAlgStr, 16) MAX_BIOS_SIZE = 0x1000000; print("%s - biosFile=%s, startOffset=0x%x, offsetSize=0x%x, hashAlg=%d" % (function, biosPath, startOffset, offsetSize, hashAlg)) # DBGDBG # use biosFile's base name for the .tmp and .hash files # biosFile - file to be hashed, ie if biosFileName = biosXYZ.bin then base = biosXYZ # tempFile - base.tmp - temp file containing the data to hash # i.e. biosFile's data from startOffset to startOffset+offsetSize # hashFile - base.hash - output file containg the hash of tempFile # verify that biosFile can be opened try: biosFile = open(biosPath, 'rb') except: print("Unable to open specified file: %s" % (biosPath)) return False # strip off the .ext leaving the base if(biosFileName.endswith('.bin') == True): base = os.path.basename(biosFileName).split('.bin') else: print("Expected .bin extention for Bios File %s" % (biosPath)) return False #TODO: will all bios files have .bin extentions?????????????????????????????????????? #print("%s - base=%s" % (function, base[0])) # DBGDBG # verify that .tmp, .dat and .hash files can be created in the current dir, else exit tmpFileName = utilities.formFileName(base[0], "tmp") hashFileName = utilities.formFileName(base[0], "hash") datFileName = utilities.formFileName(base[0], "dat") #print("%s - tmpFileName=%s, hashFileName=%s" % (function, tmpFileName, hashFileName)) # DBGDBG try: tmpFile = open(tmpFileName, 'wb') except: print("Unable to create file: %s" % (tmpFileName)) biosFile.close() return False try: hashFile = open(hashFileName, 'wb') except: print("Unable to create file: %s" % (hashFileName)) tmpFile.close() biosFile.close() return False try: datFile = open(datFileName, 'wb') except: print("Unable to create file: %s" % (datFileName)) tmpFile.close() biosFile.close() datFile.close() return False # Determine biosFile's size biosFile.seek (0, os.SEEK_END) biosFileSize = biosFile.tell() # if startOffset > MAX_BIOS_SIZE, then adjust startOffset to be relative to 4Gb if (startOffset > MAX_BIOS_SIZE): print("The specified StartOffset(0x%x) is > than the max bios size(%x) Assuming StartOffset is relative to 4Gb" % (startOffset, MAX_BIOS_SIZE)) beginingOfBiosImage = 0x100000000 - biosFileSize; startOffset = startOffset - beginingOfBiosImage; print("%s - startOffset now 0x%x, MAX_BIOS_SIZE=0x%x" % (startOffset, MAX_BIOS_SIZE)) # If startOffset + offsetSize > biosFile's size, adjust offsetSize if(startOffset + offsetSize > biosFileSize): print("%s - The specified StartOffset(0x%x) + offsetSize(0x%x) is larger than biosFileSize(0x%x)" % (function, startOffset, offsetSize, biosFileSize)) offsetSize = biosFileSize - startOffset; print("StartOffset+OffsetSize > BiosFileSize. Resetting OffsetSize to 0x%x" % (offsetSize)) #print("%s - biosFileSize=0x%x, startOffset+offsetSize=0x%x, MAX_BIOS_SIZE=0x%x" % (function, biosFileSize, startOffset+offsetSize, MAX_BIOS_SIZE)) # DBGDBG # buffer the part of the bios that will be hashed in base.tmp # open the bios file, # set the read pointer to: startOffset # read offsetSize bytes into tempFile data = array.array ("B") biosFile.seek(startOffset, os.SEEK_SET) #print("%s - pos=0x%x" % (function, biosFile.tell())) # DBGDBG data.fromfile(biosFile, offsetSize) # Initialize to None to check for supported HashAlg. hashAlgName = None # reverse lookup of the hash algorithm name(key) for the given HashAlg value hashAlgName = (key for key,val in DEFINES.TPM_ALG_HASH.items() if (val == hashAlg)).next() if (hashAlgName != None): # This handles all SHA hash algorithms. hash = M2Crypto.EVP.MessageDigest(hashAlgName.lower()) else: self.StatusBar.SetStatusText("Hash Algorithm %d is not supported" % (hashAlg)) return False hash.update(data) hashdigest = hash.digest() # cannot call this M2Crypto function twice. print(data, end='', file=tmpFile ) # for testing that the right data was hashed print(hashdigest, end='', file=hashFile ) hexHash = hashdigest.encode('hex') print("Image's hash: %s" % (hexHash)) print("Generated hash files: %s.hash and %s.dat" % (base[0],base[0])) # generate the .dat from hexHash: convert each hex byte to a ascii digit followed by a space i=0 while(i < len(hexHash)): print(hexHash[i].upper(), end='', file=datFile ) # 1st hexdigit as upper case ascii print(hexHash[i+1].upper(), end='', file=datFile ) # 2nd hexdigit as upper case ascii print(' ', end='', file=datFile ) # space after each pair i += 2 print('\n', end='', file=datFile ) # final LF to match WinLCP biosFile.close() tmpFile.close() hashFile.close() datFile.close() return True tboot-1.10.5/lcp-gen2/util.py0000644000000000000000000011754214210363175014025 0ustar 00000000000000#!/usr/bin/python # Copyright (c) 2013, Intel Corporation. All rights reserved. # using print() built infunction, disable print statement from __future__ import print_function try: import os, sys except ImportError: raise ImportError, "import OS failed" from defines import DEFINES from struct import pack, unpack import array import M2Crypto from asn1spec import * # utility routines class UTILS( object ): def checkFileTag(self, file, expectedTag): """checkFileTag - Return True if the specified file starts with the specified tag, else False""" # expectedTag either: # PCRD+TAG = "PCRD" for .pcr files # HASH_TAG = "HASH" for .hash files # read the 1st 4 bytes from the file (i.e. the actualTag) and compare that to the expectedTag # tagLength = 4 myFile = open(file, "rb") actualTag = myFile.read(tagLength) myFile.close() #print("UTILS::checkFileTag: file=%s expectedTag=%s actualTag=%s" % (file, expectedTag, actualTag)) # DBGDBG if(actualTag == expectedTag): return True else: return False def invalidHashFileMsg(self, file, actHashAlg, expHashAlg, hashFileLength): """invalidHashFileMsg - display status bar msg if hash file is invalid""" print ("Invalid hash format for this element's HashAlg. file %s, Exp Alg=%d, Act Alg=%d, Length=%d" % (file, expHashAlg, actHashAlg, hashFileLength)) # Some functions, such as Wx's ListBox.ChangeValue() takes a string # But the data is stored as a list of strins # so form a single string containing everything in list def formStringFromListOfStrings(self, list): """formStringFromListOfStrings - return a single string formed from a list of strings""" string = '' index = 0 for eachString in list: if(index != 0): # if not the 1st entry, need a LF before the new entry string += "\n" string += eachString index += 1 #print("thisString=%s, string=%s" % (eachString, string)) return string def formFileName(self, base, ext): """formFileName - return name formed from base.ext""" seperator = '.' filenameList = [base, ext] return(seperator.join(filenameList)) # return True if file verified and key was extracted, else False def verifyKeyFile(self, file, type, currentList): """verifyKeyFile - verify the key file and extract the key""" # Need currentList.KeySize and currentList.PubKeyQx key = self.getKeyFromFile(file, type) expectedKeySize = int(currentList.KeySize) / 8 if type == DEFINES.KEY_FILE_TYPE['PUBLIC_ECDSA']: # ECC public key is two value of the key size match = len(key) == expectedKeySize *2 if match: # key is flipped for little endian so the latter half is the Qx currentList.PubKeyQx = key[expectedKeySize:expectedKeySize*2] currentList.PubKeyQy = key[0:expectedKeySize] elif type == DEFINES.KEY_FILE_TYPE['PUBLIC_RSASSA']: match = len(key) == expectedKeySize if match: currentList.PubKeyData = key else: keylength = len(key) match = len(key) == expectedKeySize if not match: print("Key size mismatch actual=%d expected=%d" %(len(key), expectedKeySize)) #if(type == KEY_FILE_TYPE_PRIVATE): # expectedHeader = "-----BEGIN RSA PRIVATE KEY-----" # expectedFooter = "-----END RSA PRIVATE KEY-----" # expectedType = "Private" #elif(type == KEY_FILE_TYPE_PUBLIC): # expectedHeader = "-----BEGIN PUBLIC KEY-----" # expectedFooter = "-----END PUBLIC KEY-----" # expectedType = "Public" #else: # print("invalid key file parameter = %d specified" % (type)) # DBGDBG # return False # #expHdrLen = len(expectedHeader) #try: # f = open(file, "rb") # actualHeader = f.read(expHdrLen) #except: # self.StatusBar.SetStatusText("Error opening key file %s" % (file)) # # open failed, can't close # return False # #if(actualHeader == expectedHeader): # self.StatusBar.SetStatusText("") # clear any previous error msgs #else: # self.StatusBar.SetStatusText("File %s is not a %s key file. Expected header %s" % (file, expectedType, expectedHeader)) # f.close() # return False # ## key file header is OK ## read the rest of the file, including line endings ## then strip out the line endings and the footer ## Expect Unix style line emdings: 0x0A" per openssl .pem format ## but also handle Windows style line endings: 0x0D, 0x0A ## max file length for keySize=3072 is <3072 since could have different ## number of characters on each line and different len endings (0A or 0D0A) ## just don't want to read in a [potentially very large] user specified file size #maxLength = 3072 #f.seek (0, os.SEEK_END) #actualFileSize = f.tell() - expHdrLen - 1 # size of the rest of the file #if(actualFileSize < maxLength): # maxLength = actualFileSize # ## read the base64 encoded data from the key file into a binary string #f.seek (expHdrLen+1, os.SEEK_SET) # back to just after the header #try: # rawData = f.read(maxLength) #except: # self.StatusBar.SetStatusText("Error reading key data from file %s" % (file)) # f.close() # return False # ##print("verifyKeyFile: read %d bytes:\n%s" % (len(rawData), rawData)) # DBGDBG ##print("verifyKeyFile: read %d" % (len(rawData))) # DBGDBG ## Verify the footer #if expectedFooter in rawData: # self.StatusBar.SetStatusText("") # clear any previous error msgs #else: # self.StatusBar.SetStatusText("File %s is not a %s key file. Expected footer %s" % # (file, expectedType, expectedFooter)) # f.close() # return False # ## strip off the footer #footerPos = rawData.find('-') # find 1st '-' #rawData = rawData[0:footerPos-1] ##print("verifyKeyFile: w/o footer %d bytes:\n%s" % (len(rawData), rawData)) # DBGDBG ##print("verifyKeyFile: w/o footer %d bytes" % (len(rawData))) # DBGDBG # ## Verify that the file matches the current KeySize ## ## Key File sizes: 1024 2048 3072 for key + footer incl. LR/CR ## public file range: 240-260 420-440 590-610 ## private file range: 850-870 1640-1685 2390-2430 ## #keySize = self.keySizeEdit.GetValue() ##print("verifyKeyFile: keySize = %s, type = %s, .pem's length = %d" % (keySize, expectedType, maxLength)) # DBGDBG #currentList = self.pdef.getCurrentListObject() #misMatch = False #if(expectedType == "Public"): # if(keySize == "1024"): # if not ((240 <= maxLength) and (maxLength <= 260)): # print("verifyKeyFile: Public key file, size not 1024!") # DBGDBG # misMatch = True # elif(keySize == "2048"): # if not ((420 <= maxLength) and (maxLength <= 440)): # print("verifyKeyFile: Public key file, size not 2048!") # DBGDBG # misMatch = True # elif(keySize == "3072"): # if not ((590 <= maxLength) and (maxLength <= 610)): # print("verifyKeyFile: Public key file, size not 3072!") # DBGDBG # misMatch = True # if(misMatch == True): # self.StatusBar.SetStatusText("Key size mismatch. File %s is not %s." % (file, keySize)) # self.pubKeyFileEdit.SetValue("") # f.close() # return False # else: # keyData = self.decodePublicKeyModulus(file, keySize, expectedHeader, expectedFooter) # currentList.PubKeyData = keyData # save the public key modulus # #print("verifyKeyFile: Public Key. Length: %d. Data:\n%s" % (len(keyData), currentList.PubKeyData)) # DBGDBG # #elif(expectedType == "Private"): # if(keySize == "1024"): # if not ((850 <= maxLength) and (maxLength <= 870)): # print("verifyKeyFile: Private key file, size not 1024!") # DBGDBG # misMatch = True # elif(keySize == "2048"): # if not ((1640 <= maxLength) and (maxLength <= 1685)): # print("verifyKeyFile: Private key file, size not 20481") # DBGDBG # misMatch = True # elif(keySize == "3072"): # if not ((2390 <= maxLength) and (maxLength <= 2430)): # print("verifyKeyFile: Private key file, size not 3072!") # DBGDBG # misMatch = True # if(misMatch == True): # self.StatusBar.SetStatusText("Key size mismatch. File %s is not %s." % (file, keySize)) # self.pvtKeyFileEdit.SetValue("") # f.close() # return False # # Note: Don't need to save the private key data, pycrypto reads it from the file directly # #f.close() return match # Verify that the file is a valid HASH_FILE with a HASH_TAG, hashAlg and hashSize # [with 1 or more SHA1 hashes] - legacy support from the TPM1.2 LCP1 Spec # or a raw data file [i.e. no header] with ONLY 1 20 bit SHA1 or 32 bit SHA256 hash # # if OK, return a list containing: [True, HashFileModeXXX] defined in defines.py # else return a list containing: [False, HashFileModeNull] # if file format or length is invalid # or if the length indicates the hash does not correspond to the elements.HashAlg # #TODO: Bill: verifyHashFile- LCP2 spec deletes the HASH_FILE struct def for files with multiple hashes?? #TODO: Bill: verifyHashFile- still supporting files with multiple SHA1 hashes [with the hdr] or raw SHA1 or 256 files # def verifyHashFile(self, file, hashAlg): """verifyHashFile - return a list indicating if the file is valid and its type""" # HASH_FILE's are structured as: # - SHA1 or SHA256 hash data only, for raw SHA1 or SHA256 files with 1 hash # - SHA1 hash files with a header [defined below] containing 1 or more SHA1 hashes # # Where the header is: # HASH_TAG = 0x48534148 = "HASH" # typedef struct { # UINT32 tag HASH_TAG; # 4 bytes "HASH" # UINT8 hashAlg ; # 1 byte SHA1_ALG = 4 # UINT8 hashSize ; # 1 byte SHA1 = 20 # UINT8 reserve[10] ; # 12 bytes # SHA1 - SHA256 hash ; # 20 bytes # } HASH_FILE; # ________ # File Size # 36 bytes # read the 1st 4 bytes from the file (i.e. the actualTag) and compare that to the expectedTag # function = "verifyHashFile" mode = DEFINES.HashFileMode['RawSHA256'] # default hashFileLengthHdrSha1 = 36 # header + SHA1 hash data hashFileLengthRawSha1 = DEFINES.DIGEST_SIZE['SHA1'] # raw hash files have only the hash data, no header hashFileLengthRawSha256 = DEFINES.DIGEST_SIZE['SHA256'] #hashFileLengthRawSha384 = 48 #hashFileLengthRawSha512 = 64 try: f = open(file, "rb") except: print("Error opening hash file %s" % (file)) return [False, DEFINES.HashFileMode['HdrNull']] try: hashAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() if hashAlgStr == 'SHA1_LEGACY': hashAlgStr = 'SHA1' except StopIteration: print("Unsupported hash algorithm (%d)" %(hashAlg)) return [False, DEFINES.HashFileMode['HdrNull']] # # check the file size to determine the type of file being read # f.seek (0, os.SEEK_END) actualSize = f.tell() if(actualSize == hashFileLengthHdrSha1): mode = DEFINES.HashFileMode['HdrSHA1'] hashFileLength = hashFileLengthHdrSha1 # read the data # f.seek (0, os.SEEK_SET) # back to the begininng data = array.array ("B") # Load file into data array try: data.fromfile (f, hashFileLength) except: print ("Error reading hash from file %s" % (file)) f.close() return [False, DEFINES.HashFileMode['HdrNull']] if(hashAlg != DEFINES.TPM_ALG_HASH['SHA1'] and hashAlg != DEFINES.TPM_ALG_HASH['SHA1_LEGACY']): self.invalidHashFileMsg(file, hashAlg, DEFINES.TPM_ALG_HASH['SHA1'], hashFileLength) return [False, DEFINES.HashFileMode['HdrNull']] expectedHashTag = "HASH" # 0x48415348 expectedSha1HashAlg = 4 # '\x04' expectedSha1HashSize = 20 # '\x14' actualHashTag = data[0:4].tostring() # 0:3 inclusive = 0:4 exclusive of 4 actualHashAlg = data[4] actualHashSize = data[5] if(actualHashTag != expectedHashTag): # check if a raw file matching the element's HashAlg length print ("File: %s invalid tag = %s, expected %s" % (file, actualHashTag, expectedHashTag)) return [False, DEFINES.HashFileMode['HdrNull']] if(actualHashAlg != expectedSha1HashAlg): print ("File: %s invalid hashAlg = 0x%x, expected 0x%x" % (file, actualHashAlg, expectedSha1HashAlg)) return [False, DEFINES.HashFileMode['HdrNull']] if(actualHashSize != expectedSha1HashSize): print ("File: %s invalid hashSize = 0x%x, expected 0x%x" % (file, actualHashSize, expectedSha1HashSize)) return [False, DEFINES.HashFileMode['HdrNull']] elif actualSize == DEFINES.DIGEST_SIZE[hashAlgStr]: modeStr = 'Raw' + hashAlgStr mode = DEFINES.HashFileMode[modeStr] hashFileLength = DEFINES.DIGEST_SIZE[hashAlgStr] else: self.invalidHashFileMsg(file, hashAlg, DEFINES.TPM_ALG_HASH[hashAlgStr], actualSize) print ("File: %s invalid size = %d, expected %d" % (file, actualSize, DEFINES.DIGEST_SIZE[hashAlgStr])) return [False, DEFINES.HashFileMode['HdrNull']] print("verifyHashFile - HashAlg=%d, Mode=%d, Len=%d" % (hashAlg, mode, hashFileLength)) # DBGDBG f.close() # handle SHA1 files with headers #if(mode == DEFINES.HashFileMode['HdrSHA1']): # #else: # print("verifyHashFile - Error: invalid mode = %d, aborting." % (mode)) # return [False, DEFINES.HashFileMode['HdrNull']] return [True, mode] # Determine the type of and validate the pcrFile, except for the numHashes field # This includes checking that the file's type and hashAlg matches the element's expected HashAlg # Return [True, PcrFileModePcrXShaYYY if ok, see defines.py # [False, PcrFileModeNull] othewise # def verifyPcrFile(self, file, elementExpAlg): """verifyPcrFile - Validate the pcrFile""" # 2 types of PCR dump files are supported: PCRD and PCR2 # PCR Dump File format # typedef struct { # UINT32 tag PCRD_TAG; # 4 bytes "PCRD" = 0x44524350 # UINT8 hashAlg ; # 1 byte SHA1_ALG = 4 SHA256_ALG = 0x0b # UINT8 hashSize ; # 1 byte SHA1 = 20 SHA256 = 32 # UINT8 numHashes ; # 1 byte number of hashes in the file # UINT8 reserve[9] ; # 9 bytes # SHA1 pcrs[24] ; # 20 bytes * numHashes # } HASH_FILE; # ________ # File Size # 16 + (NumHashes * HashSize) bytes # Typically all 24 PCRs included so size for SHA1 = 16 + 24*20 = 496 = 0x1f0 # LCP tool only requires the 1st 8 PCRs, if they are selected via pcr0to7SelectionBitMask # I.e. if the bit mask 0-7 = 1 then that PCR is required # # - PCR2 PCR dump File format - from App. C.1.2 # typedef struct { # UINT32 tag PCR2_TAG; # 4 bytes "PCR2" = 0x32524350 # UINT16 hashAlg ; # 2 bytes TPM_ALG_SHAXXXXX # UINT8 count ; # 1 byte number of valid digests # UINT8 reserve ; # 1 byte # UINT16 size ; # 2 bytes size of hash # union { # HASH20 pcrs[24] ; # 20 bytes * 24 of which count are used per the pcrSelection mash # HASH32 pcrs[24] ; # 32 bytes * 24 of which count are used per the pcrSelection mash # } HASH_FILE; # ________ # File Size # 8 + (count * HashSize) bytes, assuming no holes in the mask function = "verifyPcrFile" expectedPcrdTag = "PCRD" # 0x44524350 expectedPcr2Tag = "PCR2" # 0x32524350 try: f = open(file, "rb") except: print ("Error opening PCR data file %s" % (file)) return [False, DEFINES.PcrFileMode['Null']] # Determine if this is a PCRD or PCR2 file # Based on the type, ensure the file's HaskAlg matches the element's ExpAlg f.seek (0, os.SEEK_SET) # back to the begininng data = array.array ("B") # Load file into data array try: data.fromfile (f, DEFINES.PCRFileMinHdrSize) except: print ("Error reading PCR data from file %s" % (file)) f.close() return [False, DEFINES.PcrFileMode['Null']] try: elementExpAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if val == elementExpAlg).next() except StopIteration: print ("Unsupported hash algorithm %d" %(elementExpAlg)) fileHashTag = data[0:4].tostring() # 0:3 inclusive = 0:4 exclusive of 4 numHashes = data[6] # PCRD 'numHashes' same as PCR2 'count' fileType = DEFINES.PcrFileMode['Null'] if(fileHashTag == expectedPcrdTag): # PCRD file fileType = DEFINES.PcrFileMode['PcrdSHA1'] fileActualHashAlg = data[4] # HashAlg is a UINT8 if(elementExpAlg != DEFINES.TPM_ALG_HASH['SHA1']): print ("%s file %s SHA1 hash algorithm does not match the PCONF element's expected algorithm: 0x%x" % (expectedPcrdTag, file, elementExpAlg)) return [False, DEFINES.PcrFileMode['Pcrd']] else: actAlg = DEFINES.TPM_ALG_HASH['SHA1'] # LCP2 PCRD format only supports SHA1 per C.1.1 minFileLength = DEFINES.PCRDFileHdrSize + (8*DEFINES.DIGEST_SIZE['SHA1']) # min PCRD SHA1 file has 8 hash's elif(fileHashTag == expectedPcr2Tag): # PCR2 file # HashAlg in [4:5] is little endian so for current algs high byte=data[5]=0 and low byte=hashAlg fileActualHashAlg = unpack('= %d" % (file, actualFileSize, minFileLength)) f.close() return [False, DEFINES.PcrFileMode['Null']] # file looks ok, except for the numHashes field which is checked by build.hashPcrInfoFromFile() when it reads the data # can't check that yet since don't know which PCRs will be selected f.close() return [True, fileType] # Verify that the pcr file contains the expected number of pcr hashes # Return True if ok or if no PCR's are selected, else return False # # file - is the specified pcr file # fileType - indicates the type of PCR data file per the PcrFileModeXXXXX defines # pcr0to7SelectionBitMask - is a mask indicating the selected PCRs # def verifyPcrInfoNumHashes(self, file, fileType, hashAlg, pcr0to7SelectionBitMask): """verifyPcrInfoNumHashes - verify the pcr file contains enough hashes""" function = "verifyPcrInfoNumHashes" # check for case when no PCR's were selected # nothing to hash in that case if(pcr0to7SelectionBitMask == 0): print("Warning: No PCR was selected. Nothing to hash: pcr0to7SelectionBitMask=0") print ("Note: No PCR was selected. If desired, select PCR's and click 'Apply PCR Selection'") return True try: hashAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if val == hashAlg).next() except StopIteration: print("verifyPcrInfoNumHashes - invalid fileType=%x hash alg!!!" % (file, fileType, hashAlg)) # Should NEVER get here if(fileType == DEFINES.PcrFileMode['Pcrd']): minFileLength = DEFINES.PCRDFileHdrSize + (8*DEFINES.DIGEST_SIZE['SHA1']) # min PCRD SHA1 file has 8 hash's elif(fileType == DEFINES.PcrFileMode['Pcr2']): minFileLength = DEFINES.PCR2FileHdrSize + (8*DEFINES.DIGEST_SIZE[hashAlgStr]) # min PCR2 SHA1 file has 8 hash's else: print("verifyPcrInfoNumHashes - invalid fileType=%x!!!" % (file, fileType)) # Should NEVER get here print("verifyPcrInfoNumHashes %s, type %d, pcr0to7SelectionBitMask=0x%x" % (file, fileType, pcr0to7SelectionBitMask)) # DBGDBG try: f = open(file, "rb") except: print ("Error opening PCR data file %s" % (file)) return False f.seek (0, os.SEEK_END) actualFileSize = f.tell () f.seek (0, os.SEEK_SET) # back to the begininng data = array.array ("B") # Load file into data array try: data.fromfile (f, minFileLength) except: print ("Error reading PCR data from file %s" % (file)) f.close() return False f.close() numHashes = data[6] # same for both PCRD and PCR2 files # now that we have NumHashes, check the actual file size #print("verifyPcrInfoNumHashes - numHashes=%x" % (numHashes)) # DBGDBG if(numHashes == 0): print ("File: %s invalid numHashes = 0" % (file)) return False if(fileType == DEFINES.PcrFileMode['Pcrd']): expectedFileSize = DEFINES.PCRDFileHdrSize + (numHashes * DEFINES.DIGEST_SIZE['SHA1']) elif(fileType == DEFINES.PcrFileMode['Pcr2']): expectedFileSize = DEFINES.PCR2FileHdrSize + (numHashes * DEFINES.DIGEST_SIZE[hashAlgStr]) else: print("verifyPcrInfoNumHashes - invalid fileType=%d" % (fileType)) # DBGDBG Should NEVER get here return False if(actualFileSize < expectedFileSize): print ("File: %s invalid File size = 0x%x=%i, expected 0x%x" % (file, actualFileSize, actualFileSize, expectedFileSize)) return False # verify that numHashes >= the largest selected hash # must have at least that many hashes in the PCR dump file #print("verifyPcrInfoNumHashes - verify numHashes are in the file") # DBGDBG mask = 0x80 bit = 8 while(bit > 0): if(mask & pcr0to7SelectionBitMask): break # found the largest selected PCR else: bit -= 1 mask >>= 1 if(bit > numHashes): # not enough hashes in the PCR dump file, abort print ("Too few hashes in PCR dump file: %s, numHashes = 0x%x, but max selected hash = 0x%x" % (file, numHashes, bit)) return False return True # Get hash data from the specified file and return it using global _GlobalHashData # Note: no file format checking is done here as files were validated when added to the list # Return False if the hash couldn't be extracted, else return True # def getHashFromFile(self, file, hashAlg): """getHashFromFile - validate the hash file and extract the hash data""" global _GlobalHashData print("getHashFromFile - file %s, HashAlg=%d" % (file, hashAlg)) # DBGDBG result = self.verifyHashFile(file, hashAlg) # verifyHashFile() returns a list with [status, fileType] fileType = result[1] if(result[0] == False): return [] # should have detected this when file was selected fileType = result[1] data = array.array ("B") # Load file into data array try: hashAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() except StopIteration: print("Unsupported hash algorithm (%d)" %(hashAlg)) if(fileType == DEFINES.HashFileMode['HdrNull']): print("getHashFromFile - Error: invalid mode = %d, aborting." % (result[1])) return [] elif(fileType == DEFINES.HashFileMode['HdrSHA1']): hashFileLength = 36 elif(fileType in DEFINES.HashFileMode.values()): # All other raw modes hashFileLength = DEFINES.DIGEST_SIZE[hashAlgStr] else: print("getHashFromFile - Error: invalid mode = %d, aborting." % (result[1])) return [] try: f = open(file, "rb") f.seek (0, os.SEEK_SET) # beginning of file data.fromfile (f, hashFileLength) except: print("getHashFromFile - Error reading hash from file %s" % (file)) f.close() return [] f.close() #print("getHashFromFile - data = %s, len=%d" % (data, len(data))) # DBGDBG # handle all the flavors of hash files if(fileType == DEFINES.HashFileMode['HdrSHA1']): _GlobalHashData = data[16:36].tolist() # 20 bytes 16:36 exclusive print("getHashFromFile: %s, Hdr tag=%s alg=%i, size=%i, hash=%s, len=%d" % (file, data[0:4].tostring(), data[4], data[5], _GlobalHashData, len(_GlobalHashData))) # DBGDBG else: _GlobalHashData = data.tolist() assert len(data) == DEFINES.DIGEST_SIZE[hashAlgStr], "Error: File size (%d bytes) mismatch with %s size (%d bytes)" %(len(data), hashAlgStr, DEFINES.DIGEST_SIZE[hashAlgStr]) print("getHashFromFile: %s, raw %s hash=%s, len=%d" % (file, hashAlgStr, _GlobalHashData, len(_GlobalHashData))) # DBGDBG return _GlobalHashData; # Get the specified PCR data (indicated by the thisPcr mask) # Return False if couldn't read the hashes from the PCR file # othewise return True # # file - is the specified pcr file # fileType - indicates the type of PCR data file per the PcrFileModeXXXXX defines # thisPcr - the specified PCR data to find [0 < thisPcr < 8] # hashSize - is the size of the pcr data to extract # def getPcrInfoFromFile(self, file, fileType, thisPcr, hashSize, statusBar): """getPcrInfoFromFile - get the pcr data from the specified file""" global _GlobalPcrHash if(fileType == DEFINES.PcrFileMode['Pcrd']): hdrSize = DEFINES.PCRDFileHdrSize elif(fileType == DEFINES.PcrFileMode['Pcr2']): hdrSize = DEFINES.PCR2FileHdrSize else: print("verifyPcrInfoNumHashes - invalid fileType=%d" % (fileType)) # DBGDBG Should NEVER get here return False #print("getPcrInfoFromFile %s type %d, pcr %d, hashSize=%d" % (file, fileType, thisPcr, hashSize)) # DBGDBG pcrData = array.array ("B") try: f = open(file, "rb") except: print("getPcrInfoFromFile: open of file %s failed" % (file)) # should never get here, file's been opened for verif. earlier return False # read TPM1 or TPM2 PCR tag to determine the file format to use? tag = f.read(4) # read the selected pcr's hash data if tag == 'PCR2': # PCR2 file format pos = hdrSize + (thisPcr * (hashSize + 2)) # There's a 2 byte size field precedes each PCR value. f.seek (pos, os.SEEK_SET) # Read the size of the PCR value and compare to the expected hash size size = f.read(2) pcrSize = unpack("= the largest selected hash # must have at least that many hashes in the PCR dump file mask = 0x80 bit = 8 while(bit > 0): if(mask & pcr0to7SelectionBitMask): break # found the largest selected PCR else: bit -= 1 mask >>= 1 if(bit > numHashes): # not enough hashes in the PCR dump file, abort print ("Too few hashes in PCR dump file: %s, numHashes = 0x%x, but max selected hash = 0x%x" % (file, numHashes, bit)) return False # file looks ok, get the data temp = array.array ("B") # temp array hashLength = expectedPcrHashSize numSelectedPcrs = 0 mask = 0x01 bit = 0 pos = 0 while(bit < 8): if(mask & pcr0to7SelectionBitMask): if tag == 'PCR2': pos = pcrStartPos + 2 + bit * (2 + hashLength) elif tag == 'PCRD': pos = pcrStartPos + bit * hashLength temp += data[pos:pos+hashLength] numSelectedPcrs += 1 print("hashPcrInfoFromFile - Read hash %d, mask 0x%x from file %s, select=0x%x, numSelectedPcrs=%d, len(temp)=%d" % (bit, mask, file, pcr0to7SelectionBitMask, numSelectedPcrs, len(temp))) # DBGDBG mask <<= 1 bit += 1 pos += hashLength #print("hashPcrInfoFromFile TypeOf: tempList=%s, tempList[0]=%s, _GlobalPcrHash=%s, _GlobalPcrHash[0]=%s" % # (type(tempList), type(tempList[0]), type(_GlobalPcrHash), type(_GlobalPcrHash[0]))) # DBGDBG #pcrHash = hashlib.sha1() hashAlg = header[4] # TODO: is hashAlg determined by GUI or from PCR file. hashAlgStr = None try: hashAlgStr = (key for key,val in DEFINES.TPM_ALG_HASH.items() if hashAlg == val).next() except StopIteration: print ("Error unsupported hash algorithm (%d)" %(hashAlg)) # Set hash algorithm pcrHash = None if 'SM3' in hashAlgStr: pcrHash = sm3() else: pcrHash = M2Crypto.EVP.MessageDigest(hashAlgStr.lower()) if tag == 'PCR2': pcrHash.update(temp) elif tag == 'PCRD': #pcrHash = hashlib.sha1() pcrHash = M2Crypto.EVP.MessageDigest('sha1') # The PCR composite hash consists of: TPM_PCR_COMPOSITE structure # UINT16 sizeOfSelect # BigEndian = 00 03 # UINT8 pcr_select[3] # UINT32 valueSize # BigEndian = 20 * NumberOfSelectedHashes # UINT8 pcrValue[] # all the selected PCR hashes data = pack("L", valueSize) # Note '>' for BigEndian packing of valueSize pcrHash.update(data) # pack pcrValue[] pcrHash.update(temp) # hash.digest() Returns the digest of the strings passed to the update() method so far. # This is a string of digest_size bytes [which may contain non-ASCII characters, including null bytes] # Note: cannot pass this string thru struct.pack() which takes ints _GlobalPcrHash = pcrHash.digest() #print("hashPcrInfoFromFile: %s, Generated hash: Length=%d HexData=%s " % # (file, hashLength, pcrHash.hexdigest())) # DBGDBG return _GlobalPcrHash def getKeyFromFile(self, file, type): # Read the key file from the with open(file, 'rb') as kf: mb = M2Crypto.BIO.MemoryBuffer(kf.read()) kf.close() pem = mb.getvalue() pem_lines = pem.split('\n') key = None # Find line index of BEGIN and END header/footer der = '' foundbegin = False for line in pem_lines: if ('END' in line) and ('PUBLIC' in line or 'PRIVATE' in line): break if foundbegin: der += line.strip() if ('BEGIN' in line) and ('PUBLIC' in line or 'PRIVATE' in line): foundbegin = True try: # in case ASN1 can't decode the ASN1 notation.. if type == DEFINES.KEY_FILE_TYPE['PRIVATE_RSASSA']: asn, substrate = der_decoder.decode(der.decode('base64'), asn1Spec=RSAPrivateKey()) rsapvt = asn.getComponentByName('privateExponent') # returns univ.Integer() octet = univ.OctetString(hexValue=format(int(rsapvt), '0x')) # convert to Octet key = octet.asOctets() elif type == DEFINES.KEY_FILE_TYPE['PUBLIC_RSASSA']: # This decodes DER encoded ASN1 public key asn, substrate = der_decoder.decode(der.decode('base64'), asn1Spec=SubjectPublicKeyInfo()) bits = asn.getComponentByName('subjectPublicKey') # second level decode for RSAPublicKey() bits_string = ''.join(map(str, bits)) octet = univ.OctetString(binValue=bits_string) rsaasn, substrate = der_decoder.decode(octet.asOctets(), asn1Spec=RSAPublicKey()) rsapub = rsaasn.getComponentByName('modulus') # returns univ.Integer() octet = univ.OctetString(hexValue=format(int(rsapub), '0x')) # convert to Octet key = octet.asOctets() elif type == DEFINES.KEY_FILE_TYPE['PRIVATE_ECDSA']: asn, substrate = der_decoder.decode(der.decode('base64'), asn1Spec=ECPrivateKey()) ecpvt = asn.getComponentByName('privateKey') # returns univ.OctetString() key = ecpvt.asOctets() elif type == DEFINES.KEY_FILE_TYPE['PUBLIC_ECDSA']: # This decodes DER encoded ASN1 public key asn, substrate = der_decoder.decode(der.decode('base64'), asn1Spec=SubjectPublicKeyInfo()) bits = asn.getComponentByName('subjectPublicKey') # returns univ.BitString() # DSAPublicKey is Integer() so no decoding is needed, but need to remove the prefix 0x04. bits_string = ''.join(map(str, bits[8:])) # the first byte specifies the compress alg? octet = univ.OctetString(binValue=bits_string) key = octet.asOctets() except Exception as ex: print ("Exception: unable to decode pem file") print (ex) if key != None: keyLE = key[::-1] # little endian else: keyLE = '' return keyLE # the last function in the file doesn't show up in the scope list in Understand for some reason! def stub(self): pass tboot-1.10.5/lcptools-v2/Makefile0000644000000000000000000000337114210363175014705 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # lcptools makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk LCP2_TARGETS := \ lcp2_mlehash \ lcp2_crtpol \ lcp2_crtpollist \ lcp2_crtpolelt \ lcp2 : $(LCP2_TARGETS) # # universal rules # build : $(LCP2_TARGETS) dist : install install : @set -e; for i in $(LCP2_TARGETS);\ do \ $(MAKE) DISTDIR=$(DISTDIR) INST_TARGET=$(DISTDIR)/usr/sbin/$$i do_install; \ done .PHONY: do_install do_install : $(INST_TARGET) $(INST_TARGET) : $(notdir $(INST_TARGET)) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $^ clean : rm -f *~ *.a *.so *.o *.rpm $(DEP_FILES) $(LCP2_TARGETS) mrproper : clean distclean : clean # # dependencies # LDFLAGS += -L. # LCP v2 POLELT_PLUGINS := custom_elt.o mle_elt_legacy.o pconf_legacy.o sbios_elt.o stm_elt.o pconf2_elt.o mle_elt.o LCP2_LIB := liblcp.a LIBS += -lcrypto -llcp -lz $(ROOTDIR)/safestringlib/libsafestring.a $(LCP2_LIB) : pol.o poldata.o pollist2.o pollist2_1.o polelt.o lcputils.o hash.o pollist1.o $(AR) rc $@ $^ lcp2_crtpolelt : crtpolelt.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ lcp2_crtpollist : crtpollist.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ lcp2_crtpol : crtpol.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ lcp2_mlehash : mlehash.o $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ # # implicit rules # HDRS := $(wildcard $(ROOTDIR)/include/*.h) $(wildcard $(CURDIR)/*.h) BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile %.o : %.c $(HDRS) $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.10.5/lcptools-v2/crtpol.c0000644000000000000000000007042114210363175014714 0ustar 00000000000000/* * crtpol.c: Intel(R) TXT policy (LCP_POLICY) creation tool * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define PRINT printf #include "../../include/config.h" #include "../../include/hash.h" #include "../../include/uuid.h" #include "../../include/lcp3.h" #include "polelt_plugin.h" #include "pol.h" #include "poldata.h" #include "lcputils.h" #include "pollist2.h" #include "pollist2_1.h" #include "pollist1.h" #define TOOL_VER_MAJOR 0x1 #define TOOL_VER_MINOR 0x1 static const char help[] = "Usage: lcp2_crtpol [OPTION]\n" "Create an Intel(R) TXT policy (and policy data file)\n\n" "--create\n" " --alg hash algorithm for the policy\n" " if polver < 3 - alg is always sha1\n" " --type type\n" " [--minver ] SINITMinVersion\n" " [--max_sinit_min] MaxSINITMinVersion\n" " [--rev [,ctrN] 8 revocation values (comma separated,\n" " no spaces)\n" " [--ctrl policy file\n" " [--data ] policy data file\n" " [FILE]... policy list files\n" " [--mask] \n" " Allowed policy hash algorithm(s)\n" " Can be used more than once\n" " [--auxalg] AUX allowed hash algorithm(s)\n" " Not applicable for current LCP_POLICY v. 3.2\n" " --sign \n" " LCP allowed signing algorithm(s)\n" " Can be used more than once\n" " [--polver] LCP version:\n" " TPM1.2: 2.0, 2.1, 2.2, 2.3, 2.4 \n" " TPM2.0: 3.0, 3.1, 3.2>\n" " If not set policy ver will be 3.0\n" "--show\n" " [--brief] brief format output\n" " [policy file] policy file\n" " [policy data file] policy data file\n" "--help\n" "--verbose enable verbose output; can be\n" " specified with any command\n" "--version show tool version.\n\n"; bool verbose = false; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"version", no_argument, NULL, 'V'}, {"create", no_argument, NULL, 'C'}, {"show", no_argument, NULL, 'S'}, /* options */ {"alg", required_argument, NULL, 'a'}, {"type", required_argument, NULL, 't'}, {"minver", required_argument, NULL, 'm'}, {"max_sinit_min", required_argument, NULL, 'n'}, {"rev", required_argument, NULL, 'r'}, {"ctrl", required_argument, NULL, 'c'}, {"pol", required_argument, NULL, 'p'}, {"data", required_argument, NULL, 'd'}, {"brief", no_argument, NULL, 'b'}, {"mask", required_argument, NULL, 'k'}, {"auxalg", required_argument, NULL, 'x'}, {"sign", required_argument, NULL, 's'}, {"polver", required_argument, NULL, 'e'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; uint16_t pol_ver = LCP_DEFAULT_POLICY_VERSION; char policy_file[MAX_PATH] = ""; char poldata_file[MAX_PATH] = ""; char lcp_alg_name[32] = ""; char aux_alg_name[32] = ""; char sign_alg_name[32] = ""; char pol_ver_name[32] = ""; char lcp_hash_mask_name[32] = ""; uint16_t lcp_hash_alg = TPM_ALG_NULL; uint16_t aux_hash_alg = TPM_ALG_MASK_NULL; uint16_t lcp_hash_mask = TPM_ALG_MASK_NULL; char type[32] = ""; uint8_t sinit_min_ver = 0; unsigned int nr_rev_ctrs = 0; uint16_t rev_ctrs[LCP_MAX_LISTS] = { 0 }; uint32_t policy_ctrl = LCP_DEFAULT_POLICY_CONTROL; uint32_t lcp_sign_alg_mask = SIGN_ALG_MASK_NULL; bool brief = false; unsigned int nr_files = 0; char files[LCP_MAX_LISTS][MAX_PATH]; size_t list_21_sizes[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t pol_type = LCP_POLTYPE_ANY; uint8_t max_sinit_min_version = 0xFF; uint8_t max_biosac_min_version = 0; //Prototypes: static int create_legacy(void); static lcp_policy_data_t2 *create_poldata(void); static int create(void); static int show(void); int create_legacy(void) /*Attempt to create legacy policy for TPM 1.2*/ { lcp_policy_data_t2 *poldata = NULL; lcp_policy_t *pol = NULL; size_t policy_size = offsetof(lcp_policy_t, policy_hash) + SHA1_DIGEST_SIZE; //54 bytes LOG("[create_legacy]\n"); pol = malloc(policy_size); if (pol == NULL) { ERROR("Error: failed to allocate policy.\n"); } memset_s(pol, policy_size, 0x00); pol->version = pol_ver; pol->hash_alg = LCP_POLHALG_SHA1; //Legacy value for TPM 1.2 pol->policy_type = pol_type; pol->sinit_min_version = sinit_min_ver; for ( unsigned int i = 0; i < nr_rev_ctrs; i++ ) pol->data_revocation_counters[i] = rev_ctrs[i]; pol->policy_control = policy_ctrl; pol->max_sinit_min_version = max_sinit_min_version; if (pol->policy_type == LCP_POLTYPE_LIST) { poldata = create_poldata(); if (poldata == NULL) { ERROR("Error: failed to create policy data.\n"); free(pol); return 1; } calc_policy_data_hash(poldata, (lcp_hash_t2 *) &pol->policy_hash, pol->hash_alg); } bool ok; ok = write_file(policy_file, pol, policy_size); if ( ok && pol->policy_type == LCP_POLTYPE_LIST ) ok = write_file(poldata_file, poldata, get_policy_data_size(poldata)); free(pol); if (poldata != NULL) free(poldata); return ok ? 0 : 1; } lcp_policy_data_t2 *create_poldata(void) { lcp_policy_data_t2 *poldata = NULL; lcp_policy_list_t2_1 *pollist21 = NULL; void *file_data = NULL; lcp_list_t *pollist = NULL; bool no_sigblock_ok = false; size_t file_len; uint16_t version; uint16_t use_only_version; //Sets the version of list to use size_t list_size; poldata = malloc(sizeof(*poldata)); if ( poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); return NULL; } memset_s(poldata, sizeof(*poldata), 0); strlcpy(poldata->file_signature, LCP_POLICY_DATA_FILE_SIGNATURE, sizeof(poldata->file_signature)); poldata->num_lists = 0; for ( unsigned int i = 0; i < nr_files; i++ ) { file_data = read_file(files[i], &file_len, false); if ( file_data == NULL ) { free(poldata); return NULL; } memcpy_s((void*)&version, sizeof(uint16_t), file_data, sizeof(uint16_t)); if (i == 0) { use_only_version = version; //Read version of first list } free(file_data); if ( use_only_version != version ) { //If version differs, that's error ERROR("ERROR: Mixing list versions is not supported.\n"); free(poldata); return NULL; } if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION) ) { pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(poldata); return NULL; } poldata = add_tpm12_policy_list(poldata, (lcp_policy_list_t *)pollist); free(pollist); pollist = NULL; } else if( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) ) { pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(poldata); return NULL; } poldata = add_tpm20_policy_list(poldata, (lcp_policy_list_t2 *)pollist); free(pollist); pollist = NULL; } else if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { bool result; pollist21 = read_policy_list_2_1_file(false, files[i]); if (pollist21 == NULL) { free(poldata); return NULL; } if (pollist21->KeySignatureOffset != 0) { //list is signed result = verify_tpm20_pollist_2_1_sig(pollist21); if (!result) { free(poldata); return NULL; } } poldata = add_tpm20_policy_list2_1(poldata, &list_size, pollist21); if (poldata == NULL) { free(pollist21); return NULL; } list_21_sizes[i] = list_size; free(pollist21); pollist21 = NULL; } if ( poldata == NULL ) { return NULL; } } return poldata; } int create(void) { lcp_policy_data_t2 *poldata = NULL; lcp_policy_t2 *pol = malloc(sizeof(*pol)); if ( pol == NULL ) { ERROR("Error: failed to allocate policy\n"); return 1; } memset_s(pol, sizeof(*pol), 0); pol->version = pol_ver; pol->hash_alg = lcp_hash_alg; pol->sinit_min_version = sinit_min_ver; for ( unsigned int i = 0; i < nr_rev_ctrs; i++ ) { pol->data_revocation_counters[i] = rev_ctrs[i]; } pol->max_sinit_min_ver = max_sinit_min_version; pol->policy_control = policy_ctrl; if (aux_hash_alg == TPM_ALG_MASK_NULL && pol->version == LCP_VER_3_0) { pol->aux_hash_alg_mask = convert_hash_alg_to_mask(pol->hash_alg); } else { pol->aux_hash_alg_mask = aux_hash_alg; } if (lcp_hash_mask == TPM_ALG_MASK_NULL) { pol->lcp_hash_alg_mask = convert_hash_alg_to_mask(pol->hash_alg); } else{ pol->lcp_hash_alg_mask = lcp_hash_mask; } pol->lcp_sign_alg_mask = lcp_sign_alg_mask; if ( strcmp(type, "any") == 0 ) { pol->policy_type = LCP_POLTYPE_ANY; } else if ( strcmp(type, "list") == 0 ) { pol->policy_type = LCP_POLTYPE_LIST; poldata = create_poldata(); if (poldata == NULL) { poldata = malloc(sizeof(*poldata)); if ( poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pol); return 1; } memset_s(poldata, sizeof(*poldata), 0); strlcpy(poldata->file_signature, LCP_POLICY_DATA_FILE_SIGNATURE, sizeof(poldata->file_signature)); poldata->num_lists = 0; for ( unsigned int i = 0; i < nr_files; i++ ) { bool no_sigblock_ok = false; size_t file_len; uint16_t version; uint16_t use_only_version; //Sets the version of list to use lcp_list_t *pollist = NULL; void *file_data = read_file(files[i], &file_len, false); if ( file_data == NULL ) { free(pol); free(poldata); return 1; } memcpy_s((void*)&version, sizeof(uint16_t), file_data, sizeof(uint16_t)); if (i == 0) { use_only_version = version; //Read version of first list } free(file_data); if ( use_only_version != version ) { //If version differs, that's error ERROR("ERROR: Mixing list versions is not supported.\n"); free(pol); free(poldata); return 1; } if ( MAJOR_VER(version) == 1 ) { pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(pol); free(poldata); return 1; } poldata = add_tpm12_policy_list(poldata, (lcp_policy_list_t *)pollist); free(pollist); pollist = NULL; } else if( MAJOR_VER(version) == 2 ) { pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(pol); free(poldata); return 1; } poldata = add_tpm20_policy_list(poldata, (lcp_policy_list_t2 *)pollist); free(pollist); pollist = NULL; } else if ( MAJOR_VER(version) == 3 ) { bool result; lcp_policy_list_t2_1 *pollist21 = read_policy_list_2_1_file(false, files[i]); if (pollist21 == NULL) { free(pol); free(poldata); return 1; } if (pollist21->KeySignatureOffset != 0) { //list is signed result = verify_tpm20_pollist_2_1_sig(pollist21); if (!result) { free(pol); free(poldata); return 1; } } size_t list_size; poldata = add_tpm20_policy_list2_1(poldata, &list_size ,pollist21); if (poldata == NULL) { free(pol); free(pollist21); return 1; } list_21_sizes[i] = list_size; free(pollist21); pollist21 = NULL; } if ( poldata == NULL ) { free(pol); return 1; } } } calc_policy_data_hash(poldata, &pol->policy_hash, pol->hash_alg); } else { ERROR("Error: unknown policy type\n"); free(pol); return 1; } LOG("pol alg=0x%x, mask=0x%x, aux_mask=0x%x, sign_mask=0x%x\n", pol->hash_alg, pol->lcp_hash_alg_mask, pol->aux_hash_alg_mask, pol->lcp_sign_alg_mask); bool ok; ok = write_file(policy_file, pol, get_policy_size(pol)); if ( ok && pol->policy_type == LCP_POLTYPE_LIST ) ok = write_file(poldata_file, poldata, get_policy_data_size(poldata)); free(pol); free(poldata); return ok ? 0 : 1; } int show(void) { size_t len, pol_len = 0, poldata_len = 0; void *data; const char *pol_file = "", *poldata_file = ""; lcp_policy_t2 *pol = NULL; lcp_policy_t *pol_legacy = NULL; lcp_policy_data_t2 *poldata = NULL; int err = 1; data = read_file(files[0], &len, false); if ( data == NULL ) return 1; /* * files may be in any order or only one, so assume that if the * first file is not for policy then it must be for policy data */ if ( verify_policy(data, len, true) ) { pol = data; pol_len = len; pol_file = files[0]; } else if (verify_legacy_policy(data, len)) { pol_legacy = data; pol_len = len; pol_file = files[0]; } else { poldata = (lcp_policy_data_t2 *)data; poldata_len = len; poldata_file = files[0]; } if ( nr_files == 2 ) { data = read_file(files[1], &len, false); if ( data == NULL ) goto done; if ( pol == NULL && pol_legacy == NULL ) { pol = data; pol_len = len; pol_file = files[1]; } else { poldata = data; poldata_len = len; poldata_file = files[1]; } } if ( pol != NULL ) { DISPLAY("policy file: %s\n", pol_file); if ( verify_policy(pol, pol_len, false) ) display_policy(" ", pol, brief); } else { DISPLAY("policy file: %s\n", pol_file); if ( verify_legacy_policy(pol_legacy, pol_len) ) display_legacy_policy(" ", pol_legacy); } if ( poldata != NULL ) { DISPLAY("\npolicy data file: %s\n", poldata_file); if ( !verify_policy_data(poldata, poldata_len) ) { goto done; } display_policy_data(" ", poldata, brief); if ( (pol && (pol->policy_type == LCP_POLTYPE_LIST)) || (pol_legacy && (pol_legacy->policy_type == LCP_POLTYPE_LIST)) ) { lcp_hash_t2 hash; int diff; if (pol != NULL) { calc_policy_data_hash(poldata, &hash, pol->hash_alg); if ( 0 == memcmp_s(&hash, sizeof(hash), &pol->policy_hash, get_lcp_hash_size(pol->hash_alg), &diff) && diff == 0 ) DISPLAY("\npolicy data hash matches policy hash\n"); else { ERROR("\nError: policy data hash does not match policy hash\n"); goto done; } } else { calc_policy_data_hash(poldata, &hash, pol_legacy->hash_alg); if ( 0 == memcmp_s(&hash, sizeof(hash), &pol_legacy->policy_hash, SHA1_DIGEST_SIZE, &diff) && diff == 0 ) DISPLAY("\npolicy data hash matches policy hash\n"); else { ERROR("\nError: policy data hash does not match policy hash\n"); goto done; } } } else goto done; } err = 0; done: if (pol) { free(pol); } if (pol_legacy) { free(pol_legacy); } if (poldata) { free(poldata); } return err; } int main (int argc, char *argv[]) { int cmd = 0; bool prev_cmd = false; int c; do { c = getopt_long_only(argc, argv, "", long_opts, NULL); /*LOG("getopt: %c %s\n", c, optarg);*/ switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* show */ case 'V': /* version */ if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 'a': strlcpy(lcp_alg_name, optarg, sizeof(lcp_alg_name)); lcp_hash_alg = str_to_hash_alg(lcp_alg_name); LOG("cmdline opt: alg: %s\n", lcp_alg_name); break; case 'p': /* policy file */ strlcpy(policy_file, optarg, sizeof(policy_file)); LOG("cmdline opt: pol: %s\n", policy_file); break; case 'd': /* policy data file */ strlcpy(poldata_file, optarg, sizeof(poldata_file)); LOG("cmdline opt: data: %s\n", poldata_file); break; case 't': /* type */ strlcpy(type, optarg, sizeof(type)); LOG("cmdline opt: type: %s\n", type); if ( strcmp(type, "any") == 0 ) { pol_type = LCP_POLTYPE_ANY; } else if ( strcmp(type, "list") == 0 ) { pol_type = LCP_POLTYPE_LIST; } else { ERROR("Error: unsupported policy type.\n"); return 1; } break; case 'r': /* revocation counters */ nr_rev_ctrs = ARRAY_SIZE(rev_ctrs); parse_comma_sep_ints(optarg, rev_ctrs, &nr_rev_ctrs); LOG("cmdline opt: rev: "); for ( unsigned int i = 0; i < nr_rev_ctrs; i++ ) LOG("%u, ", rev_ctrs[i]); LOG("\n"); break; case 'm': /* SINITMinVersion */ sinit_min_ver = strtoul(optarg, NULL, 0); LOG("cmdline opt: minver: 0x%x (%u)\n", sinit_min_ver, sinit_min_ver); break; case 'n': /*MaxSINITMinVersion*/ max_sinit_min_version = strtoul(optarg, NULL, 0); LOG("cmdline opt: max_sinit_min: 0x%x (%u)\n", max_sinit_min_version, max_sinit_min_version); break; case 'c': /* PolicyControl */ policy_ctrl = strtoul(optarg, NULL, 0); LOG("cmdline opt: ctrl: 0x%x\n", policy_ctrl); break; case 'b': /* brief */ brief = true; LOG("cmdline opt: brief: %u\n", brief); break; case 'k': /* policy hash algorithm mask */ strlcpy(lcp_hash_mask_name, optarg, sizeof(lcp_hash_mask_name)); lcp_hash_mask |= str_to_lcp_hash_mask(lcp_hash_mask_name); LOG("cmdline opt: hash alg mask: %s\n", lcp_hash_mask_name); LOG("approved hash algorithm mask value: = 0x%04X\n", lcp_hash_mask); if ( lcp_hash_mask == TPM_ALG_MASK_NULL ) { ERROR("Error: LCP hash alg not supported\n"); return 1; } break; case 'x': /* AUX hash algorithm */ if ( pol_ver == 0x0302 ) { LOG("AUX hash alg not supported for LCP policy 3.x"); break; } strlcpy(aux_alg_name, optarg, sizeof(aux_alg_name)); LOG("cmdline opt: auxalg: %s\n", aux_alg_name); aux_hash_alg = str_to_lcp_hash_mask(aux_alg_name); if ( aux_hash_alg == TPM_ALG_MASK_NULL) { ERROR("Error: AUX hash alg not supported\n"); return 1; } break; case 's': /* LCP signing algorithm */ if (MAJOR_VER(pol_ver) == MAJOR_VER(LCP_VER_2_0)) break; //Option not supported for legacy policy else { strlcpy(sign_alg_name, optarg, sizeof(sign_alg_name)); LOG("cmdline opt: sign: %s\n", sign_alg_name); lcp_sign_alg_mask |= str_to_sig_alg_mask(sign_alg_name, pol_ver, sizeof(sign_alg_name)); LOG("approved signature alg mask value: 0x%04X\n", lcp_sign_alg_mask); if ( lcp_sign_alg_mask == SIGN_ALG_MASK_NULL) { ERROR("Error: signing alg not supported\n"); return 1; } break; } case 'e': /* LCP version */ strlcpy(pol_ver_name, optarg, sizeof(pol_ver_name)); LOG("cmdline opt: sign: %s\n", pol_ver_name); pol_ver = str_to_pol_ver(pol_ver_name); if ( pol_ver == LCP_VER_NULL) { ERROR("Error: Invalid policy version\n"); return 1; } break; case 0: case -1: break; default: ERROR("Error: unrecognized option\n"); return 1; } } while ( c != -1 ); /* process any remaining argv[] items */ while ( optind < argc && nr_files < ARRAY_SIZE(files) ) { LOG("cmdline opt: file: %s\n", argv[optind]); strlcpy(files[nr_files++], argv[optind], sizeof(files[0])); optind++; } if ( cmd == 0 ) { ERROR("Error: no command option was specified\n"); return 1; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); return 0; } else if ( cmd == 'C' ) { /* --create */ uint16_t lcp_major_version = pol_ver & 0xFF00; if ( lcp_hash_alg == TPM_ALG_NULL && lcp_major_version == LCP_VER_3_0) { ERROR("Error: alg not supported or not specified.\n"); return 1; } LOG("pol_ver & 0xFF00 is 0x%x\n", lcp_major_version); if ( lcp_major_version == LCP_VER_2_0 ){ if ( lcp_sign_alg_mask != SIGN_ALG_MASK_NULL) { LOG("Info: Signature algorithm mask not defined for LCPv2, specified mask is ignored.\n"); } } else if ( lcp_sign_alg_mask == SIGN_ALG_MASK_NULL) { ERROR("Error: LCPv3 signing alg mask not supported or not specified\n"); return 1; } if ( *type == '\0' ) { ERROR("Error: no type specified\n"); return 1; } if ( strcmp(type, "list") != 0 && strcmp(type, "any") != 0 ) { ERROR("Error: unknown type\n"); return 1; } if ( *policy_file == '\0' ) { ERROR("Error: no policy file specified\n"); return 1; } if ( strcmp(type, "list") == 0 && *poldata_file == '\0' ) { ERROR("Error: list type but no policy data file specified\n"); return 1; } if ( strcmp(type, "list") == 0 && nr_files == 0 ) { ERROR("Error: list type but no policy lists specified\n"); return 1; } if (lcp_major_version == LCP_VER_3_0) { return create(); } else if (lcp_major_version == LCP_VER_2_0) { return create_legacy(); } else { ERROR("Error: policy must be version 3.x or 2.x\n"); return 1; } } else if ( cmd == 'S' ) { /* --show */ if ( nr_files == 0 ) { ERROR("Error: no policy or policy data file specified\n"); return 1; } if ( nr_files > 2 ) { ERROR("Error: too many files specified\n"); return 1; } return show(); } else if ( cmd == 'V' ) /* --version */ { DISPLAY("lcp2_crtpol version: %i.%i\nBuild date: %s", TOOL_VER_MAJOR, TOOL_VER_MINOR, __DATE__); return 0; } ERROR("Error: unknown command\n"); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/crtpolelt.c0000644000000000000000000002176414210363175015427 0ustar 00000000000000/* * crtpolelt.c: Intel(R) TXT policy element (LCP_POLICY_ELEMENT) creation tool * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "polelt.h" #include "lcputils.h" #define TOOL_VER_MAJOR 0x1 #define TOOL_VER_MINOR 0x1 #define MAX_HELP_TEXT 4096 static char help[MAX_HELP_TEXT] = "Usage: lcp2_crtpolelt [OPTION]\n" "Create an Intel(R) TXT policy element of specified type.\n\n" "--create\n" " --type type of element; must be first option;\n" " see below for type strings and their\n" " options\n" " --out output file name\n" " [--ctrl ] PolEltControl field (hex or decimal)\n" "--show\n" " policy element file name\n" "--help help\n" "--verbose enable verbose output; can be\n" " specified with any command\n" "--version show tool version.\n" "types :\n"; bool verbose = false; #define MAX_CMDLINE_OPTS 256 static struct option long_opts[MAX_CMDLINE_OPTS] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"version", no_argument, NULL, 'V'}, {"create", no_argument, NULL, 'C'}, {"show", no_argument, NULL, 'S'}, /* options */ {"type", required_argument, NULL, 't'}, {"out", required_argument, NULL, 'o'}, {"ctrl", required_argument, NULL, 'c'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; static void add_plugins(void) { /* we will add each plugin's opts to end, so find initial last one */ unsigned int nr_opts = 0; struct option *opt = long_opts; while ( opt->name != NULL ) { opt++; nr_opts++; } for ( unsigned int i = 0; i < nr_polelt_plugins; i++ ) { polelt_plugin_t *plugin = polelt_plugins[i]; LOG("supporting LCP element plugin type \'%s\'\n", plugin->type_string); /* copy options */ struct option *plugin_opt = plugin->cmdline_opts; while ( plugin_opt != NULL && plugin_opt->name != NULL && nr_opts < ARRAY_SIZE(long_opts) ) { *opt++ = *plugin_opt++; nr_opts++; } if ( nr_opts == ARRAY_SIZE(long_opts) ) ERROR("Error: too many plugin options\n"); /* copy help text */ strcat_s(help, MAX_HELP_TEXT, plugin->help_txt); } } int main (int argc, char *argv[]) { int cmd = 0; polelt_plugin_t *curr_plugin = NULL; bool prev_cmd = false; uint32_t pol_elt_ctrl = DEFAULT_POL_ELT_CONTROL; char out_file[MAX_PATH] = ""; int c; /* add each plugin's command line option strings and help text */ add_plugins(); do { c = getopt_long_only(argc, argv, "", long_opts, NULL); switch (c) { case 'H': /* help */ case 'C': /* create */ case 'S': /* show */ case 'V': /* version */ if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 't': /* type */ curr_plugin = find_polelt_plugin_by_type_string(optarg); if ( curr_plugin == NULL ) { ERROR("Error: unknown type \'%s\'\n", optarg); return 1; } LOG("cmdline opt: type: \'%s\'\n", curr_plugin->type_string); break; case 'o': /* out */ strlcpy(out_file, optarg, sizeof(out_file)); LOG("cmdline opt: out: %s\n", out_file); break; case 'c': /* ctrl */ pol_elt_ctrl = strtoul(optarg, NULL, 0); LOG("cmdline opt: ctrl: 0x%x\n", pol_elt_ctrl); break; case 0: case -1: break; case '?': /* unknown option */ return 1; default: /* assume this is handled by the plugin */ if ( curr_plugin == NULL ) { ERROR("Error: type must be the first option\n"); return 1; } if ( !(curr_plugin->cmdline_handler)(c, optarg) ) return 1; break; } } while ( c != -1 ); if ( cmd == 0 ) { ERROR("Error: no command was specified\n"); return 1; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); return 0; } else if ( cmd == 'S' ) { /* --show */ if ( optind == argc ) { ERROR("Error: no files specified\n"); return 1; } /* process any remaining argv[] items as element files */ while ( optind < argc ) { LOG("cmdline opt: file: %s\n", argv[optind]); DISPLAY("policy element file: %s\n", argv[optind]); size_t len; lcp_policy_element_t *elt = (lcp_policy_element_t *) read_file(argv[optind++], &len, false); if ( elt == NULL ) return 1; if ( !verify_policy_element(elt, len) ) return 1; display_policy_element(" ", elt, false); } return 0; } else if ( cmd == 'C' ) { /* --create */ if ( curr_plugin == NULL ) { ERROR("Error: no type was specified\n"); return 1; } if ( *out_file == '\0' ) { ERROR("Error: no output file specified\n"); return 1; } /* process any remaining argv[] items in plugin */ while ( optind < argc ) { LOG("cmdline opt: file: %s\n", argv[optind]); if ( !(curr_plugin->cmdline_handler)(0, argv[optind]) ) return 1; optind++; } /* * write element to out_file */ lcp_policy_element_t *elt = (curr_plugin->create_elt)(); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return 1; } /* size is filled in by create() */ elt->type = curr_plugin->type; elt->policy_elt_control = pol_elt_ctrl; if ( !write_file(out_file, elt, elt->size) ) { ERROR("Error: error writing element\n"); free(elt); return 1; } free(elt); return 0; } else if ( cmd == 'V' ) /* --version */ { DISPLAY("lcp2_crtpolelt version: %i.%i\nBuild date: %s", TOOL_VER_MAJOR, TOOL_VER_MINOR, __DATE__); return 0; } ERROR("Error: unknown command option\n"); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/crtpollist.c0000644000000000000000000006322414210363175015613 0ustar 00000000000000/* * crtpollist.c: Intel(R) TXT policy list (LCP_POLICY_LIST) creation tool * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #define PRINT printf #include "../../include/config.h" #include "../../include/hash.h" #include "../../include/uuid.h" #include "../../include/lcp3.h" #include "../../include/lcp3_hlp.h" #include "polelt_plugin.h" #include "lcputils.h" #include "pollist2.h" #include "pollist2_1.h" #include "polelt.h" #include "pollist1.h" #define TOOL_VER_MAJOR 0x1 #define TOOL_VER_MINOR 0x1 static const char help[] = "Usage: lcp2_crtpollist [OPTIONS]\n" "Create an Intel(R) TXT policy list.\n\n" "Supports:\n" " LCP_POLICY_LIST - legacy list format - major version 0x1.\n" " LCP_POLICY_LIST_2 - current list format for RSA-SSA - major version 0x2\n" " LCP_POLICY_LIST_2_1 - current list format for RSA-PSS and ECDSA - major version 0x1\n" "\n--create\n" "Creates LCP list version containing elements from [ELT FILES]\n" "and writes it to .\n\n" "To generate LCP_POLICY_LIST_2_1:\n" " --out policy list file\n" " --listver policy list version must be 0x300\n" " [ELT FILES]... policy element file(s)\n" "To generate LCP_POLICY_LIST_2:\n" " --out policy list file\n" " [--sigalg] signature algorithm\n" " --listver policy list version must be 0x200||0x201\n" " [ELT FILES]... policy element file(s)\n" "To generate LCP_POLICY_LIST:\n" " --out policy list file\n" " --listver policy list version must be 0x100\n\n" " [ELT FILES]... policy element file(s)\n" "\n--sign\n" "Signs policy list file\n" " --sigalg signature algorithm\n" " [--hashalg] LCP_POLICY_LIST2_1 option:\n" " hash algorithm\n" " --pub PEM file of public key\n" " [--priv ] PEM file of private key\n" " [--rev ] revocation counter value\n" " [--nosig] don't add SigBlock\n" " --out policy list file to sign\n" "\n--addsig\n" "Adds signature file to LCP_POLICY_LIST_2 - this option cannot be used\n" "with LCP_POLICY_LIST_2_1.\n" " --sig file containing signature (big-endian)\n" " --out policy list file\n" "\n--show\n" "Displays policy list contents.\n" " policy list file\n" "\n--verify\n" "Verifies signed LCP_POLICY_LIST_2_1 signature.\n" " policy list file with signature\n" "\n--help\n" "\n--verbose enable verbose output; can be\n" " specified with any command\n\n" "\n--version show tool version.\n" "The public and private keys can be created as follows:\n" " openssl genrsa -out privkey.pem 2048\n" " openssl rsa -pubout -in privkey.pem -out pubkey.pem\n"; bool verbose = false; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"sign", no_argument, NULL, 'S'}, {"addsig", no_argument, NULL, 'A'}, {"show", no_argument, NULL, 'W'}, {"verify", no_argument, NULL, 'V'}, {"version", no_argument, NULL, 'v'}, /* options */ {"out", required_argument, NULL, 'o'}, {"sigalg", required_argument, NULL, 'a'}, {"hashalg", required_argument, NULL, 'h'}, {"pub", required_argument, NULL, 'u'}, {"priv", required_argument, NULL, 'i'}, {"rev", required_argument, NULL, 'r'}, {"nosig", no_argument, NULL, 'n'}, {"sig", required_argument, NULL, 's'}, {"listver", required_argument, NULL, 'l'}, {"verbose", no_argument, NULL, 't'}, {0, 0, 0, 0} }; #define MAX_FILES 32 static uint16_t version = 0x0; static char pollist_file[MAX_PATH] = ""; static char sigalg_name[32] = ""; static uint16_t sigalg_type = TPM_ALG_NULL; // Default static char pubkey_file[MAX_PATH] = ""; static char privkey_file[MAX_PATH] = ""; static char sig_file[MAX_PATH] = ""; static uint16_t rev_ctr = 0; static bool no_sigblock = false; static unsigned int nr_files = 0; static char files[MAX_FILES][MAX_PATH]; static char hash_alg_name[32] = ""; static uint16_t hash_alg_cli = TPM_ALG_SHA256; //Default static int create_list_2_1(void) { LOG("create:version=0x0300\n"); lcp_policy_list_t2_1 *pollist = NULL; size_t len; lcp_policy_element_t *elt = NULL; bool write_ok = false; pollist = create_empty_tpm20_policy_list_2_1(); if ( pollist == NULL ) return 1; if (version && MAJOR_VER(version) == 3) pollist->Version = version; if (nr_files > MAX_FILES) { ERROR("Too many element files specified.\n"); return 1; } for ( unsigned int i = 0; i < nr_files; i++ ) { elt = read_file(files[i], &len, false); if ( elt == NULL ) { free(pollist); return 1; } if ( !verify_policy_element(elt, len) ) { free(pollist); free(elt); return 1; } pollist = add_tpm20_policy_element_2_1(pollist, elt); if ( pollist == NULL ) { free(elt); return 1; } free(elt); elt = NULL; } write_ok = write_tpm20_policy_list_2_1_file(pollist_file, pollist); free(pollist); return write_ok ? 0 : 1; } static int create(void) { lcp_list_t *pollist; bool write_ok = false; LOG("[create]\n"); uint16_t major_ver = MAJOR_VER(version); uint16_t minor_ver = MINOR_VER(version); if ( major_ver != MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION) && major_ver != MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) && major_ver != MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { ERROR("Error: only list versions 0x100, 0x200, 0x201 or 0x300 are supported\n"); return 1; } switch (major_ver) { case MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION): if (minor_ver > LCP_TPM12_POLICY_LIST_MAX_MINOR) { ERROR("Error: minor version 0x%02x not supported\n", minor_ver); return 1; } pollist = (lcp_list_t *) create_empty_tpm12_policy_list(); if (pollist == NULL) return 1; break; case MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION): if (minor_ver > LCP_TPM20_POLICY_LIST2_MAX_MINOR) { ERROR("Error: minor version 0x%02x not supported\n", minor_ver); return 1; } pollist = (lcp_list_t *) create_empty_tpm20_policy_list(); if ( pollist == NULL ) return 1; pollist->tpm20_policy_list.version = version; break; case MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300): if (minor_ver > LCP_TPM20_POLICY_LIST2_1_MAX_MINOR) { ERROR("Error: minor version 0x%02x not supported\n", minor_ver); return 1; } return create_list_2_1(); default: return 1; } for ( unsigned int i = 0; i < nr_files; i++ ) { size_t len; lcp_policy_element_t *elt = read_file(files[i], &len, false); if ( elt == NULL ) { free(pollist); return 1; } if ( !verify_policy_element(elt, len) ) { free(pollist); return 1; } if (major_ver == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION)) pollist = (lcp_list_t*) add_tpm20_policy_element(&(pollist->tpm20_policy_list), elt); else if (major_ver == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION)) pollist = (lcp_list_t*) add_tpm12_policy_element(&(pollist->tpm12_policy_list), elt); if ( pollist == NULL ) return 1; } if (major_ver == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION)) write_ok = write_tpm20_policy_list_file(pollist_file, &(pollist->tpm20_policy_list)); else if (major_ver == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION)) write_ok = write_tpm12_policy_list_file(pollist_file, &(pollist->tpm12_policy_list)); free(pollist); return write_ok ? 0 : 1; } static int sign(void) { LOG("[sign]\n"); bool result; void *file_data = read_file(pollist_file, NULL, false); sign_user_input user_input; if ( file_data == NULL ) { return 1; } //List version is first two bytes of the list file memcpy_s((void*)&version, sizeof(uint16_t), (const void *)file_data, sizeof(uint16_t)); free(file_data); //We just need version file_data = NULL; //sign_user_input is used to pass some data from users to functions in //pollis2.c and pollist2_1.c user_input.sig_alg = sigalg_type; user_input.hash_alg = hash_alg_cli; user_input.rev_ctr = rev_ctr; if (strcpy_s(user_input.list_file, MAX_PATH, pollist_file) != EOK) { ERROR("Error: cannot open file.\n"); return 1; } if (strcpy_s(user_input.pubkey_file, MAX_PATH, pubkey_file) != EOK) { ERROR("Error: cannot open file.\n"); return 1; } if (strcpy_s(user_input.privkey_file, MAX_PATH, privkey_file) != EOK) { ERROR("Error: cannot open file.\n"); return 1; } if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION) ) { LOG("sign: LCP_POLICY_LIST,sig_alg=LCP_POLSALG_RSA_PKCS_15\n"); result = sign_lcp_policy_list_t(user_input); if (result) { DISPLAY("List signed successfully and written to %s\n", user_input.list_file); return 0; } else { DISPLAY("Failed to sign and write LCP list.\n"); return 1; } } else if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) ) { LOG("sign: LCP_POLICY_LIST2,sig_alg=0x%x\n", user_input.sig_alg); result = sign_lcp_policy_list_t2(user_input); if (result) { DISPLAY("List signed successfully and written to %s\n", user_input.list_file); return 0; } else { DISPLAY("Failed to sign and write LCP list.\n"); return 1; } } else if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300)) { LOG("sign: LCP_POLICY_LIST2_1,sig_alg=0x%x\n", user_input.sig_alg); result = sign_lcp_policy_list_t2_1(user_input); if (result) { DISPLAY("List signed successfully and written to %s\n", user_input.list_file); return 0; } else { DISPLAY("Failed to sign and write LCP list.\n"); return 1; } } return 1; } static int addsig(void) { /* read existing policy list file */ bool no_sigblock_ok = true; lcp_list_t *pollist = read_policy_list_file(pollist_file, false, &no_sigblock_ok); if ( pollist == NULL ) return 1; uint16_t version ; memcpy_s((void*)&version, sizeof(uint16_t), (const void *)pollist, sizeof(uint16_t)); if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { DISPLAY("Not supported.\n"); return 0; } lcp_signature_t2 *sig = get_tpm20_signature(&(pollist->tpm20_policy_list)); if ( sig == NULL ) { free(pollist); return 1; } /* check public key size */ if ( (sig->rsa_signature.pubkey_size != 128 /* 1024 bits */) && (sig->rsa_signature.pubkey_size != 256 /* 2048 bits */) && (sig->rsa_signature.pubkey_size != 384 /* 3072 bits */) ) { ERROR("Error: public key size is not 1024/2048/3072 bits\n"); free(pollist); return 1; } /* read signature file */ size_t len; uint8_t *data = read_file(sig_file, &len, false); if ( data == NULL ) { free(pollist); return 1; } if ( len != sig->rsa_signature.pubkey_size ) { ERROR("Error: signature file size doesn't match public key size\n"); free(pollist); free(data); return 1; } /* verify that this sigblock actually matches the policy list */ LOG("verifying signature block...\n"); if (!verify_tpm20_pollist_sig(&pollist->tpm20_policy_list)) { ERROR("Error: signature file does not match policy list\n"); free(pollist); free(data); return 1; } LOG("signature file verified\n"); uint8_t *plsigblock = get_tpm20_sig_block(&(pollist->tpm20_policy_list)); if ( plsigblock == NULL ) { ERROR("Error: list sig block not found\n"); free(pollist); free(data); return 1; } /* data is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->rsa_signature.pubkey_size; i++ ) *(plsigblock + i) = *(data + (sig->rsa_signature.pubkey_size - i - 1)); if ( verbose ) { LOG("signature:\n"); display_tpm20_signature(" ", sig, pollist->tpm20_policy_list.sig_alg, false); } bool write_ok = write_tpm20_policy_list_file(pollist_file, &(pollist->tpm20_policy_list)); free(pollist); free(data); return write_ok ? 0 : 1; } static int show(void) { /* read existing file */ bool no_sigblock_ok = true; size_t file_len; lcp_list_t *pollist = read_file(files[0], &file_len, true); if ( pollist == NULL ) return 1; uint16_t version; memcpy_s((void*)&version, sizeof(uint16_t), (const void *)pollist, sizeof(uint16_t)); free(pollist); if (MAJOR_VER(version) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION) ) { pollist = read_policy_list_file(files[0], false, &no_sigblock_ok); if (pollist == NULL) { ERROR("Error: failed to read policy list file.\n"); return 1; } LOG("show: version == 0x0100\n"); DISPLAY("policy list file: %s\n", files[0]); display_tpm12_policy_list("", &(pollist->tpm12_policy_list), false); free(pollist); return 0; } if (MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) ) { pollist = read_policy_list_file(files[0], false, &no_sigblock_ok); if (pollist == NULL) { ERROR("Error: failed to read policy list file.\n"); return 1; } LOG("show: version == 0x0200\n"); DISPLAY("policy list file: %s\n", files[0]); display_tpm20_policy_list("", &(pollist->tpm20_policy_list), false); if ( pollist->tpm20_policy_list.sig_alg == TPM_ALG_RSASSA && !no_sigblock_ok ) { if ( verify_tpm20_pollist_sig(&(pollist->tpm20_policy_list)) ) DISPLAY("signature verified\n"); else DISPLAY("failed to verify signature\n"); } free(pollist); return 0; } if (MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { lcp_policy_list_t2_1 *pollist = read_policy_list_2_1_file(false, files[0]); if (pollist == NULL) { ERROR("Error: failed to read policy list file.\n"); return 1; } LOG("show: version == 0x0300\n"); DISPLAY("policy list file: %s\n", files[0]); display_tpm20_policy_list_2_1("", pollist, false); return 0; } return 0; } static int verify(void) { LOG("Verify policy list 2.1\n"); lcp_policy_list_t2_1 *pollist2_1 = NULL; void *file_data = NULL; size_t file_len; uint16_t version; file_data = read_file(files[0], &file_len, true); if (file_data == NULL) { ERROR("Error: failed to read pollist file.\n"); return 1; } memcpy_s((void*)&version, sizeof(uint16_t), file_data, sizeof(uint16_t)); free(file_data); file_data = NULL; if ( MAJOR_VER(version) == 1 ) { LOG("Unsupported.\n"); return 0; } else if ( MAJOR_VER(version) == 2 ){ LOG("Unsupported.\n"); return 0; } else if ( MAJOR_VER(version) == 3 ) { bool result; pollist2_1 = read_policy_list_2_1_file(false, files[0]); if ( pollist2_1 == NULL ) { ERROR("Error: failed to get policy list from file.\n"); return 1; } if ( pollist2_1->KeySignatureOffset == 0 ) { DISPLAY("Verification successful. List is not signed. Exiting.\n"); free(pollist2_1); return 0; } result = verify_tpm20_pollist_2_1_sig(pollist2_1); if (!result) { free(pollist2_1); DISPLAY("List signature did not verify positively.\n"); return 0; } else { free(pollist2_1); DISPLAY("List signature correct. Verification successful\n"); return 0; } } ERROR("Error: version unrecognized.\n"); return 1; } int main(int argc, char *argv[]) { int cmd = 0; bool prev_cmd = false; int c; do { c = getopt_long_only(argc, argv, "", long_opts, NULL); LOG("c=%c\n",c); switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* sign */ case 'A': /* addsig */ case 'W': /* show */ case 'V': /* verify */ case 'v': /* version */ if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 'o': /* out */ strlcpy(pollist_file, optarg, sizeof(pollist_file)); LOG("cmdline opt: out: %s\n", pollist_file); break; case 'h': strlcpy(hash_alg_name, optarg, sizeof(hash_alg_name)); LOG("cmdline opt hash_alg: %s\n", hash_alg_name); hash_alg_cli = str_to_hash_alg(hash_alg_name); if (hash_alg_cli == TPM_ALG_NULL) { ERROR("ERROR: incorrect hash alg specified"); return 1; } break; case 'a': strlcpy(sigalg_name, optarg, sizeof(sigalg_name)); LOG("cmdline opt: sigalg: %s\n", sigalg_name); sigalg_type = str_to_sig_alg(sigalg_name); break; case 'u': /* pub */ strlcpy(pubkey_file, optarg, sizeof(pubkey_file)); LOG("cmdline opt: pub: %s\n", pubkey_file); break; case 'i': /* priv */ strlcpy(privkey_file, optarg, sizeof(privkey_file)); LOG("cmdline opt: pub: %s\n", privkey_file); break; case 'r': /* rev */ rev_ctr = strtoul(optarg, NULL, 0); LOG("cmdline opt: rev: 0x%x (%u)\n", rev_ctr, rev_ctr); break; case 'n': /* nosig */ no_sigblock = true; LOG("cmdline opt: nosig: %u\n", no_sigblock); break; case 's': /* sigblock */ strlcpy(sig_file, optarg, sizeof(sig_file)); LOG("cmdline opt: sigblock: %s\n", sig_file); break; case 'l': /* listver */ version = strtoul(optarg, NULL, 16); if (version) { break; } else { ERROR("Error: only list versions 0x100, 0x200, 0x201 or 0x300 " \ "are supported\n"); return 1; } case 't': verbose = true; break; case 0: case -1: break; default: ERROR("Error: unrecognized option\n"); return 1; } } while ( c != -1 ); /* process any remaining argv[] items */ while ( optind < argc && nr_files < ARRAY_SIZE(files) ) { LOG("cmdline opt: file: %s\n", argv[optind]); strlcpy(files[nr_files++], argv[optind], sizeof(files[0])); optind++; } if ( cmd == 0 ) { ERROR("Error: no command option was specified\n"); return 1; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); return 0; } else if ( cmd == 'C' ) { /* --create */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } if ( !version ) { ERROR("ERROR: LCP list version not specified.\n"); return 1; } return create(); } else if ( cmd == 'S' ) { /* --sign */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } if (sigalg_type == TPM_ALG_NULL) { ERROR("Error: signature algorithm must be specified.\n"); return 1; } else { if ( *pubkey_file == '\0' ) { ERROR("Error: no public key file specified\n"); return 1; } if ( no_sigblock ) { /* no signature wanted */ if ( *privkey_file != '\0' ) { ERROR("Error: private key file specified with --nosig option\n"); return 1; } } else { /* we generate sig, so need private key */ if ( *privkey_file == '\0' ) { ERROR("Error: no private key file specified\n"); return 1; } } if (sigalg_type != TPM_ALG_RSASSA && sigalg_type != TPM_ALG_ECDSA && sigalg_type != TPM_ALG_RSAPSS && sigalg_type != TPM_ALG_SM3_256 && sigalg_type != LCP_POLSALG_RSA_PKCS_15 && sigalg_type != TPM_ALG_SM2) { ERROR("Error: Signature algorithm 0x%x unsupported.\n", sigalg_type); return 1; } } return sign(); } else if ( cmd == 'A' ) { /* --addsig */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } if ( *sig_file == '\0' ) { ERROR("Error: no signature file specified\n"); return 1; } return addsig(); } else if ( cmd == 'W' ) { /* --show */ if ( nr_files != 1 ) { ERROR("Error: no policy list file specified\n"); return 1; } return show(); } else if ( cmd == 'V') { /*--verify*/ if ( *files[0] == '\0' ) { ERROR("ERROR: no policy list file specified."); return 1; } return verify(); } else if ( cmd == 'v' ) { /* --version */ DISPLAY("lcp2_crtpollist version: %i.%i\nBuild date: %s", TOOL_VER_MAJOR, TOOL_VER_MINOR, __DATE__); return 0; } ERROR("Error: unknown command\n"); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/custom_elt.c0000644000000000000000000001613514210363175015571 0ustar 00000000000000/* * custom_elt.c: custom (user/ISV/etc. -defined) policy element * (LCP_CUSTOM_ELEMENT) plugin * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #define _GNU_SOURCE #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define NULL_UUID { 0x00000000, 0x0000, 0x0000, 0x0000, \ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } static uuid_t uuid = NULL_UUID; static size_t data_len; static uint8_t *data; static char *skipspace(const char *s) { while (*s != '\0' && isspace(*s)) s++; return (char *)s; } static bool string_to_uuid(const char *s, uuid_t *uuid) { int i; char *next; *uuid = (uuid_t)NULL_UUID; s = skipspace(s); /* * users can input "tboot" to specify to use the default tb policy uuid * for wrapping tb policy into lcp custom element */ if ( strcmp(s, "tboot") == 0 ) { *uuid = (uuid_t)LCP_CUSTOM_ELEMENT_TBOOT_UUID; return true; } /* Fetch data1 */ if ( *s++ != '{' ) return false; s = skipspace(s); uuid->data1 = (uint32_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data2 */ if ( *s++ != ',' ) return false; s = skipspace(s); uuid->data2 = (uint16_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data3 */ if ( *s++ != ',' ) return false; s = skipspace(s); uuid->data3 = (uint16_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data4 */ if ( *s++ != ',' ) return false; s = skipspace(s); uuid->data4 = (uint16_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data5 */ if ( *s++ != ',' ) return false; s = skipspace(s); if ( *s++ != '{' ) return false; s = skipspace(s); for ( i = 0; i < 6; i++ ) { uuid->data5[i] = (uint8_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; if ( i < 5 ) { /* Check "," */ if ( *s++ != ',' ) return false; s = skipspace(s); } else { /* Check "}}" */ if ( *s++ != '}' ) return false; s = skipspace(s); if ( *s++ != '}' ) return false; s = skipspace(s); } } if ( *s != '\0' ) return false; return true; } static bool cmdline_handler(int c, const char *opt) { if ( c == 'u' ) { if ( !string_to_uuid(opt, &uuid) ) { ERROR("Error: uuid is not well formed: %s\n", opt); return false; } LOG("cmdline opt: uuid:"); if ( verbose ) { print_uuid(&uuid); LOG("\n"); } return true; } else if ( c != 0 ) { ERROR("Error: unknown option for custom type\n"); return false; } /* data file */ LOG("cmdline opt: data file: %s\n", opt); data = read_file(opt, &data_len, false); if ( data == NULL ) return false; return true; } static lcp_policy_element_t *create(void) { LOG("[create]\n"); if ( are_uuids_equal(&uuid, &((uuid_t)NULL_UUID)) ) { ERROR("Error: no uuid specified\n"); free(data); return NULL; } size_t data_size = sizeof(lcp_custom_element_t) + data_len; lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); free(data); return NULL; } memset_s(elt, sizeof(*elt) + data_size, 0); elt->size = sizeof(*elt) + data_size; lcp_custom_element_t2 *custom = (lcp_custom_element_t2 *)&elt->data; custom->uuid = uuid; memcpy_s(custom->data, data_len, data, data_len); free(data); data = NULL; LOG("create custom element succeed!\n"); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_custom_element_t2 *custom = (lcp_custom_element_t2 *)elt->data; DISPLAY("%s uuid: ", prefix); print_uuid(&custom->uuid); DISPLAY("\n"); DISPLAY("%s data:\n", prefix); print_hex(prefix, custom->data, elt->size - sizeof(*elt) - sizeof(custom->uuid)); } static struct option opts[] = { {"uuid", required_argument, NULL, 'u'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "custom", opts, " custom\n" " --uuid UUID in format:\n" " {0xaabbccdd, 0xeeff, 0xgghh, 0xiijj,\n" " {0xkk 0xll, 0xmm, 0xnn, 0xoo, 0xpp}}\n" " or \"--uuid tboot\" to use default\n" " file containing element data\n", LCP_POLELT_TYPE_CUSTOM2, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/hash.c0000644000000000000000000001773414210363175014344 0ustar 00000000000000/* * hash.c: support functions for tb_hash_t type * * Copyright (c) 2020 Cisco Systems, Inc. * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../../include/config.h" #include "../../include/hash.h" /* * are_hashes_equal * * compare whether two hash values are equal. * */ bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { int diff; if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) return false; if ( hash_alg == TB_HALG_SHA1 ) return (memcmp_s(hash1, SHA1_LENGTH, hash2, SHA1_LENGTH, &diff) == 0 && diff == 0); else if ( hash_alg == TB_HALG_SHA256 ) return (memcmp_s(hash1, SHA256_LENGTH, hash2, SHA256_LENGTH, &diff) == 0 && diff == 0); else if ( hash_alg == TB_HALG_SM3 ) return (memcmp_s(hash1, SM3_LENGTH, hash2, SM3_LENGTH, &diff) == 0 && diff == 0); else if ( hash_alg == TB_HALG_SHA384 ) return (memcmp_s(hash1, SHA384_LENGTH, hash2, SHA384_LENGTH, &diff) == 0 && diff == 0); else if ( hash_alg == TB_HALG_SHA512 ) return (memcmp_s(hash1, SHA512_LENGTH, hash2, SHA512_LENGTH, &diff) == 0 && diff == 0); else return false; } /* * hash_buffer * * hash the buffer according to the algorithm * */ bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) return false; if ( hash_alg == TB_HALG_SHA1 || hash_alg == TB_HALG_SHA1_LG ) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); const EVP_MD *md; md = EVP_sha1(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, size); EVP_DigestFinal(ctx, hash->sha1, NULL); EVP_MD_CTX_destroy(ctx); return true; } else if (hash_alg == TB_HALG_SHA256) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); const EVP_MD *md; md = EVP_sha256(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, size); EVP_DigestFinal(ctx, hash->sha256, NULL); EVP_MD_CTX_destroy(ctx); return true; } else if (hash_alg == TB_HALG_SHA384) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); const EVP_MD *md; md = EVP_sha384(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, size); EVP_DigestFinal(ctx, hash->sha384, NULL); EVP_MD_CTX_destroy(ctx); return true; } else if (hash_alg == TB_HALG_SHA512) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); const EVP_MD *md; md = EVP_sha512(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, size); EVP_DigestFinal(ctx, hash->sha512, NULL); EVP_MD_CTX_destroy(ctx); return true; } else if (hash_alg == TB_HALG_SM3) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); const EVP_MD *md; md = EVP_sm3(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, size); EVP_DigestFinal(ctx, hash->sm3, NULL); EVP_MD_CTX_destroy(ctx); return true; } else return false; } /* * extend_hash * * perform "extend" of two hashes (i.e. hash1 = SHA(hash1 || hash2) * */ bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { uint8_t buf[2*sizeof(tb_hash_t)]; if ( hash1 == NULL || hash2 == NULL ) return false; if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX *ctx = EVP_MD_CTX_create(); const EVP_MD *md; memcpy_s(buf, sizeof(buf), &(hash1->sha1), sizeof(hash1->sha1)); memcpy_s(buf + sizeof(hash1->sha1), sizeof(buf) - sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1)); md = EVP_sha1(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, 2*sizeof(hash1->sha1)); EVP_DigestFinal(ctx, hash1->sha1, NULL); EVP_MD_CTX_destroy(ctx); return true; } else return false; } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) return; if ( hash_alg == TB_HALG_SHA1 ) { for ( unsigned int i = 0; i < SHA1_LENGTH; i++ ) { printf("%02x", hash->sha1[i]); if ( i < SHA1_LENGTH-1 ) printf(" "); } printf("\n"); } else if ( hash_alg == TB_HALG_SHA256 ) { for ( unsigned int i = 0; i < SHA256_LENGTH; i++ ) { printf("%02x", hash->sha256[i]); if ( i < SHA256_LENGTH-1 ) printf(" "); } printf("\n"); } else if ( hash_alg == TB_HALG_SHA384 ) { for ( unsigned int i = 0; i < SHA384_LENGTH; i++ ) { printf("%02x", hash->sha384[i]); if ( i < SHA384_LENGTH-1 ) printf(" "); } printf("\n"); } else if ( hash_alg == TB_HALG_SHA512 ) { for ( unsigned int i = 0; i < SHA512_LENGTH; i++ ) { printf("%02x", hash->sha512[i]); if ( i < SHA512_LENGTH-1 ) printf(" "); } printf("\n"); } else if ( hash_alg == TB_HALG_SM3) { for ( unsigned int i = 0; i < SM3_LENGTH; i++ ) { printf("%02x", hash->sm3[i]); if ( i < SM3_LENGTH-1 ) printf(" "); } printf("\n"); } else return; } /* * import a hash in the format "755567de6e0a3ee1b71a895b76..." */ bool import_hash(const char *string, tb_hash_t *hash, uint16_t alg) { size_t hash_len = get_hash_size(alg); size_t string_len = strnlen(string, hash_len * 2 + 1); unsigned int iter_a, iter_b; char byte[3] = {0, 0, 0}; for (iter_a = 0, iter_b = 0; iter_a < string_len && iter_b <= hash_len; iter_a += 2, iter_b++) { memcpy_s(byte, sizeof(byte), &string[iter_a], 2); hash->sha512[iter_b] = strtol(byte, NULL, 16); } if (iter_a != string_len || iter_b != hash_len) return false; return true; } void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg) { if ( dest_hash == NULL || src_hash == NULL ) return; if ( hash_alg == TB_HALG_SHA1 ) memcpy_s(dest_hash, SHA1_LENGTH, src_hash, SHA1_LENGTH); else return; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/lcptools.txt0000644000000000000000000000576314210363175015654 0ustar 00000000000000These are some example instructions for creating an Intel(R) TXT Launch Control Policy (LCP) using the new LCP tools (i.e. for platforms produced after 2008). These steps assume that all referenced binaries have already been built and paths are relative to the tboot/lcptools-v2/ directory: Create policy element(s): ======================== Create an MLE element: --------------------- 1. lcp2_mlehash --create --cmdline "the command line for tboot from grub.conf" --alg sha1 /boot/tboot.gz > mle_hash 2. lcp2_crtpolelt --create --type mle --ctrl 0x00 --minver 17 --alg sha1 --out mle.elt mle_hash Note: Since GRUB2 does not pass the file name in the command line field of the multiboot entry, the command line to be included in creation of MLE element should exclude the first file name in the command line field of multiboot entry. Create an SBIOS element: ----------------------- 1. Create hash file containing BIOS hash(es), e.g. named sbios_hash 2. lcp2_crtpolelt --create --type sbios --alg sha1 --out sbios.elt sbios_hash Create a CUSTOM element: ----------------------- 1. Create or determine the UUID that will identify this data format (e.g. using 'uuidgen') 2. Create the data the will be placed in this element. E.g. the policy file from tb_polgen. 2. lcp2_crtpolelt --create --type custom --out custom.elt --uuid Create policy list(s): ===================== Combine the elements into an unsigned list: ------------------------------------------ 1. lcp2_crtpollist --create --out list_unsig.lst mle.elt pconf.elt The two blocks below are intended to be mutually exclusive. The openssl signing is supported for cases where the signing environment is separate from the policy creation environment and the software allowed to run there is strictly controlled and already supports openssl. Use lcp2_crtpollist to sign the list (sigalg=rsa): ----------------------------------- 1. openssl genrsa -out privkey.pem 2048 2. openssl rsa -pubout -in privkey.pem -out pubkey.pem 3. cp list_unsig.lst list_sig.lst 4. lcp2_crtpollist --sign --sigalg rsassa --pub pubkey.pem --priv privkey.pem --out list_sig.lst Use lcp2_crtpollist to sign the list (sigalg=ecdsa): ----------------------------------- 1. cp list_unsig.lst list_sig.lst 2. lcp2_crtpollist --sign --sigalg ecdsa --out list_sig.lst Use openssl to sign the list: ---------------------------- 1. openssl rsa -pubout -in privkey.pem -out pubkey.pem 2. cp list_unsig.lst list_sig.lst 3. lcp2_crtpollist --sign --sigalg rsassa --pub pubkey.pem --nosig --out list_sig.lst 4. openssl genrsa -out privkey.pem 2048 5. openssl dgst -sha1 -sign privkey.pem -out list.sig list_sig.lst 6. lcp2_crtpollist --addsig --sig list.sig --out list_sig.lst Create policy and policy data files: =================================== 1. lcp2_crtpol2 --create --alg sha1 --type list --pol list.pol --data list.data list_{unsig,sig}.lst LCP Policy Data file is allowed to be mixing of LCP_POLICY_LIST and LCP_POLICY_LIST2 lists. tboot-1.10.5/lcptools-v2/lcputils.c0000644000000000000000000013510714210363175015253 0ustar 00000000000000/* * lcputils.c: misc. LCP helper fns * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER >= 0x30000000L #include #include #include #include #endif #include #include #define PRINT printf #include "../../include/config.h" #include "../../include/hash.h" #include "../../include/uuid.h" #include "../../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #include "pollist2.h" static uint16_t pkcs_get_hashalg(const unsigned char *data); void ERROR(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } void LOG(const char *fmt, ...) { va_list ap; if ( verbose ) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } } void DISPLAY(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); } size_t strlcpy(char *dst, const char *src, size_t siz) { strcpy_s(dst, siz, src); return strnlen_s(dst, siz); } void print_hex(const char *prefix, const void *data, size_t n) { #define NUM_CHARS_PER_LINE 20 unsigned int i = 0; while ( i < n ) { if ( i % NUM_CHARS_PER_LINE == 0 && prefix != NULL ) { DISPLAY("%s", prefix); } DISPLAY("%02x ", *(uint8_t *)data++); i++; if ( i % NUM_CHARS_PER_LINE == 0 ) { DISPLAY("\n"); } } if ( i % NUM_CHARS_PER_LINE != 0 ) { DISPLAY("\n"); } } void parse_comma_sep_ints(char *s, uint16_t ints[], unsigned int *nr_ints) { unsigned int nr = 0; while ( true ) { char *str = strsep(&s, ","); if ( str == NULL || nr == *nr_ints ) break; ints[nr++] = strtoul(str, NULL, 0); } *nr_ints = nr; return; } void *read_file(const char *file, size_t *length, bool fail_ok) { LOG("[read_file]\n"); LOG("read_file: filename=%s\n", file); FILE *fp = fopen(file, "rb"); if ( fp == NULL ) { if ( !fail_ok ) ERROR("Error: failed to open file %s: %s\n", file, strerror(errno)); return NULL; } /* find size */ fseek(fp, 0, SEEK_END); long len = ftell(fp); if (len <= 0) { ERROR("Error: failed to get file length or file is empty.\n"); fclose(fp); return NULL; } rewind(fp); void *data = malloc(len); if ( data == NULL ) { ERROR("Error: failed to allocate %d bytes memory\n", len); fclose(fp); return NULL; } if ( fread(data, len, 1, fp) != 1 ) { ERROR("Error: reading file %s\n", file); free(data); fclose(fp); return NULL; } fclose(fp); if ( length != NULL ) *length = len; LOG("read file succeed!\n"); return data; } bool write_file(const char *file, const void *data, size_t size) { LOG("[write_file]\n"); FILE *fp = fopen(file, "wb"); if ( fp == NULL ) { ERROR("Error: failed to open file %s for writing: %s\n", file, strerror(errno)); return false; } if ( fwrite(data, size, 1, fp) != 1 ) { ERROR("Error: writing file %s\n", file); fclose(fp); return false; } fclose(fp); LOG("write file succeed!\n"); return true; } bool parse_line_hashes(const char *line, tb_hash_t *hash, uint16_t alg) { /* skip any leading whitespace */ while ( *line != '\0' && isspace(*line) ) line++; /* rest of line is hex of hash */ unsigned int i = 0; while ( *line != '\0' && *line != '\n' ) { char *next; switch (alg) { case LCP_POLHALG_SHA1: //Legacy value for TPM 1.2 hash->sha1[i++] = (uint8_t)strtoul(line, &next, 16); break; case TPM_ALG_SHA1: hash->sha1[i++] = (uint8_t)strtoul(line, &next, 16); break; case TPM_ALG_SHA256: hash->sha256[i++] = (uint8_t)strtoul(line, &next, 16); break; case TPM_ALG_SHA384: hash->sha384[i++] = (uint8_t)strtoul(line, &next, 16); break; default: ERROR("Error: unsupported alg: 0x%x\n",alg); return false; } if ( next == line ) /* done */ break; line = next; /* spaces at end cause strtoul() to interpret as 0, so skip them */ while ( *line != '\0' && !isxdigit(*line) ) line++; } if ( i != get_hash_size(alg) ) { ERROR("Error: incorrect number of chars for hash\n"); return false; } return true; } bool parse_file(const char *filename, bool (*parse_line)(const char *line)) { if ( filename == NULL || parse_line == NULL ) return false; LOG("reading hashes file %s...\n", filename); FILE *fp = fopen(filename, "r"); if ( fp == NULL ) { ERROR("Error: failed to open file %s (%s)\n", filename, strerror(errno)); return false; } static char line[1024]; while ( true ) { char *s = fgets(line, sizeof(line), fp); if ( s == NULL ) { fclose(fp); return true; } LOG("read line: %s\n", line); if ( !(*parse_line)(line) ) { fclose(fp); return false; } } fclose(fp); return false; } const char *hash_alg_to_str(uint16_t alg) { static char buf[32]; switch(alg){ case TPM_ALG_SHA1: return "TPM_ALG_SHA1"; case TPM_ALG_SHA256: return "TPM_ALG_SHA256"; case TPM_ALG_SHA384: return "TPM_ALG_SHA384"; case TPM_ALG_SHA512: return "TPM_ALG_SHA512"; case TPM_ALG_SM3_256: return "TPM_ALG_SM3_256"; case TPM_ALG_SM2: return "TPM_ALG_SM2"; case LCP_POLHALG_SHA1: //Legacy value for TPM 1.2 return "LCP_POLHALG_SHA1"; default: snprintf_s_i(buf, sizeof(buf), "unknown (%u)", alg); return buf; } } const char *key_alg_to_str(uint16_t alg) { switch (alg) { case TPM_ALG_RSA: return "TPM_ALG_RSA"; case TPM_ALG_ECC: return "TPM_ALG_ECC"; default: return ""; } } const char *sig_alg_to_str(uint16_t alg) { static char buf[32]; switch(alg){ case TPM_ALG_RSASSA: return "TPM_ALG_RSASSA"; case TPM_ALG_ECDSA: return "TPM_ALG_ECDSA"; case TPM_ALG_SM2: return "TPM_ALG_SM2"; case TPM_ALG_RSAPSS: return "TPM_ALG_RSAPSS"; case TPM_ALG_SM3_256: return "TPM_ALG_SM3_256"; case TPM_ALG_NULL: return "TPM_ALG_NULL"; case LCP_POLSALG_RSA_PKCS_15: return "LCP_POLSALG_RSA_PKCS_15"; default: snprintf_s_i(buf, sizeof(buf), "unknown (%u)", alg); return buf; } } uint16_t str_to_hash_alg(const char *str) { if (strcmp(str,"sha1") == 0) return TPM_ALG_SHA1; else if (strcmp(str,"sha256") == 0) return TPM_ALG_SHA256; else if (strcmp(str,"sha384") == 0) return TPM_ALG_SHA384; else if (strcmp(str,"sha512") == 0) return TPM_ALG_SHA512; else if (strcmp(str,"sm3") == 0) return TPM_ALG_SM3_256; else return TPM_ALG_NULL; } uint16_t str_to_lcp_hash_mask(const char *str) { if (strcmp(str,"sha1") == 0) return TPM_ALG_MASK_SHA1; else if (strcmp(str,"sha256") == 0) return TPM_ALG_MASK_SHA256; else if (strcmp(str,"sha384") == 0) return TPM_ALG_MASK_SHA384; else if (strcmp(str,"sha512") == 0) return TPM_ALG_MASK_SHA512; else if (strcmp(str,"sm3") == 0) return TPM_ALG_MASK_SM3_256; else if(strncmp(str, "0X", 2) || strncmp(str, "0x", 2)) return strtoul(str, NULL, 0); else return TPM_ALG_MASK_NULL; } uint16_t str_to_sig_alg(const char *str) { if (strcmp(str,"rsa-pkcs15") == 0) return LCP_POLSALG_RSA_PKCS_15; if( strcmp(str,"rsa-ssa") == 0 || strcmp(str,"rsassa") == 0 || strcmp(str,"rsa") == 0 ) return TPM_ALG_RSASSA; if ( strcmp(str,"ecdsa") == 0) return TPM_ALG_ECDSA; if ( strcmp(str,"sm2") == 0) return TPM_ALG_SM2; if( strcmp(str,"rsa-pss") == 0 || strcmp(str,"rsapss") == 0 ) return TPM_ALG_RSAPSS; else { LOG("Unrecognized signature alg, assuming TPM_ALG_NULL"); return TPM_ALG_NULL; } } uint32_t str_to_sig_alg_mask(const char *str, const uint16_t version, size_t size) { uint16_t lcp_major_ver = version & 0xFF00; if( lcp_major_ver == LCP_VER_2_0 ) { //signature algorithm mask is undefined in LCPv2 return SIGN_ALG_MASK_NULL; } else if( lcp_major_ver == LCP_VER_3_0 ) { if (strncmp(str, "rsa-2048-sha1", size) == 0) { return SIGN_ALG_MASK_RSASSA_2048_SHA1; } else if (strncmp(str, "rsa-2048-sha256", size) == 0) { return SIGN_ALG_MASK_RSASSA_2048_SHA256; } else if (strncmp(str, "rsa-3072-sha256", size) == 0) { return SIGN_ALG_MASK_RSASSA_3072_SHA256; } else if (strncmp(str, "rsa-3072-sha384", size) == 0) { return SIGN_ALG_MASK_RSASSA_3072_SHA384; } else if (strncmp(str, "ecdsa-p256", size) == 0) { return SIGN_ALG_MASK_ECDSA_P256; } else if (strncmp(str, "ecdsa-p384", size) == 0) { return SIGN_ALG_MASK_ECDSA_P384; } else if (strncmp(str, "sm2", size) == 0) { return SIGN_ALG_MASK_SM2; } else if(strncmp(str, "0X", 2) || strncmp(str, "0x", 2)){ return strtoul(str, NULL, 0); } else{ //Format unrecognized return SIGN_ALG_MASK_NULL; } } else return SIGN_ALG_MASK_NULL; } uint16_t str_to_pol_ver(const char *str) { if( strcmp(str,"2.0") == 0) return LCP_VER_2_0; else if ( strcmp(str,"2.1") == 0) return LCP_VER_2_1; else if ( strcmp(str,"2.2") == 0) return LCP_VER_2_2; else if ( strcmp(str,"2.3") == 0) return LCP_VER_2_3; else if ( strcmp(str,"2.4") == 0) return LCP_VER_2_4; else if ( strcmp(str,"3.0") == 0) return LCP_VER_3_0; else if ( strcmp(str,"3.1") == 0) return LCP_VER_3_1; else if ( strcmp(str, "3.2") == 0) return LCP_VER_3_2; else return LCP_VER_NULL; } uint16_t convert_hash_alg_to_mask(uint16_t hash_alg) { LOG("convert_hash_alg_to_mask hash_alg = 0x%x\n", hash_alg); switch(hash_alg){ case TPM_ALG_SHA1: return TPM_ALG_MASK_SHA1; case TPM_ALG_SHA256: return TPM_ALG_MASK_SHA256; case TPM_ALG_SHA384: return TPM_ALG_MASK_SHA384; case TPM_ALG_SHA512: return TPM_ALG_MASK_SHA512; case TPM_ALG_SM3_256: return TPM_ALG_MASK_SM3_256; default: return 0; } return 0; } size_t get_lcp_hash_size(uint16_t hash_alg) { switch(hash_alg){ case TPM_ALG_SHA1: return SHA1_DIGEST_SIZE; case TPM_ALG_SHA256: return SHA256_DIGEST_SIZE; case TPM_ALG_SHA384: return SHA384_DIGEST_SIZE; case TPM_ALG_SHA512: return SHA512_DIGEST_SIZE; case TPM_ALG_SM3_256: return SM3_256_DIGEST_SIZE; case LCP_POLHALG_SHA1: //Legacy value for TPM 1.2 return SHA1_DIGEST_SIZE; default: return 0; } return 0; } bool verify_rsa_signature(sized_buffer *data, sized_buffer *pubkey, sized_buffer *signature, uint16_t hashAlg, uint16_t sig_alg, uint16_t list_ver) /* This function: verifies policy list's rsapss and rsassa signatures using pubkey In: Data - pointer to sized buffer with signed LCP policy list contents: LCP_POLICY_LIST2_1 - entire list up to KeyAndSignature field (that includes RevoCation counter) i.e. KeyAndSignatureOffset bytes of data from the list. LCP_POLICY_LIST and LCP_POLICY_LIST2 - entire list minus the signature field. pubkey - pointer to sized buffer containing public key in BE form signature - pointer to sized buffer containing signature in BE form hashAlg - LCP_SIGNATURE2_1->RsaKeyAndSignature.Signature.HashAlg i.e. hash alg defined for the list signature. Or TPM_HASHALG_NULL if hashalg is not a member of list structure (it will be read from signature) sig_alg - signature algorithm of the list list_ver - specify list version: LCP_POLICY_LIS, LCP_POLICY_LIST2 or LCP_POLICY_LIST2_1 Out: true/false on verification success or failure */ { int status; EVP_PKEY_CTX *evp_context = NULL; EVP_PKEY *evp_key = NULL; BIGNUM *modulus = NULL; BIGNUM *exponent = NULL; tb_hash_t *digest = NULL; unsigned char exp_arr[] = {0x01, 0x00, 0x01}; unsigned char *decrypted_sig = NULL; #if OPENSSL_VERSION_NUMBER >= 0x30000000L size_t dcpt_sig_len; #else RSA *rsa_pubkey = NULL; #endif LOG("[verify_rsa_signature]\n"); if (data == NULL || pubkey == NULL || signature == NULL) { ERROR("Error: list data, pubkey or signature buffer not defined.\n"); return false; } modulus = BN_bin2bn(pubkey->data, pubkey->size, NULL); exponent = BN_bin2bn(exp_arr, 3, NULL); if ( modulus == NULL || exponent == NULL ) { ERROR("Error: failed to convert modulus and/or exponent.\n"); goto OPENSSL_ERROR; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L evp_context = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); if ( evp_context == NULL) { ERROR("Error: failed to initialize CTX from name.\n"); goto OPENSSL_ERROR; } OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new(); if ( params_build == NULL ) { ERROR("Error: failed to set up parameter builder.\n"); goto OPENSSL_ERROR; } if ( !OSSL_PARAM_BLD_push_BN(params_build, "n", modulus) ) { ERROR("Error: failed to push modulus into param build.\n"); goto OPENSSL_ERROR; } if ( !OSSL_PARAM_BLD_push_BN(params_build, "e", exponent) ) { ERROR("Error: failed to push exponent into param build.\n"); goto OPENSSL_ERROR; } if ( !OSSL_PARAM_BLD_push_BN(params_build, "d", NULL) ) { ERROR("Error: failed to push NULL into param build.\n"); goto OPENSSL_ERROR; } OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build); if ( params == NULL ) { ERROR("Error: failed to construct parameters from builder.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_fromdata_init(evp_context) <= 0 ) { ERROR("Error: failed to initialize key creation.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_fromdata(evp_context, &evp_key, EVP_PKEY_PUBLIC_KEY, params) <= 0 ) { ERROR("Error: failed to create key.\n"); goto OPENSSL_ERROR; } OSSL_PARAM_free(params); OSSL_PARAM_BLD_free(params_build); EVP_PKEY_CTX_free(evp_context); evp_context = NULL; #else rsa_pubkey = RSA_new(); if ( rsa_pubkey == NULL ) { ERROR("Error: failed to allocate key\n"); status = 0; goto EXIT; } #if OPENSSL_VERSION_NUMBER >= 0x10100000L RSA_set0_key(rsa_pubkey, modulus, exponent, NULL); #else rsa_pubkey->n = modulus; rsa_pubkey->e = exponent; rsa_pubkey->d = rsa_pubkey->p = rsa_pubkey->q = NULL; #endif #endif if (MAJOR_VER(list_ver) != MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300)) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L evp_context = EVP_PKEY_CTX_new(evp_key, NULL); if ( evp_context == NULL ) { ERROR("Error: failed to instatiate CTX.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_encrypt_init(evp_context) <= 0 ) { ERROR("Error: failed to initialize signature decryption.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_CTX_set_rsa_padding(evp_context, RSA_NO_PADDING) <= 0 ) { ERROR("Error: failed to set RSA padding.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_encrypt(evp_context, NULL, &dcpt_sig_len, signature->data, pubkey->size) <= 0 ) { ERROR("Error: failed to retrieve decrypted signature length.\n"); goto OPENSSL_ERROR; } decrypted_sig = OPENSSL_malloc(dcpt_sig_len); if ( decrypted_sig == NULL ) { ERROR("Error: failed to allocate memory for decrypted signature.\n"); status = 0; goto EXIT; } if ( EVP_PKEY_encrypt(evp_context, decrypted_sig, &dcpt_sig_len, signature->data, pubkey->size) <= 0 ) { ERROR("Error: failed to decrypt signature.\n"); goto OPENSSL_ERROR; } if ( verbose ) { LOG("Decrypted signature: \n"); print_hex("", decrypted_sig, dcpt_sig_len); } EVP_PKEY_CTX_free(evp_context); evp_context = NULL; #else decrypted_sig = OPENSSL_malloc(pubkey->size); status = RSA_public_decrypt(pubkey->size, signature->data, decrypted_sig, rsa_pubkey, RSA_NO_PADDING); if (status <= 0) { ERROR("Error: failed to decrypt signature.\n"); goto OPENSSL_ERROR; } if ( verbose ) { LOG("Decrypted signature: \n"); print_hex("", decrypted_sig, pubkey->size); } #endif //In older lists we need to get hashAlg from signature data. hashAlg = pkcs_get_hashalg((const unsigned char *) decrypted_sig); OPENSSL_free((void *) decrypted_sig); } #if OPENSSL_VERSION_NUMBER < 0x30000000L evp_key = EVP_PKEY_new(); if ( evp_key == NULL) { goto OPENSSL_ERROR; } status = EVP_PKEY_set1_RSA(evp_key, rsa_pubkey); if (status <= 0) { goto OPENSSL_ERROR; } #endif evp_context = EVP_PKEY_CTX_new(evp_key, NULL); if ( evp_context == NULL ) { ERROR("Error: failed to initialize CTX from pkey.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_verify_init(evp_context) <= 0) { ERROR("Error: failed to initialize verification."); goto OPENSSL_ERROR; } if ( sig_alg == TPM_ALG_RSAPSS) status = EVP_PKEY_CTX_set_rsa_padding(evp_context, RSA_PKCS1_PSS_PADDING); else if (sig_alg == TPM_ALG_RSASSA || sig_alg == LCP_POLSALG_RSA_PKCS_15) status = EVP_PKEY_CTX_set_rsa_padding(evp_context, RSA_PKCS1_PADDING); else { ERROR("Error: unsupported signature algorithm.\n"); status = 0; goto EXIT; } if ( status <= 0) { ERROR("Error: failed to set rsa padding.\n"); goto OPENSSL_ERROR; } if ( hashAlg == TPM_ALG_SHA1 ) { status = EVP_PKEY_CTX_set_signature_md(evp_context, EVP_sha1()); } else if ( hashAlg == TPM_ALG_SHA256 ) { status = EVP_PKEY_CTX_set_signature_md(evp_context, EVP_sha256()); } else if ( hashAlg == TPM_ALG_SHA384 ) { status = EVP_PKEY_CTX_set_signature_md(evp_context, EVP_sha384()); } else { ERROR("Error: Unknown hash alg.\n"); status = 0; goto EXIT; } if ( status <= 0 ) { ERROR("Error: failed to set signature message digest.\n"); goto OPENSSL_ERROR; } digest = malloc(get_lcp_hash_size(hashAlg)); if (digest == NULL) { ERROR("Error: failed to allocate digest"); status = 0; goto EXIT; } if ( !hash_buffer((const unsigned char *) data->data, data->size, digest, hashAlg) ) { ERROR("Error: failed to hash list contents.\n"); status = 0; goto EXIT; } status = EVP_PKEY_verify(evp_context, signature->data, pubkey->size, (const unsigned char *) digest, get_lcp_hash_size(hashAlg)); if (status < 0) { //Error occurred goto OPENSSL_ERROR; } else { //EVP_PKEY_verify executed successfully goto EXIT; } OPENSSL_ERROR: ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); status = 0; EXIT: #if OPENSSL_VERSION_NUMBER < 0x30000000L if (rsa_pubkey != NULL) OPENSSL_free((void *) rsa_pubkey); #endif if (evp_context != NULL) OPENSSL_free((void *) evp_context); if (evp_key != NULL) OPENSSL_free((void *) evp_key); if (modulus != NULL) OPENSSL_free((void *) modulus); if (exponent != NULL) OPENSSL_free((void *) exponent); if (digest != NULL) free(digest); return status ? true : false; } bool verify_ec_signature(sized_buffer *data, sized_buffer *pubkey_x, sized_buffer *pubkey_y, sized_buffer *sig_r, sized_buffer *sig_s, uint16_t sigalg, uint16_t hashalg) { /* This function: verifies ecdsa or SM2 signature using pubkey (lists 2.0 and 2.1 only!) In: Data - LCP policy list contents: LCP_LIST_2_1: entire list up to KeyAndSignature field (that includes RevoCation counter) i.e. hash of KeyAndSignatureOffset bytes of the list. LCP_LIST_2: entire list up to the r member of the Signature field that is sizeof list - 2 * keysize sized_buffers: pubkey_x - public key x coordinate (must be BE) pubkey_y - public key y coordinate (must be BE) sig_r and sig_s - buffers containing signature bytes BE sigalg - signature algorithm used to sign list (must be ecdsa or sm2) hashAlg - hash algorithm used to create digest Out: true/false on verification success or failure */ int result; BIGNUM *x = NULL; BIGNUM *y = NULL; EVP_PKEY *evp_key = NULL; const EVP_MD *mdtype; const unsigned char *der_encoded_sig = NULL; int encoded_len; int curveId = 0; EVP_MD_CTX *mctx = NULL; EVP_PKEY_CTX *pctx = NULL; #if OPENSSL_VERSION_NUMBER >= 0x30000000L const EC_GROUP *ec_group = NULL; EC_POINT *ec_point = NULL; unsigned char *point_buffer = NULL; size_t pt_buf_len; BN_CTX *bctx = NULL; const char *curveName = NULL; #else EC_KEY *ec_key = NULL; EC_GROUP *ec_group = NULL; #endif LOG("[verify_ec_signature]\n"); if ( data == NULL || pubkey_x == NULL || pubkey_y == NULL || sig_r == NULL || sig_s == NULL ) { ERROR("Error: one or more buffers are not defined.\n"); return false; } if ( hashalg == TPM_ALG_SM3_256 ) { curveId = NID_sm2; mdtype = EVP_sm3(); #if OPENSSL_VERSION_NUMBER >= 0x30000000L curveName = SN_sm2; #endif } else if ( hashalg == TPM_ALG_SHA256 ) { curveId = NID_secp256k1; mdtype = EVP_sha256(); #if OPENSSL_VERSION_NUMBER >= 0x30000000L curveName = SN_secp256k1; #endif } else if ( hashalg == TPM_ALG_SHA384 ) { curveId = NID_secp384r1; mdtype = EVP_sha384(); #if OPENSSL_VERSION_NUMBER >= 0x30000000L curveName = SN_secp384r1; #endif } else { ERROR("Error: unsupported hashalg.\n"); result = 0; goto EXIT; } ec_group = EC_GROUP_new_by_curve_name(curveId); if ( ec_group == NULL ) { ERROR("Error: failed to create new EC group.\n"); goto OPENSSL_ERROR; } x = BN_bin2bn(pubkey_x->data, pubkey_x->size, NULL); y = BN_bin2bn(pubkey_y->data, pubkey_y->size, NULL); if ( x == NULL || y == NULL ) { ERROR("Error: Failed to convert binary pubkey to BIGNUM x and/or y.\n"); goto OPENSSL_ERROR; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L ec_point = EC_POINT_new(ec_group); if ( ec_point == NULL ) { ERROR("Error: failed to create new EC point.\n"); goto OPENSSL_ERROR; } bctx = BN_CTX_new(); if ( bctx == NULL ) { ERROR("Error: Failed to create BIGNUM context.\n"); goto OPENSSL_ERROR; } if ( EC_POINT_set_affine_coordinates(ec_group, ec_point, x, y, bctx) <= 0 ) { ERROR("Error: failed to set affine coordinates.\n"); goto OPENSSL_ERROR; } BN_CTX_free(bctx); bctx = NULL; bctx = BN_CTX_new(); pt_buf_len = EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_COMPRESSED, NULL, 0, bctx); point_buffer = OPENSSL_malloc(pt_buf_len); if ( point_buffer == NULL ) { ERROR("Error: failed to allocate point buffer.\n"); goto OPENSSL_ERROR; } if ( EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_COMPRESSED, point_buffer, pt_buf_len, bctx) <= 0 ) { ERROR("Error: failed to convert EC point into octal string.\n"); goto OPENSSL_ERROR; } EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); if ( ctx == NULL ) { ERROR("Error: failed to initialize key creation CTX.\n"); goto OPENSSL_ERROR; } OSSL_PARAM_BLD *params_build = OSSL_PARAM_BLD_new(); if ( params_build == NULL ) { ERROR("Error: failed to set up parameter builder.\n"); goto OPENSSL_ERROR; } if ( !OSSL_PARAM_BLD_push_utf8_string(params_build, "group", curveName, 0) ) { ERROR("Error: failed to push group into param build.\n"); goto OPENSSL_ERROR; } if ( !OSSL_PARAM_BLD_push_octet_string(params_build, "pub", point_buffer, pt_buf_len) ) { ERROR("Error: failed to push pubkey into param build.\n"); goto OPENSSL_ERROR; } OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(params_build); if ( params == NULL ) { ERROR("Error: failed to construct params from build.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_fromdata_init(ctx) <= 0 ) { ERROR("ERROR: failed to initialize key creation from data.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_fromdata(ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params) <= 0) { ERROR("Error: failed to create EC_KEY.\n"); result = 0; goto EXIT; } OSSL_PARAM_BLD_free(params_build); OSSL_PARAM_free(params); EVP_PKEY_CTX_free(ctx); BN_CTX_free(bctx); #else ec_key = EC_KEY_new(); if (ec_key == NULL) { ERROR("Error: failed to generate EC_KEY.\n"); result = 0; goto EXIT; } evp_key = EVP_PKEY_new(); if (evp_key == NULL) { ERROR("Error: failed to generate EC_KEY.\n"); result = 0; goto EXIT; } if ( EC_KEY_set_group(ec_key, ec_group) <= 0) { ERROR("Failed to set EC Key group.\n"); goto OPENSSL_ERROR; } if ( EC_KEY_set_public_key_affine_coordinates(ec_key, x, y) <= 0) { ERROR("Failed to set key coordinates.\n"); goto OPENSSL_ERROR; } if ( EVP_PKEY_assign_EC_KEY(evp_key, ec_key) <= 0) { ERROR("Error: failed to assign EC KEY to EVP structure.\n"); goto OPENSSL_ERROR; } if (sigalg == TPM_ALG_SM2) { if ( EVP_PKEY_set_alias_type(evp_key, EVP_PKEY_SM2) <= 0 ) { ERROR("Error: failed to set EVP KEY alias to SM2.\n"); goto OPENSSL_ERROR; } } #endif mctx = EVP_MD_CTX_new(); if (mctx == NULL) { ERROR("Error: failed to generate message digest context.\n"); result = 0; goto EXIT; } pctx = EVP_PKEY_CTX_new(evp_key, NULL); if (pctx == NULL) { ERROR("Error: failed to generate key context.\n"); result = 0; goto EXIT; } if (sigalg == TPM_ALG_SM2) { if ( EVP_PKEY_CTX_set1_id(pctx, SM2_ID, SM2_ID_LEN) <= 0 ) { ERROR("Error: failed to set sm2 id.\n"); goto OPENSSL_ERROR; } } EVP_MD_CTX_set_pkey_ctx(mctx, pctx); der_encoded_sig = der_encode_sig_comps(sig_r, sig_s, &encoded_len); if (der_encoded_sig == NULL) { ERROR("Error: failed to DER encode signature components.\n"); result = 0; goto EXIT; } if ( EVP_DigestVerifyInit(mctx, NULL, mdtype, NULL, evp_key) <= 0 ) { ERROR("Error: error while verifying (init).\n"); goto OPENSSL_ERROR; } if ( verbose ) { LOG("Data that was signed:\n"); print_hex(" ", data->data, data->size); } if ( EVP_DigestVerifyUpdate(mctx, data->data, data->size) <= 0) { ERROR("Error: error while verifying (update).\n"); goto OPENSSL_ERROR; } result = EVP_DigestVerifyFinal(mctx, der_encoded_sig, encoded_len); if (result < 0) { ERROR("Error: error while verifying (final)\tError code = %d.\n", result); goto OPENSSL_ERROR; } goto EXIT; OPENSSL_ERROR: ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n",ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); result = 0; EXIT: //cleanup: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (ec_point != NULL) { OPENSSL_free((void *) ec_point); } if (point_buffer != NULL) { OPENSSL_free((void *) point_buffer); } if (curveName != NULL) { OPENSSL_free((void *) curveName); } #else if (ec_key != NULL) { OPENSSL_free((void *) ec_key); } #endif if (ec_group != NULL) { OPENSSL_free((void *) ec_group); } if (evp_key != NULL) { OPENSSL_free((void *) evp_key); } if (x != NULL) { OPENSSL_free((void *) x); } if (y != NULL) { OPENSSL_free((void *) y); } if (der_encoded_sig != NULL) { OPENSSL_free((void *) der_encoded_sig); } if (mctx != NULL) { OPENSSL_free(mctx); } if (pctx != NULL) { OPENSSL_free(pctx); } return result ? true : false; } bool ec_sign_data(sized_buffer *data, sized_buffer *r, sized_buffer *s, uint16_t sigalg, uint16_t hashalg, const char *privkey_file) { /* This function: Performs the signing operation on the policy list data using OpenSSL SM2 and ECDSA functions. In: pointer to data to sign, pointers to buffers for r and s parts (must be BE), sigalg to use (must be TPM_ALG_SM2/ECDSA), hashalg (must be TPM_ALG_SHA256/SHA384/SM3_256) path to private key. Out: True on success, false on failure */ int result; size_t sig_length; EVP_PKEY *evp_key = NULL; EVP_MD_CTX *mctx = NULL; EVP_PKEY_CTX *pctx = NULL; FILE *fp = NULL; ECDSA_SIG *ecdsa_sig = NULL; const BIGNUM *sig_r = NULL; //Is freed when ECDSA_SIG is freed const BIGNUM *sig_s = NULL; //Is freed when ECDSA_SIG is freed const unsigned char *signature_block = NULL; #if OPENSSL_VERSION_NUMBER < 0x30000000L EC_KEY *ec_key = NULL; #endif LOG("[ec_sign_data]\n"); if (data == NULL || r == NULL || s == NULL) { ERROR("Error: one or more data buffers not defined.\n"); return false; } mctx = EVP_MD_CTX_new(); if (mctx == NULL) { ERROR("Error: failed to allocate message digest context.\n"); goto OPENSSL_ERROR; } fp = fopen(privkey_file, "rb"); if ( fp == NULL ) { ERROR("Error: failed to open file %s: %s\n", privkey_file, strerror(errno)); result = 0; goto EXIT; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L OSSL_DECODER_CTX *dctx; dctx = OSSL_DECODER_CTX_new_for_pkey(&evp_key, "PEM", NULL, "EC", OSSL_KEYMGMT_SELECT_PRIVATE_KEY, NULL, NULL); if ( dctx == NULL ) { goto OPENSSL_ERROR; } if ( !OSSL_DECODER_from_fp(dctx, fp) ) { goto OPENSSL_ERROR; } OSSL_DECODER_CTX_free(dctx); #else ec_key = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL); if (ec_key == NULL) { ERROR("Error: failed to allocate EC key.\n"); goto OPENSSL_ERROR; } evp_key = EVP_PKEY_new(); if (evp_key == NULL) { ERROR("Error: failed to allocate EVP key.\n"); goto OPENSSL_ERROR; } result = EVP_PKEY_assign_EC_KEY(evp_key, ec_key); if (result <= 0) { ERROR("Error: failed to assign EC key to EVP structure.\n"); goto OPENSSL_ERROR; } if (sigalg == TPM_ALG_SM2) { result = EVP_PKEY_set_alias_type(evp_key, EVP_PKEY_SM2); if (result <= 0) { ERROR("Error: failed to assign SM2 alias to EVP key.\n"); goto OPENSSL_ERROR; } } #endif fclose(fp); fp = NULL; pctx = EVP_PKEY_CTX_new(evp_key, NULL); if (pctx == NULL) { ERROR("Error: failed to allocate pkey context.\n"); goto OPENSSL_ERROR; } if (sigalg == TPM_ALG_SM2) { result = EVP_PKEY_CTX_set1_id(pctx, SM2_ID, SM2_ID_LEN); if (result <= 0) { ERROR("Error: failed to allocate SM2 id.\n"); goto OPENSSL_ERROR; } } EVP_MD_CTX_set_pkey_ctx(mctx, pctx); switch (hashalg) { case TPM_ALG_SM3_256: result = EVP_DigestSignInit(mctx, &pctx, EVP_sm3(), NULL, evp_key); break; case TPM_ALG_SHA256: result = EVP_DigestSignInit(mctx, &pctx, EVP_sha256(), NULL, evp_key); break; case TPM_ALG_SHA384: result = EVP_DigestSignInit(mctx, &pctx, EVP_sha384(), NULL, evp_key); break; default: ERROR("Error: unsupported hashalg.\n"); return false; } if (result <= 0) { ERROR("Error: failed to initialize signature.\n"); goto OPENSSL_ERROR; } result = EVP_DigestSignUpdate(mctx, data->data, data->size); if (result <= 0) { ERROR("Error: failed to update signature.\n"); goto OPENSSL_ERROR; } // Dry run, calculate length: result = EVP_DigestSignFinal(mctx, NULL, &sig_length); if (result <= 0 ) { ERROR("Error: failed to comp=ute signature length.\n"); goto OPENSSL_ERROR; } signature_block = OPENSSL_malloc(sig_length); if (signature_block == NULL) { ERROR("Error: failed to allocate signature block.\n"); goto OPENSSL_ERROR; } result = EVP_DigestSignFinal(mctx, (unsigned char *) signature_block, &sig_length); if (result <= 0) { ERROR("Error: failed to comp=ute signature length.\n"); goto OPENSSL_ERROR; } // signature_block is DER encoded, we decode it: ecdsa_sig = d2i_ECDSA_SIG(NULL, &signature_block, sig_length); if (ecdsa_sig == NULL) { ERROR("Error: failed to decode signature.\n"); goto OPENSSL_ERROR; } sig_r = ECDSA_SIG_get0_r(ecdsa_sig); sig_s = ECDSA_SIG_get0_s(ecdsa_sig); if (sig_r == NULL || sig_s == NULL ) { ERROR("Error: failed to extract signature components.\n"); goto OPENSSL_ERROR; } BN_bn2bin(sig_r, r->data); BN_bn2bin(sig_s, s->data); goto EXIT; OPENSSL_ERROR: DISPLAY("Error.\n"); ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); result = 0; EXIT: #if OPENSSL_VERSION_NUMBER < 0x30000000L if (ec_key != NULL) { OPENSSL_free((void *) ec_key); } #endif if (evp_key != NULL) { OPENSSL_free((void *) evp_key); } if (mctx != NULL) { OPENSSL_free((void *) mctx); } if (pctx != NULL) { OPENSSL_free((void *) pctx); } if (fp != NULL) { fclose(fp); } if (ecdsa_sig != NULL) { ECDSA_SIG_free(ecdsa_sig); } return result ? true : false; } EVP_PKEY_CTX *rsa_get_sig_ctx(const char *key_path, uint16_t key_size_bytes) { FILE *fp = NULL; EVP_PKEY *evp_priv = NULL; EVP_PKEY_CTX *context = NULL; //This will be returned LOG("[rsa_get_sig_ctx]\n"); fp = fopen(key_path, "r"); if (fp == NULL) goto ERROR; evp_priv = PEM_read_PrivateKey(fp, NULL, NULL, NULL); if (evp_priv == NULL) goto OPENSSL_ERROR; fclose(fp); fp = NULL; if (EVP_PKEY_size(evp_priv) != key_size_bytes) { ERROR("ERROR: key size incorrect\n"); goto ERROR; } context = EVP_PKEY_CTX_new(evp_priv, NULL); if (context == NULL) goto OPENSSL_ERROR; OPENSSL_free(evp_priv); return context; OPENSSL_ERROR: ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); ERROR: if (fp != NULL) fclose(fp); if (evp_priv != NULL) OPENSSL_free(evp_priv); if (context != NULL) OPENSSL_free(context); return NULL; } bool rsa_ssa_pss_sign(sized_buffer *signature_block, sized_buffer *data_to_sign, uint16_t sig_alg, uint16_t hash_alg, EVP_PKEY_CTX *private_key_context) /* This function: signs data using rsa private key context In: pointer to a correctly sized buffer to hold signature block, digest of lcp list data, hash alg used to hash data, Openssl private key context Out: true on success, false on failure. Also signature_block gets signature block data */ { LOG("[rsa_ssa_pss_sign]\n"); int result; //For openssl return codes size_t siglen; //Holds length of signature returned by openssl must be 256 or 384 const EVP_MD *evp_hash_alg; if (signature_block == NULL || data_to_sign == NULL || private_key_context == NULL) { ERROR("Error: one or more data buffers is not defined.\n"); return false; } //Init sig result = EVP_PKEY_sign_init(private_key_context); if (result <= 0) { goto OPENSSL_ERROR; } //Set padding if (sig_alg == TPM_ALG_RSASSA || sig_alg == LCP_POLSALG_RSA_PKCS_15) { result = EVP_PKEY_CTX_set_rsa_padding(private_key_context, RSA_PKCS1_PADDING); } else if (sig_alg == TPM_ALG_RSAPSS) { result = EVP_PKEY_CTX_set_rsa_padding(private_key_context, RSA_PKCS1_PSS_PADDING); } else { ERROR("ERROR: unsupported signature algorithm.\n"); return false; } if (result <= 0) { goto OPENSSL_ERROR; } if (sig_alg == TPM_ALG_RSAPSS) { result = EVP_PKEY_CTX_set_rsa_pss_saltlen(private_key_context, -1); if (result <= 0) { goto OPENSSL_ERROR; } } switch (hash_alg) { case LCP_POLHALG_SHA1: //Legacy value for TPM 1.2 evp_hash_alg = EVP_sha1(); break; case TPM_ALG_SHA1: evp_hash_alg = EVP_sha1(); break; case TPM_ALG_SHA256: evp_hash_alg = EVP_sha256(); break; case TPM_ALG_SHA384: evp_hash_alg = EVP_sha384(); break; default: ERROR("Unsupported hash alg.\n"); return false; } //Set signature md parameter result = EVP_PKEY_CTX_set_signature_md(private_key_context, evp_hash_alg); if (result <= 0) { goto OPENSSL_ERROR; } //Calculate signature size (dry run) result = EVP_PKEY_sign(private_key_context, NULL, &siglen, data_to_sign->data, get_lcp_hash_size(hash_alg)); if (result <= 0) { goto OPENSSL_ERROR; } if (siglen != signature_block->size) { ERROR("ERROR: signature size incorrect.\n"); return false; } //Do the signing result = EVP_PKEY_sign(private_key_context, signature_block->data, &siglen, data_to_sign->data, get_lcp_hash_size(hash_alg)); if (result <= 0) { goto OPENSSL_ERROR; } //All good, function end return true; //Error handling OPENSSL_ERROR: ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); return false; } uint16_t pkcs_get_hashalg(const unsigned char *data) /* From: http://mpqs.free.fr/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp_EMC_Corporation_Public-Key_Cryptography_Standards_(PKCS).pdf#page=40 EM=00∥01∥FF∥…∥FF∥00∥T - PKCS1.5 padding starts with 00 01 || 0xFF for padding || 00 || T - this is the DER encoded hash identifier and hash message T - SHA-1: 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 ∥ H T - SHA-256: 30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ∥ H T - SHA-384: 30 41 30 0D 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 ∥ H T - SHA-512: 30 51 30 0D 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 ∥ H E.g. SHA-256 30 31 - sequence 0x31 bytes 30 0D - sequence 0x0D bytes 06 09 - OID (object ID) - 9 bytes 60 86 48 01 65 03 04 02 01 - OID: SHA-256: FIPS180-3 05 00 - parameters and size 04 20 - octet of strings size 0x20 bytes H - hash of a secret message */ { uint8_t der_oid = 0x06; size_t oid_size; if (data == NULL) { return TPM_ALG_NULL; } data += 2; //Skip 00 01 //Skip 0xFFs padding and 00 after it do { data++; } while (*data == 0xFF); //Then move to der_oid data += 5; if (*data != der_oid) { return TPM_ALG_NULL; } data += 1; //Read oid size: oid_size = *data; if (oid_size == 0x05) return TPM_ALG_SHA1; //Only Sha1 has this size //Move to the last byte to see what alg is used data += oid_size; switch (*data) { case 0x01: return TPM_ALG_SHA256; case 0x02: return TPM_ALG_SHA384; case 0x03: return TPM_ALG_SHA512; default: return TPM_ALG_NULL; } } void buffer_reverse_byte_order(uint8_t *buffer, size_t length) /*Works in place, modifies passed buffer*/ { uint8_t temp; int left_index = 0; int right_index = length - 1; while (right_index > left_index) { temp = buffer[right_index]; buffer[right_index] = buffer[left_index]; buffer[left_index] = temp; left_index++; right_index--; } } sized_buffer *allocate_sized_buffer(size_t size) { /* Allocate size bytes of memory for a buffer and return it or NULL on failure. */ sized_buffer *buffer = NULL; if (size == 0) { ERROR("Error: buffer size must be at least 1.\n"); return NULL; } buffer = malloc(size + offsetof(sized_buffer, data)); if (buffer == NULL) { ERROR("Error: failed to allocate buffer.\n"); return NULL; } return buffer; } unsigned char *der_encode_sig_comps(sized_buffer *sig_r, sized_buffer *sig_s, int *length) { //Buffers for signature (will be passed to EVP_Verify): unsigned char *der_encoded_sig = NULL; unsigned char *helper_ptr = NULL; //Will be adjusted by openssl api - orig value + sigsize ECDSA_SIG *sig = NULL; BIGNUM *r; BIGNUM *s; int encoded_size = 0; LOG("[der_encode_sig_comps]\n"); r = BN_bin2bn(sig_r->data, sig_r->size, NULL); s = BN_bin2bn(sig_s->data, sig_s->size, NULL); if (r == NULL || s == NULL) { ERROR("Error: failed to allocate signature componenst.\n"); goto EXIT; } sig = ECDSA_SIG_new(); if (sig == NULL) { ERROR("Error: failed to allocate signature structure.\n"); goto EXIT; } if (!ECDSA_SIG_set0(sig, r, s)) { ERROR("Error: failed to set signature components.\n"); goto EXIT; } encoded_size = i2d_ECDSA_SIG(sig, NULL); if (!encoded_size) { ERROR("Error: failed to calculate the size of encoded buffer.\n"); goto EXIT; } helper_ptr = OPENSSL_malloc(encoded_size); der_encoded_sig = helper_ptr; *length = encoded_size; //i2d_ECDSA_SIG changes value of the pointer passed, that's why we first assigned //it to der_encoded_sig, which will hold the encoded_sig. if (!i2d_ECDSA_SIG(sig, &helper_ptr)) { ERROR("Error: failed to encode signature.\n"); return NULL; } EXIT: if (sig != NULL) { ECDSA_SIG_free(sig); //SIG_free also frees r and s r = NULL; s = NULL; } if (r != NULL) { OPENSSL_free((void *) r); } if (s != NULL) { OPENSSL_free((void *) s); } return der_encoded_sig; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/lcputils.h0000644000000000000000000001117614210363175015257 0ustar 00000000000000/* * lcputils.h: LCP utility fns * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __LCPUTILS_H__ #define __LCPUTILS_H__ #define MAJOR_VER(v) ((v) >> 8) #define MINOR_VER(v) ((v) & 0xff) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define MAX_PATH 256 #include //Helper struct to pass user input data to functions in pollist2 and pollist2_1 typedef struct sign_user_input { uint16_t sig_alg; uint16_t hash_alg; uint16_t rev_ctr; char list_file[MAX_PATH]; char pubkey_file[MAX_PATH]; char privkey_file[MAX_PATH]; } sign_user_input; /* This will hold various dynamic buffers like keys, sigs, digests and such. */ typedef struct sized_buffer { size_t size; unsigned char data[]; } sized_buffer; extern bool verbose; extern void ERROR(const char *fmt, ...); extern void LOG(const char *fmt, ...); extern void DISPLAY(const char *fmt, ...); extern size_t strlcpy(char *dst, const char *src, size_t siz); extern void print_hex(const char *prefix, const void *data, size_t n); extern void parse_comma_sep_ints(char *s, uint16_t ints[], unsigned int *nr_ints); extern void *read_file(const char *file, size_t *length, bool fail_ok); extern bool write_file(const char *file, const void *data, size_t size); extern bool parse_line_hashes(const char *line, tb_hash_t *hash, uint16_t alg); extern bool parse_file(const char *filename, bool (*parse_line)(const char *line)); extern const char *hash_alg_to_str(uint16_t alg); extern const char *key_alg_to_str(uint16_t alg); extern const char *sig_alg_to_str(uint16_t alg); extern sized_buffer *allocate_sized_buffer(size_t size); uint16_t str_to_hash_alg(const char *str); uint16_t str_to_lcp_hash_mask(const char *str); uint16_t convert_hash_alg_to_mask(uint16_t hash_alg); uint16_t str_to_sig_alg(const char *str); uint32_t str_to_sig_alg_mask(const char *str, const uint16_t version, size_t size); uint16_t str_to_pol_ver(const char *str); size_t get_lcp_hash_size(uint16_t hash_alg); extern void buffer_reverse_byte_order(uint8_t *buffer, size_t length); extern bool ec_sign_data(sized_buffer *data, sized_buffer *r, sized_buffer *s, uint16_t hashalg, uint16_t sigalg, const char *privkey_file); extern bool rsa_ssa_pss_sign(sized_buffer *sig_block, sized_buffer *data, uint16_t sig_alg, uint16_t hash_alg, EVP_PKEY_CTX *private_key_context); bool verify_ec_signature(sized_buffer *data, sized_buffer *pubkey_x, sized_buffer *pubkey_y, sized_buffer *sig_r, sized_buffer *sig_s, uint16_t sigalg, uint16_t hashalg); bool verify_rsa_signature(sized_buffer *data, sized_buffer *pubkey, sized_buffer *signature, uint16_t hashAlg, uint16_t sig_alg, uint16_t list_ver); EVP_PKEY_CTX *rsa_get_sig_ctx(const char *key_path, uint16_t key_size_bytes); unsigned char *der_encode_sig_comps(sized_buffer *sig_r, sized_buffer *sig_s, int *length); #endif /* __LCPUTILS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/mle_elt.c0000644000000000000000000001271414210363175015033 0ustar 00000000000000/* * mle_elt.c: MLE2 policy element (LCP_MLE_ELEMENT2) plugin * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define MAX_HASHES 32 static uint8_t sinit_min_version; static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static char alg_name[32] = "sha1"; static uint16_t alg_type = TPM_ALG_SHA1; static bool parse_mle_line(const char *line) { if ( nr_hashes == MAX_HASHES ) return false; return parse_line_hashes(line, &hashes[nr_hashes++], alg_type); } static bool cmdline_handler(int c, const char *opt) { if ( c == 'm' ) { sinit_min_version = (uint8_t)strtoul(opt, NULL, 0); LOG("cmdline opt: sinit_min_version: 0x%x\n", sinit_min_version); return true; } else if (c == 'a') { strlcpy(alg_name, opt,sizeof(alg_name)); alg_type = str_to_hash_alg(alg_name); LOG("cmdline opt: hash alg: %s\n",alg_name); return true; } else if ( c != 0 ) { ERROR("Error: unknown option for mle type\n"); return false; } /* MLE hash files */ LOG("cmdline opt: mle hash file: %s\n", opt); if ( !parse_file(opt, parse_mle_line) ) return false; return true; } static lcp_policy_element_t *create(void) { LOG("[create]\n"); size_t data_size = sizeof(lcp_mle_element_t2) + nr_hashes * get_hash_size(alg_type); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset_s(elt, sizeof(*elt) + data_size, 0); elt->size = sizeof(*elt) + data_size; lcp_mle_element_t2 *mle = (lcp_mle_element_t2 *)&elt->data; mle->sinit_min_version = sinit_min_version; mle->hash_alg = alg_type; mle->num_hashes = nr_hashes; lcp_hash_t2 *hash = mle->hashes; for ( unsigned int i = 0; i < nr_hashes; i++ ) { memcpy_s(hash, get_hash_size(alg_type), &hashes[i], get_hash_size(alg_type)); hash = (void *)hash + get_hash_size(alg_type); } LOG("create mle element succeed!\n"); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_mle_element_t2 *mle = (lcp_mle_element_t2 *)elt->data; DISPLAY("%s sinit_min_version: 0x%x\n", prefix, mle->sinit_min_version); DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(mle->hash_alg)); DISPLAY("%s num_hashes: %u\n", prefix, mle->num_hashes); uint8_t *hash = (uint8_t *)&mle->hashes; unsigned int hash_size = get_hash_size(mle->hash_alg); for ( unsigned int i = 0; i < mle->num_hashes; i++ ) { DISPLAY("%s hashes[%u]: ", prefix, i); print_hex("", hash, hash_size); hash += hash_size; } } static struct option opts[] = { {"minver", required_argument, NULL, 'm'}, {"alg", required_argument, NULL, 'a'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "mle2", opts, " mle2\n" " Creates current LCP_ELEMENT_MLE2. Supports algorithm agility.\n" " [--minver ] minimum version of SINIT\n" " [--alg ] hash alg of element\n" " [FILE2] ... one or more files containing MLE\n" " hash(es); each file can contain\n" " multiple hashes\n", LCP_POLELT_TYPE_MLE2, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/mle_elt_legacy.c0000644000000000000000000001250214210363175016352 0ustar 00000000000000/* * mle_elt_legacy.c: MLE policy element (LCP_MLE_ELEMENT) plugin * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define MAX_HASHES 32 static uint8_t sinit_min_version; static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static uint16_t alg_type = LCP_POLHALG_SHA1; //Legacy value for TPM 1.2 static bool parse_mle_line(const char *line) { bool result; if ( nr_hashes == MAX_HASHES ) return false; result = parse_line_hashes(line, &hashes[nr_hashes++], alg_type); if (!result) { DISPLAY("Legacy mle element only supports sha1 hash digests.\n"); } return result; } static bool cmdline_handler(int c, const char *opt) { if ( c == 'm' ) { sinit_min_version = (uint8_t)strtoul(opt, NULL, 0); LOG("cmdline opt: sinit_min_version: 0x%x\n", sinit_min_version); return true; } else if ( c != 0 ) { ERROR("Error: unknown option for mle type\n"); return false; } /* MLE hash files */ LOG("cmdline opt: mle hash file: %s\n", opt); if ( !parse_file(opt, parse_mle_line) ) return false; return true; } static lcp_policy_element_t *create(void) { LOG("[create]\n"); size_t data_size; lcp_policy_element_t *elt = NULL; lcp_mle_element_t *mle = NULL; lcp_hash_t *hash = NULL; data_size = sizeof(lcp_mle_element_t) + (nr_hashes * SHA1_DIGEST_SIZE); elt = calloc(1, sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } elt->size = sizeof(*elt) + data_size; mle = (lcp_mle_element_t *) &elt->data; mle->sinit_min_version = sinit_min_version; mle->hash_alg = LCP_POLHALG_SHA1; //Legacy value for TPM 1.2 mle->num_hashes = nr_hashes; hash = mle->hashes; for (uint16_t i = 0; i < nr_hashes; i++) { memcpy_s(hash, (nr_hashes - i) * SHA1_DIGEST_SIZE, &hashes[i], SHA1_DIGEST_SIZE); hash = (void *) hash + SHA1_DIGEST_SIZE; } LOG("Create legacy mle element success.\n"); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_mle_element_t *mle = (lcp_mle_element_t *)elt->data; DISPLAY("%s sinit_min_version: 0x%x\n", prefix, mle->sinit_min_version); DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(mle->hash_alg)); DISPLAY("%s num_hashes: %u\n", prefix, mle->num_hashes); uint8_t *hash = (uint8_t *)&mle->hashes; for ( unsigned int i = 0; i < mle->num_hashes; i++ ) { DISPLAY("%s hashes[%u]: ", prefix, i); print_hex("", hash, SHA1_DIGEST_SIZE); DISPLAY("\n"); hash += SHA1_DIGEST_SIZE; } } static struct option opts[] = { {"minver", required_argument, NULL, 'm'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "mle", opts, " mle\n" " Creates legacy LCP_ELEMENT_MLE. Only supports sha1.\n" " [--minver ] minimum version of SINIT\n" " [FILE2] ... one or more files containing MLE\n" " hash(es); each file can contain\n" " multiple hashes\n", LCP_POLELT_TYPE_MLE, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/mlehash.c0000644000000000000000000003442114210363175015032 0ustar 00000000000000/* * mlehash.c: tool to determine the hash of a Intel(R) TXT MLE * * Copyright (c) 2006-2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "../include/elf_defns.h" #include "../include/mle.h" #include "lcputils.h" #define TOOL_VER_MAJOR 0x1 #define TOOL_VER_MINOR 0x1 #define MAX_HELP_TEXT 4096 static char help[MAX_HELP_TEXT] = "Usage: lcp2_mlehash [OPTION]\n" "Create an Intel(R) TXT policy mlehash.\n" "--create\n" " --cmdline cmdline\n" " --alg hashalg " "--help print out help message\n" "--verbose display progress indications.\n" "--version show tool version.\n"; bool verbose = false; char alg_name[32] = "sha256"; uint16_t alg_type = TPM_ALG_SHA256; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"version", no_argument, NULL, 'V'}, {"create", no_argument, NULL, 'C'}, /* options */ {"cmdline", required_argument, NULL, 'c'}, {"alg", required_argument, NULL, 'a'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; /* * is_elf_image * * check an image is elf or not? * */ static bool is_elf_image(const void *image, const size_t size) { LOG("[is_elf_image]\n"); elf_header_t *elf; LOG("checking whether image is an elf image ... "); if ( image == NULL ) { LOG(": failed! - Pointer is zero.\n"); return false; } /* check size */ if ( sizeof(elf_header_t) > size ) { LOG(": failed! - Image size is smaller than ELF header size.\n"); return false; } elf = (elf_header_t *)image; /* check magic number for ELF */ if (( elf->e_ident[EI_MAG0] != ELFMAG0 ) || ( elf->e_ident[EI_MAG1] != ELFMAG1 ) || ( elf->e_ident[EI_MAG2] != ELFMAG2 ) || ( elf->e_ident[EI_MAG3] != ELFMAG3 )) { LOG(": failed! - ELF magic number is not matched.\n"); return false; } /* check data encoding in ELF */ if ( elf->e_ident[EI_DATA] != ELFDATA2LSB ) { LOG(": failed! - ELF data encoding is not the least significant " "byte occupying the lowest address.\n"); return false; } /* check ELF image is executable? */ if ( elf->e_type != ET_EXEC ) { LOG(": failed! - ELF image is not executable.\n"); return false; } /* check ELF image is for IA? */ if ( elf->e_machine != EM_386 ) { LOG(": failed! - ELF image is not for IA.\n"); return false; } /* check ELF version is valid? */ if ( elf->e_version != EV_CURRENT ) { LOG(": failed! - ELF version is invalid.\n"); return false; } if ( sizeof(elf_program_header_t) > elf->e_phentsize ) { LOG(": failed! - Program size is smaller than program " "header size.\n"); return false; } LOG(": succeeded!\n"); return true; } static bool get_elf_image_range(const elf_header_t *elf, void **start, void **end) { LOG("[get_elf_image_range]\n"); int i; unsigned long u_start, u_end; if (elf == NULL) { LOG("Error: ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ if ((start == NULL) || (end == NULL)) { LOG("Error: Output pointers are zero.\n"); return false; } u_start = 0; u_end = 0; for (i = 0; i < elf->e_phnum; i++) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if (ph->p_type == PT_LOAD) { if (u_start > ph->p_paddr) u_start = ph->p_paddr; if (u_end < ph->p_paddr+ph->p_memsz) u_end = ph->p_paddr+ph->p_memsz; } } if (u_start >= u_end) { *start = NULL; *end = NULL; return false; } else { *start = (void *)u_start; *end = (void *)u_end; LOG("get range succeed!\n"); return true; } } /* * * expand entire file into memory * */ static bool expand_elf_image(const elf_header_t *elf, void *base, size_t size) { int i; LOG("[expand_elf_image]\n"); LOG("expanding elf image ... "); if ( elf == NULL ) { LOG(": failed! - ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ /* load elf image into memory */ for (i = 0; i < elf->e_phnum; i++) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if (ph->p_type == PT_LOAD) { if ( ph->p_memsz > size ) { LOG("expanded image exceeded allocated size\n"); return false; } memcpy_s(base, size, (void *)elf + ph->p_offset, ph->p_filesz); memset_s(base + ph->p_filesz, ph->p_memsz - ph->p_filesz, 0); base += ph->p_memsz; size -= ph->p_memsz; } } LOG(": succeeded!.\n"); return true; } /* * print_dump * * dump the memory * */ #if 0 #define log_info(fmt, ...) verbose ? printf(fmt, ##__VA_ARGS__) : 0 static void print_dump(uint32_t s, uint32_t e) { uint32_t i,j; unsigned char* p; for ( i = s, j = 0; i < e; i++, j++ ) { p = (unsigned char*)i; log_info("%02x ", *p); if ( j % 20 == 0 ) log_info("\n"); } log_info("\n"); } #endif /* * read_mle_file * * read file from disk, if compressed, uncompress it * */ static bool read_mle_file(const char *filename, void **buffer, size_t *length) { LOG("[read_mle_file]\n"); gzFile fcompressed = NULL; FILE *fdecompressed = NULL; struct stat filestat; char tmpbuffer[1024]; unsigned long i; *length = 0; *buffer = NULL; /* check the file exists or not */ LOG("checking whether the file exists or not ... "); if ( stat(filename, &filestat)) goto error; LOG(": existed!\n"); /* try uncompress the file (gzopen will handle uncompressed files too) */ LOG("trying to uncompress the file ... "); fcompressed = gzopen(filename, "rb"); if ( !fcompressed ) { LOG(": failed!\n"); return false; } LOG(": succeeded!\n"); LOG("creating a temporary file to uncompress ... "); fdecompressed = tmpfile(); if ( !fdecompressed ) goto error; LOG(": succeeded!\n"); LOG("opening the decompressed file ... "); while ( !gzeof(fcompressed) ) { i = gzread(fcompressed, tmpbuffer, 1024); *length += i; if ( fwrite(tmpbuffer, 1, i, fdecompressed) != i ) goto error; } LOG(": succeeded!\n"); gzclose(fcompressed); fcompressed = NULL; LOG("testing decompression is ... "); if ( *length <= 0 ) goto error; LOG(": succeeded!\n"); /* uncompression succeeded */ fseek(fdecompressed, 0, SEEK_SET); /* read file into buffer */ LOG("reading the decompressed file ... "); *buffer = malloc(*length); if ( *buffer == NULL ) goto error; memset_s(*buffer, *length, 0); if ( fread(*buffer, 1, *length, fdecompressed) != *length ) goto error2; fclose(fdecompressed); LOG(": succeeded!\n"); return true; error: if ( *buffer ) free( *buffer ); error2: LOG(": failed!\n"); if ( fcompressed ) gzclose(fcompressed); if ( fdecompressed ) fclose(fdecompressed); return false; } static mle_hdr_t *find_mle_hdr(void *start, size_t size) { LOG("[find_mle_hdr]\n"); void *end; end = start + size - sizeof(uuid_t); while ( start <= end ) { if ( are_uuids_equal((const uuid_t *)start, &((uuid_t)MLE_HDR_UUID)) ){ LOG("find mle hdr succeed!\n"); return (mle_hdr_t *)start; } start += sizeof(uuid_t); } return NULL; } /* * main */ int main(int argc, char* argv[]) { void *elf_start=NULL, *elf_end=NULL; void *exp_start=NULL; void *base=NULL; size_t size, exp_size; elf_header_t *base_as_elf; mle_hdr_t *mle_hdr; int c, ret = 1; char mle_file[MAX_PATH] = ""; extern int optind; /* current index of get_opt() */ char *cmdline = NULL; bool prev_cmd = false; int cmd = 0; while ((c = getopt_long_only(argc, (char ** const)argv, "", long_opts, NULL)) != -1) { switch (c) { case 'H': case 'C': case 'V': if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 'c': cmdline = malloc(strnlen_s(optarg, 4096) + 1); if ( cmdline == NULL ) { printf("Out of memory\n"); return 1; } strcpy_s(cmdline, strnlen_s(optarg, 4096) + 1, optarg); break; case 'a': strlcpy(alg_name, optarg, sizeof(alg_name)); LOG("cmdline opt: alg: %s\n",alg_name); break; case 0: case -1: break; default: printf("Unknown command line option\n"); break; } } if ( optind < argc ) { LOG("cmdline opt: mlefile:%s\n", argv[optind]); strlcpy(mle_file,argv[optind],sizeof(mle_file)); } if ( cmd == 0 ) { ERROR("Error: no command was specified\n"); goto out; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); ret = 0; goto out; } else if ( cmd == 'C' ) { if ( *mle_file == '\0' ) { ERROR("Error: no output file specified\n"); goto out; } alg_type = str_to_hash_alg(alg_name); /* read file */ if ( !read_mle_file(mle_file, &base, &size) ) goto out; /* expand image */ if ( !is_elf_image(base, size) ) goto out; base_as_elf = (elf_header_t *)base; /* get expanded size and allocate memory for it */ if ( !get_elf_image_range(base_as_elf, &elf_start, &elf_end) ) goto out; exp_size = elf_end - elf_start; exp_start = malloc(exp_size); if ( exp_start == NULL ) { LOG("not enough memory for expanded image\n"); goto out; } /* expand the image */ if ( !expand_elf_image(base_as_elf, exp_start, exp_size) ) goto out; /* find the MLE header in the expanded image */ mle_hdr = find_mle_hdr(exp_start, exp_size); if ( mle_hdr == NULL ) { LOG("no MLE header found in image\n"); goto out; } /* before hashing, find command line area in MLE then zero-fill and copy command line param to it */ if ( mle_hdr->cmdline_end_off > mle_hdr->cmdline_start_off && cmdline != NULL ) { memset_s(exp_start + mle_hdr->cmdline_start_off, mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off, '\0'); strcpy_s(exp_start + mle_hdr->cmdline_start_off, mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off, cmdline); } /* hash the MLE portion of the image */ LOG("begin to hash (%s) the mle portion of the image\n", alg_name); size_t hash_size = mle_hdr->mle_end_off - mle_hdr->mle_start_off; void *hash_buf = exp_start + mle_hdr->mle_start_off; lcp_hash_t2 *hash = malloc(sizeof(lcp_hash_t2)); hash_buffer(hash_buf, hash_size, (tb_hash_t *)hash, alg_type); print_hash((tb_hash_t *)hash, alg_type); } else if ( cmd == 'V' ) /* --version */ { DISPLAY("lcp2_mlehash version: %i.%i\nBuild date: %s", TOOL_VER_MAJOR, TOOL_VER_MINOR, __DATE__); ret = 0; goto out; } ret = 0; out: if (cmdline) free(cmdline); if (base) free(base); if (exp_start) free(exp_start); return ret; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pconf2_elt.c0000644000000000000000000002262514210363175015447 0ustar 00000000000000/* * PCONF2 policy element (LCP_PCONF_ELEMENT2) plugin * * Copyright (c) 2020 Cisco Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" struct pcr_data { uint16_t alg; struct { bool valid; tb_hash_t value; } pcr[8]; }; static struct pcr_data pcrs; static bool cmdline_handler(int c, const char *opt) { int pcr; switch (c) { case 'a': /* hash algorithm */ pcrs.alg = str_to_hash_alg(opt); if (pcrs.alg == TPM_ALG_NULL) { ERROR("Error: invalid hash algorithm\n"); return false; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': pcr = c - '0'; /* convert the hash value into a tb_hash_t */ if (!import_hash(opt, &pcrs.pcr[pcr].value, pcrs.alg)) { ERROR("Error: unable to parse the hash value\n"); return false; } /* mark the pcr as valid for the pconf element and cleanup */ pcrs.pcr[pcr].valid = true; break; default: /* invalid arg */ return false; } return true; } static lcp_policy_element_t *create(void) { unsigned int iter_a, iter_b; unsigned int pcr_count; size_t pcr_alg_size; size_t tpml_select_size; tpms_pcr_selection_t *tpms_select; tpml_pcr_selection_t *tpml_select = NULL; size_t pcr_comp_size; uint8_t *pcr_comp = NULL; size_t pcr_digest_size; tpm2b_digest_t *pcr_digest = NULL; uint8_t *tpm_quote; size_t pconf_size; lcp_pconf_element_t2 *pconf; size_t elt_size; lcp_policy_element_t *elt = NULL; /* NOTE: the intel txt sdk isn't very good when it comes to the pconf * policy element format so we are basing much of this code on the * lcp-gen2 python code */ /* NOTE: this whole function could be written much better, but it was * hacked on quite a bit while i was trying to get a valid pconf * that the acm would accept */ /* sanity checks */ pcr_count = 0; for (iter_a = 0; iter_a <= 7; iter_a++) { if (pcrs.pcr[iter_a].valid) pcr_count++; } if (pcr_count == 0) { ERROR("Error: no PCRs specified for the pconf element\n"); goto err; } if (pcrs.alg == 0) { /* do we want to default to sha1 instead of error? */ ERROR("Error: no PCR has algorithm specified\n"); goto err; } pcr_alg_size = get_hash_size(pcrs.alg); /* generate a TPMS_PCR_SELECTION and TPML_PCR_SELECTION */ tpml_select_size = sizeof(*tpml_select) + 3; /* 24 pcrs */ tpml_select = malloc(tpml_select_size); if (!tpml_select) { ERROR("Error: failed to allocate a TPMS_PCR_SELECTION\n"); goto err; } tpml_select->count = htonl(1); /* txt requries this to be 1 */ tpms_select = &tpml_select->pcr_selections; tpms_select->hash_alg = htons(pcrs.alg); tpms_select->size_of_select = 3; memset(tpms_select->pcr_select, 0x00, 3); for (iter_a = 0; iter_a <= 7; iter_a++) { /* TODO: why is this pcr_select[0] and not pcr_select[2]? python * oddity? txt spec oddity? endian issue? */ if (pcrs.pcr[iter_a].valid) tpms_select->pcr_select[0] |= (0x01 << iter_a); } /* generate a pcr composite */ pcr_comp_size = pcr_alg_size * pcr_count; pcr_comp = malloc(pcr_comp_size); if (!pcr_comp) { ERROR("Error: failed to allocate a PCR composite buffer\n"); goto err; } for (iter_a = 0, iter_b = 0; iter_a < 7 && iter_b < pcr_count; iter_a++) { if (pcrs.pcr[iter_a].valid) { memcpy(&pcr_comp[iter_b * pcr_alg_size], &pcrs.pcr[iter_a].value, pcr_alg_size); iter_b++; } } /* generate a TPM2B_DIGEST using the pcr composite */ /* TODO: not sure if this is correct, but reuse the pcr hash alg */ pcr_digest_size = sizeof(*pcr_digest) + pcr_alg_size; pcr_digest = malloc(pcr_digest_size); if (!pcr_digest) { ERROR("Error: failed to allocate a TPM2B_DIGEST\n"); goto err; } pcr_digest->size = htons(pcr_alg_size); if (!hash_buffer((void *)pcr_comp, pcr_comp_size, (void *)pcr_digest->buffer, pcrs.alg)) { ERROR("Error: TPM2B_DIGEST hash operation failed\n"); goto err; } /* generate TPMS_QUOTE_INFO, LCP_PCONF_ELEMENT2, and LCP_POLICY_ELEMENT */ /* NOTE: we can't use tpms_quote_info_t since both fields are variable */ pconf_size = sizeof(*pconf) + tpml_select_size + pcr_digest_size; elt_size = sizeof(*elt) + pconf_size; elt = malloc(elt_size); if (!elt) { ERROR("Error: failed to allocate a LCP_POLICY_ELEMENT\n"); goto err; } elt->size = elt_size; elt->type = LCP_POLELT_TYPE_PCONF2; elt->policy_elt_control = 0; pconf = (void *)elt->data; pconf->hash_alg = pcrs.alg; pconf->num_pcr_infos = 1; tpm_quote = (void *)pconf->pcr_infos; memcpy(tpm_quote, tpml_select, tpml_select_size); memcpy(tpm_quote + tpml_select_size, pcr_digest, pcr_digest_size); /* cleanup and return a pointer to LCP_POLICY_ELEMENT */ free(tpml_select); free(pcr_comp); free(pcr_digest); return elt; err: if (tpml_select) free(tpml_select); if (pcr_comp) free(pcr_comp); if (pcr_digest) free(pcr_digest); if (elt) free(elt); return NULL; } static void display(const char *prefix, const lcp_policy_element_t *elt) { unsigned int iter_a; uint8_t val; char prefix_nested[80]; lcp_pconf_element_t2 *pconf; tpms_pcr_selection_t *tpms_select; tpml_pcr_selection_t *tpml_select; tpm2b_digest_t *pcr_digest; pconf = (void *)elt->data; snprintf(prefix_nested, sizeof(prefix_nested), "%s ", prefix); DISPLAY("%salg: %s\n", prefix, hash_alg_to_string(pconf->hash_alg)); /* TODO: we only show the first pcr_info right now, fix this (?) */ tpml_select = &pconf->pcr_infos[0].pcr_selection; tpms_select = &tpml_select->pcr_selections; DISPLAY("%spcrs:", prefix); val = tpms_select->pcr_select[0]; for (iter_a = 0; iter_a < 8; iter_a++) { if (val & 0x01) DISPLAY(" %d", iter_a); val >>= 1; } DISPLAY("\n"); pcr_digest = (void *)(((uint8_t *)tpml_select) + sizeof(*tpml_select) + tpms_select->size_of_select); DISPLAY("%squote:\n", prefix); print_hex(prefix_nested, pcr_digest->buffer, get_hash_size(pconf->hash_alg)); DISPLAY("\n"); } static struct option opts[] = { {"alg", required_argument, NULL, 'a'}, {"pcr0", required_argument, NULL, '0'}, {"pcr1", required_argument, NULL, '1'}, {"pcr2", required_argument, NULL, '2'}, {"pcr3", required_argument, NULL, '3'}, {"pcr4", required_argument, NULL, '4'}, {"pcr5", required_argument, NULL, '5'}, {"pcr6", required_argument, NULL, '6'}, {"pcr7", required_argument, NULL, '7'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "pconf2", opts, " pconf2\n" " --alg PCR hash alg\n" " [--pcr0 ] PCR0 value\n" " [--pcr1 ] PCR1 value\n" " [--pcr2 ] PCR2 value\n" " [--pcr3 ] PCR3 value\n" " [--pcr4 ] PCR4 value\n" " [--pcr5 ] PCR5 value\n" " [--pcr6 ] PCR6 value\n" " [--pcr7 ] PCR7 value\n", LCP_POLELT_TYPE_PCONF2, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pconf_legacy.c0000644000000000000000000003301214210363175016035 0ustar 00000000000000/* * pconf_legacy.c: PCONF element (LCP_PCONF_ELEMENT) plugin * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define MAX_FILES 32 #define MAX_PATH 256 #define MAX_PCRS 8 //PCRs 0-7 #define MAX_PCR_FILES 8; //This will store pcr-related data typedef struct pcr_data { bool valid; uint8_t num; uint8_t locality; uint8_t digest[SHA1_DIGEST_SIZE]; } pcr_data; typedef struct __packed { tpm_pcr_selection pcr_selection; uint32_t size_of_pcrs; // big endian unsigned char pcrs[][SHA1_DIGEST_SIZE]; } pcr_composite_buffer; //Global vars: char pcr_info_files[MAX_FILES][MAX_PATH]; uint8_t num_files = 0; int prevOpt = 'i'; pcr_data pcrs[8]; static bool read_pcrinfo_file(const char *file) { /* Each line in file has the following format: locality:value pcrNum:digest(no spaces) Length max is 47 Each file is one PCR_INFO_SHORT and num of files will be NumPcrInfoShort */ char delim[] = ":"; char *line = NULL; char *token = NULL; char *ptr2token = NULL; size_t line_size_bytes = 80; size_t chars_read; unsigned long locality = 0x0; line = malloc(line_size_bytes); if (line == NULL) { return false; } FILE *fp = NULL; fp = fopen(file, "r"); if (fp == NULL) { free(line); return false; } while (getline(&line, &chars_read, fp) != -1 ) { pcr_data this_pcr; this_pcr.locality = 0xFF; //This is set by first line in file this_pcr.num = 0xFF; this_pcr.valid = false; line_size_bytes = 80; if (*line == '\n'|| *line == '#' || *line == '\r' || !*line) { // if empty or # at the beginning skip continue; } //First valid line should be locality token = strtok_s(line, &line_size_bytes, delim, &ptr2token); if (locality) { this_pcr.locality = locality; } if (strcmp(token, "locality") != 0 && !strisdigit_s(token, 1)) { ERROR("Error: in pcrInfo file a line must be 'locality:value' or pcrNum:digest\n"); goto ERROR; } if (strcmp(token, "locality") == 0) { //Only allowed once in a file if (locality) { ERROR("Error: locality was already specified.\n"); goto ERROR; } locality = strtoul(ptr2token, NULL, 16); if (!locality) { ERROR("Error: you must select at least one locality.\n"); goto ERROR; } if (locality > 0x1F) { ERROR("Error: locality mask cannot be greater than 0x1F. Detected: 0x%x\n", this_pcr.locality); goto ERROR; } this_pcr.locality = locality; continue; } //PcrNum is a digit 0 to 7 if (strisdigit_s(token, 1)) { this_pcr.num = atoi(token); if (this_pcr.num > 7) { ERROR("Error: only pcrs 0-7 are supported.\n"); goto ERROR; } } /* Getline also reads up to and including newline. We need to remove it else import_hash will fail. */ if (ptr2token == NULL) { goto ERROR; } ptr2token[40] = '\0'; if (!import_hash(ptr2token, (tb_hash_t *) &this_pcr.digest, LCP_POLHALG_SHA1)) { ERROR("Error: failed to import hash. Check digest format.\n"); goto ERROR; } if (this_pcr.locality != 0xFF && this_pcr.num != 0xFF) { this_pcr.valid = true; pcrs[this_pcr.num] = this_pcr; pcrs[0].locality = locality; } else { ERROR("Error: failed to read PCR data. Check input file.\n"); goto ERROR; } } //SUCCESS: fclose(fp); free(line); return true; ERROR: fclose(fp); free(line); return false; } static bool cmdline_handler(int c, const char *opt) { if (c) { ERROR("Error: pconf element takes no CLI options\n"); return false; } if (opt) { size_t opt_len = strnlen(opt, MAX_PATH); strncpy_s(pcr_info_files[num_files], MAX_PATH, opt, opt_len); num_files++; return true; } else { ERROR("Error: at least one file must be specified.\n"); return false; } if (num_files > MAX_FILES) { ERROR("Error: too many files specified. Max is 32.\n"); return false; } } static bool generate_composite_hash(tpm_pcr_selection *pcr_selection, pcr_data *pcrs, tb_hash_t *dest, uint8_t no_of_pcrs) { /* This function: concatenates pcr values to one blob and hashes it using sha1 in: array of pcrs, allocated destination buffer, no of pcrs out: true/false on success/failure. Dest gets the composite hash */ int count = 0; bool result; pcr_composite_buffer *buff; size_t buff_size = 0; if (pcrs == NULL || dest == NULL) { ERROR("Error: pcrs or buffer for digest are not defined.\n"); return false; } if (no_of_pcrs < 1 || no_of_pcrs > 8) { ERROR("Error: at least 1 and at most 8 pcrs must be selected.\n"); return false; } buff_size = no_of_pcrs * SHA1_DIGEST_SIZE + sizeof(buff) - sizeof(buff->pcrs[0][0]); buff = calloc(1, buff_size); if (buff == NULL) { ERROR("Error: failed to allocate buffer for composite digest.\n"); return false; } memcpy_s( &buff->pcr_selection, sizeof buff->pcr_selection, pcr_selection, sizeof buff->pcr_selection ); for (int i = 0; i < MAX_PCRS; i++) { if (pcrs[i].valid) { if (verbose) { DISPLAY("PCR%d value: ", i); print_hex("", (const void *) pcrs[i].digest, SHA1_DIGEST_SIZE); } memcpy_s( buff->pcrs[count], //Dest SHA1_DIGEST_SIZE, //Dest size (const void *) pcrs[i].digest, //Src SHA1_DIGEST_SIZE //Src size ); count++; } if (count == no_of_pcrs) break; } result = hash_buffer((unsigned char *)buff, buff_size, dest, LCP_POLHALG_SHA1); if (verbose) { DISPLAY("Composite hash value: "); print_hex("", (const void *) dest, SHA1_DIGEST_SIZE); } free(buff); return result; } static lcp_policy_element_t *create(void) { lcp_policy_element_t *elt = NULL; lcp_pconf_element_t *pconf = NULL; tpm_pcr_info_short_t *pcr_info = NULL; tb_hash_t *digest = NULL; uint8_t no_of_pcrs = 0; bool result; uint8_t pcr_select; //First set all pcrs to non-valid size_t pconf_data_size = sizeof(lcp_pconf_element_t) + (sizeof(tpm_pcr_info_short_t) * num_files); size_t elt_size = sizeof(lcp_policy_element_t) + pconf_data_size; elt = calloc(1, elt_size); if (elt == NULL) { ERROR("Error: failed to allocate memory for the element.\n"); return NULL; } elt->size = elt_size; pconf = (lcp_pconf_element_t *) elt->data; pcr_info = (tpm_pcr_info_short_t *) &pconf->pcr_infos[0]; pconf->num_pcr_infos = num_files; for (uint8_t i = 0; i < pconf->num_pcr_infos; i++) { //First clear all pcr_data values pcr_select = 0x0; no_of_pcrs = 0x0; for (int i = 0; i < MAX_PCRS; i++) { memset_s((void *) &pcrs[i], sizeof(pcr_data), 0x0); } result = read_pcrinfo_file(pcr_info_files[i]); if (!result) { ERROR("Error: failed to read PCR info file.\n"); free(elt); return NULL; } for (int i = 0; i < MAX_PCRS; i++) { if (pcrs[i].valid) { pcr_select |= (1 << i); //Calculate pcr select mask no_of_pcrs++; } } if (!pcr_select) { ERROR("Error: no pcrs were selected.\n"); return NULL; } digest = malloc(SHA1_DIGEST_SIZE); if (digest == NULL) { ERROR("Error: failed to allocate memory for digest buffer.\n"); return NULL; } pcr_info->locality_at_release = pcrs[0].locality; pcr_info->pcr_selection.size_of_select = htons(1); pcr_info->pcr_selection.pcr_select = pcr_select; result = generate_composite_hash(&pcr_info->pcr_selection, pcrs, digest, no_of_pcrs); if (!result) { ERROR("Error: failed to generate composite hash.\n"); free(digest); free(elt); return false; } memcpy_s((void *)&pcr_info->digest_at_release, SHA1_DIGEST_SIZE, (const void *)&digest->sha1, SHA1_DIGEST_SIZE); pcr_info++; //Move to next one } if (verbose) { DISPLAY("PCONF element:\n"); print_hex(" ", (void *) elt, elt_size); } free(digest); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { size_t new_prefix_len = 0; lcp_pconf_element_t *pconf = (lcp_pconf_element_t *) elt->data; tpm_pcr_info_short_t *pcr_info = (tpm_pcr_info_short_t *) pconf->pcr_infos; if (elt == NULL) { ERROR("Error: element is not defined.\n"); return; } if (*prefix == '\0') new_prefix_len = 8; else new_prefix_len = strnlen_s(prefix, 20) + 8; char new_prefix[new_prefix_len]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), "\t"); DISPLAY("%sNumPcrInfos: 0x%x\n", prefix, pconf->num_pcr_infos); for (int i = 0; i < pconf->num_pcr_infos; i++) { DISPLAY("%sPCRInfos[%d]\n", prefix, i); DISPLAY("%s%sTPM_PCR_SELECTION.sizeOfSelect: 0x%x\n", prefix, prefix, ntohs(pcr_info->pcr_selection.size_of_select)); DISPLAY("%s%sTPM_PCR_SELECTION.pcrSelect: 0x%x\n", prefix, prefix, pcr_info->pcr_selection.pcr_select); DISPLAY("%s%s:PCR-0:PCR-1:PCR-2:PCR-3:PCR-4:PCR-5:PCR-6:PCR-7:\n", prefix, new_prefix); DISPLAY("%s%s:", prefix, new_prefix); for (int j = 0; j < 8; j++) { DISPLAY(" %d :", pcr_info->pcr_selection.pcr_select&(1<locality_at_release); DISPLAY("%s%sTPM_COMPOSITE_HASH.digest_at_release:\n", prefix, prefix); DISPLAY(prefix); print_hex(new_prefix, (void *) pcr_info->digest_at_release, SHA1_DIGEST_SIZE); pcr_info++; } } static struct option opts[] = { {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "pconf", opts, " pconf\n" " Generate LCP_ELEMENT_PCONF (legacy)\n" " [FILES]\n" " Up to 32 files with pcr info data.\n" " First line should be: 'locality:.'\n" " Locality must be at least 1 and at most 0x1F.\n" " Followed by up to 8 lines specifying PCR\n" " numbers (0-7) and their contents e.g.:\n" " 1:518bd167271fbb64589c61e43d8c0165861431d8\n", LCP_POLELT_TYPE_PCONF, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pol.c0000644000000000000000000001633714210363175014211 0ustar 00000000000000/* * pol.c: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "pol.h" #include "lcputils.h" size_t get_policy_size(const lcp_policy_t2 *pol) { return offsetof(lcp_policy_t2, policy_hash) + get_lcp_hash_size(pol->hash_alg); } bool verify_legacy_policy(const lcp_policy_t *pol, size_t size) { LOG("[verify_legacy_policy]"); size_t expected_size = offsetof(lcp_policy_t, policy_hash) + SHA1_DIGEST_SIZE; if (size != expected_size) { ERROR("Error: incorrect policy size. Expected %d.\n", expected_size); return false; } if (pol->version > LCP_VER_2_4 || pol->version < LCP_VER_2_0) { ERROR("Error: policy version incorrect.\n"); return false; } if (pol->hash_alg != LCP_POLHALG_SHA1) { //Legacy value for TPM 1.2 ERROR("Error: policy hash alg incorrect.\n"); return false; } if (pol->policy_type != LCP_POLTYPE_ANY && pol->policy_type != LCP_POLTYPE_LIST) { ERROR("Error: policy type incorrect.\n"); return false; } if ( pol->reserved1 != 0 || pol->reserved2 != 0 || pol->reserved3 != 0 || pol->reserved4 != 0 ) { ERROR("Error: one of reserved fields not 0.\n"); return false; } LOG("verify policy succeed!\n"); return true; } bool verify_policy(const lcp_policy_t2 *pol, size_t size, bool silent) { LOG("[verify_policy]\n"); if ( get_policy_size(pol) > size ) { if ( !silent ) ERROR("Error: policy too big\n"); return false; } if ( pol->version < LCP_DEFAULT_POLICY_VERSION || MAJOR_VER(pol->version) != MAJOR_VER(LCP_DEFAULT_POLICY_VERSION) ) { if ( !silent ) ERROR("Error: invalid policy version: 0x%x\n", pol->version); return false; } if ( !get_lcp_hash_size(pol->hash_alg) ) { if ( !silent ) ERROR("Error: invalid policy hash alg: %u\n", pol->hash_alg); return false; } if ( pol->policy_type != LCP_POLTYPE_ANY && pol->policy_type != LCP_POLTYPE_LIST ) { if ( !silent ) ERROR("Error: invlaid policy type: %u\n", pol->policy_type); return false; } if ( pol->reserved2!= 0 ) { if ( !silent ) ERROR("Error: reserved fields not 0: %u\n", pol->reserved2); return false; } LOG("verify policy succeed!\n"); return true; } void display_legacy_policy(const char *prefix, const lcp_policy_t *pol) { if (pol == NULL) { return; } DISPLAY("%s version: 0x%x\n", prefix, pol->version); DISPLAY("%s hash_alg: 0x%x (%s)\n", prefix, pol->hash_alg, hash_alg_to_str(pol->hash_alg)); DISPLAY("%s policy_type: %s\n", prefix, policy_type_to_str(pol->policy_type)); DISPLAY("%s sinit_min_version: 0x%x\n", prefix, pol->sinit_min_version); DISPLAY("%s data_revocation_counters: ", prefix); for ( unsigned int i = 0; i < LCP_MAX_LISTS; i++ ) DISPLAY("%u, ", pol->data_revocation_counters[i]); DISPLAY("\n"); DISPLAY("%s policy_control: 0x%x\n", prefix, pol->policy_control); DISPLAY("%s max_sinit_min_ver: 0x%x\n", prefix, pol->max_sinit_min_version); if (pol->version < LCP_VER_2_4) { DISPLAY("%s max_biosac_min_ver: 0x%x\n", prefix, pol->reserved2); } DISPLAY("%s policy_hash: ", prefix); print_hex("", &pol->policy_hash, SHA1_DIGEST_SIZE); } void display_policy(const char *prefix, const lcp_policy_t2 *pol, bool brief) { (void)brief; /* quiet compiler warning portably */ if ( pol == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pol->version); DISPLAY("%s hash_alg: 0x%x (%s)\n", prefix, pol->hash_alg, hash_alg_to_str(pol->hash_alg)); DISPLAY("%s policy_type: %s\n", prefix, policy_type_to_str(pol->policy_type)); DISPLAY("%s sinit_min_version: 0x%x\n", prefix, pol->sinit_min_version); DISPLAY("%s data_revocation_counters: ", prefix); for ( unsigned int i = 0; i < ARRAY_SIZE(pol->data_revocation_counters); i++ ) DISPLAY("%u, ", pol->data_revocation_counters[i]); DISPLAY("\n"); DISPLAY("%s policy_control: 0x%x\n", prefix, pol->policy_control); DISPLAY("%s max_sinit_min_ver: 0x%x\n", prefix, pol->max_sinit_min_ver); if (pol->version == LCP_VER_3_0) { DISPLAY("%s max_biosac_min_ver: 0x%x\n", prefix, pol->max_biosac_min_ver); } else { DISPLAY("%s reserved: 0x%x\n", prefix, pol->max_biosac_min_ver); } DISPLAY("%s lcp_hash_alg_mask: 0x%x\n", prefix, pol->lcp_hash_alg_mask); DISPLAY("%s lcp_sign_alg_mask: 0x%x\n", prefix, pol->lcp_sign_alg_mask); if (pol->version == LCP_VER_3_0) { DISPLAY("%s aux_hash_alg_mask: 0x%x\n", prefix, pol->aux_hash_alg_mask); } else { DISPLAY("%s reserved2: 0x%x\n", prefix, pol->aux_hash_alg_mask); } DISPLAY("%s policy_hash: ", prefix); print_hex("", &pol->policy_hash, get_lcp_hash_size(pol->hash_alg)); } const char *policy_type_to_str(uint8_t type) { static const char *types[] = { "list", "any" }; static char buf[32] = ""; if ( type >= ARRAY_SIZE(types) ) { snprintf_s_i(buf, sizeof(buf), "unknown (%u)", type); return buf; } return types[type]; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pol.h0000644000000000000000000000433714210363175014213 0ustar 00000000000000/* * pol.h: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POL_H__ #define __POL_H__ extern size_t get_policy_size(const lcp_policy_t2 *pol); extern bool verify_policy(const lcp_policy_t2 *pol, size_t size, bool silent); extern bool verify_legacy_policy(const lcp_policy_t *pol, size_t size); extern void display_policy(const char *prefix, const lcp_policy_t2 *pol, bool brief); extern void display_legacy_policy(const char *prefix, const lcp_policy_t *pol); extern const char *policy_type_to_str(uint8_t type); #endif /* __POL_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/poldata.c0000644000000000000000000003462514210363175015043 0ustar 00000000000000/* * poldata.c: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "../include/lcp3_hlp.h" #include "polelt_plugin.h" #include "poldata.h" #include "lcputils.h" #include "pollist2.h" #include "pollist2_1.h" #include "pollist1.h" size_t get_policy_data_size(const lcp_policy_data_t2 *poldata) { LOG("[get_policy_data_size]\n"); size_t size = offsetof(lcp_policy_data_t2, policy_lists); const lcp_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { uint16_t version ; memcpy_s((void*)&version,sizeof(version),(const void *)pollist,sizeof(uint16_t)); if ( MAJOR_VER(version) == 1 ) { LOG("get_policy_data_size: version=0x0100\n"); size += get_tpm12_policy_list_size(&(pollist->tpm12_policy_list)); pollist = (void *)pollist + get_tpm12_policy_list_size(&(pollist->tpm12_policy_list)); } else if ( MAJOR_VER(version) == 2 ) { LOG("get_policy_data_size: version=0x0200\n"); size += get_tpm20_policy_list_size(&(pollist->tpm20_policy_list)); pollist = (void *)pollist + get_tpm20_policy_list_size(&(pollist->tpm20_policy_list)); } else if ( MAJOR_VER(version) == 3 ) { size += list_21_sizes[i]; } } LOG("get_policy_data_size succeed! size = %x (%u)\n", (unsigned int)size, (unsigned int)size); return size; } bool verify_policy_data(const lcp_policy_data_t2 *poldata, size_t size) { LOG("[verify_policy_data]\n"); if ( offsetof(lcp_policy_data_t2, policy_lists) >= size ) { ERROR("Error: policy data too small\n"); return false; } if ( strcmp(poldata->file_signature, LCP_POLICY_DATA_FILE_SIGNATURE) != 0 ) { ERROR("Error: policy data file signature invalid (%s): \n", poldata->file_signature); return false; } if ( poldata->reserved[0] != 0 || poldata->reserved[1] != 0 || poldata->reserved[2] != 0 ) { ERROR("Error: policy data reserved fields not 0: %u, %u, %u\n", poldata->reserved[0], poldata->reserved[1], poldata->reserved[2]); return false; } if ( poldata->num_lists == 0 || poldata->num_lists >= LCP_MAX_LISTS ) { ERROR("Error: too many lists: %u\n", poldata->num_lists); return false; } /* try to bound size as closely as possible */ const lcp_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { LOG("verifying list %u:\n", i); uint16_t version ; memcpy_s((void*)&version,sizeof(version),(const void *)pollist,sizeof(uint16_t)); if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION)) { if ( !verify_tpm12_policy_list(&(pollist->tpm12_policy_list), size, NULL, false) ) return false; pollist = (void *)pollist + get_tpm12_policy_list_size(&(pollist->tpm12_policy_list)); } else if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION)) { if ( !verify_tpm20_policy_list(&(pollist->tpm20_policy_list), size, NULL, false) ) return false; pollist = (void *)pollist + get_tpm20_policy_list_size(&(pollist->tpm20_policy_list)); } else if (MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300)) { if (!verify_tpm20_policy_list_2_1( //don't check signature &(pollist->tpm20_policy_list_2_1), get_tpm20_policy_list_2_1_size(&(pollist->tpm20_policy_list_2_1)), NULL)) { return false; } } } LOG("verify policy data succeed!\n"); return true; } void display_policy_data(const char *prefix, const lcp_policy_data_t2 *poldata, bool brief) { if ( poldata == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s file_signature: %s\n", prefix, poldata->file_signature); DISPLAY("%s num_lists: %u\n", prefix, poldata->num_lists); char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), " "); const lcp_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { DISPLAY("%s list %u:\n", prefix, i); uint16_t version ; memcpy_s((void*)&version,sizeof(version),(const void *)pollist,sizeof(uint16_t)); if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION) ) { display_tpm12_policy_list(new_prefix, &(pollist->tpm12_policy_list), brief); pollist = (void *)pollist + get_tpm12_policy_list_size(&(pollist->tpm12_policy_list)); } if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) ) { display_tpm20_policy_list(new_prefix, &(pollist->tpm20_policy_list), brief); pollist = (void *)pollist + get_tpm20_policy_list_size(&(pollist->tpm20_policy_list)); } if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { lcp_policy_list_t2_1 *new_pollist; size_t list_base_size = offsetof(lcp_policy_list_t2_1, PolicyElements) + pollist->tpm20_policy_list_2_1.PolicyElementsSize; new_pollist = get_policy_list_2_1_data((const char *) pollist, list_base_size, pollist->tpm20_policy_list_2_1.KeySignatureOffset); if (new_pollist == NULL) { ERROR("ERROR: failed to read policy list from data file.\n"); return; } display_tpm20_policy_list_2_1(new_prefix, new_pollist, false); pollist = (void *)pollist + get_raw_tpm20_list_2_1_size(&pollist->tpm20_policy_list_2_1); } } } lcp_policy_data_t2 *add_tpm12_policy_list(lcp_policy_data_t2 *poldata, const lcp_policy_list_t *pollist) { if ( poldata == NULL || pollist == NULL ) return NULL; LOG("[add_tpm12_policy_list]\n"); /* adding a policy list requires growing the policy data */ size_t old_size = get_policy_data_size(poldata); size_t list_size = get_tpm12_policy_list_size(pollist); lcp_policy_data_t2 *new_poldata = realloc(poldata, old_size + list_size); if ( new_poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(poldata); return NULL; } /* realloc() copies over previous contents */ /* add to end */ memcpy_s((void *)new_poldata + old_size, list_size, pollist, list_size); new_poldata->num_lists++; LOG("add tpm12 policy list succeed!\n"); return new_poldata; } lcp_policy_data_t2 *add_tpm20_policy_list2_1(lcp_policy_data_t2 *poldata, size_t *list_size, const lcp_policy_list_t2_1 *pollist) { LOG("[add_tpm20_policy_list2_1]\n"); size_t real_list_size; lcp_policy_data_t2 *new_poldata; size_t old_size = get_policy_data_size(poldata); unsigned char *buffer_for_list; if (pollist->KeySignatureOffset == 0) { //Not signed real_list_size = get_tpm20_policy_list_2_1_size(pollist); *list_size = real_list_size; new_poldata = realloc(poldata, old_size+real_list_size); if ( new_poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(poldata); return NULL; } memcpy_s((void *)new_poldata + old_size, real_list_size, pollist, real_list_size); new_poldata->num_lists++; LOG("add tpm20 policy list succeed!\n"); return new_poldata; } else { //Signed lcp_signature_2_1 *sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("Error: failed to allocate memory\n"); free(poldata); return NULL; } buffer_for_list = fill_tpm20_policy_list_2_1_buffer(pollist, &real_list_size); if (buffer_for_list == NULL) { ERROR("Error: failed to allocate memory\n"); free(poldata); return NULL; } *list_size = real_list_size; new_poldata = realloc(poldata, old_size+real_list_size); if ( new_poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(poldata); free(buffer_for_list); return NULL; } memcpy_s((void *)new_poldata + old_size, real_list_size, (const void *) buffer_for_list, real_list_size); new_poldata->num_lists++; LOG("add tpm20 policy list succeed!\n"); free(buffer_for_list); return new_poldata; } } lcp_policy_data_t2 *add_tpm20_policy_list(lcp_policy_data_t2 *poldata, const lcp_policy_list_t2 *pollist) { LOG("[add_tpm20_policy_list]\n"); if ( poldata == NULL || pollist == NULL ) return NULL; /* adding a policy list requires growing the policy data */ size_t old_size = get_policy_data_size(poldata); size_t list_size = get_tpm20_policy_list_size(pollist); lcp_policy_data_t2 *new_poldata = realloc(poldata, old_size + list_size); if ( new_poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(poldata); return NULL; } /* realloc() copies over previous contents */ /* add to end */ memcpy_s((void *)new_poldata + old_size, list_size, pollist, list_size); new_poldata->num_lists++; LOG("add tpm20 policy list succeed!\n"); return new_poldata; } void calc_policy_data_hash(const lcp_policy_data_t2 *poldata, lcp_hash_t2 *hash, uint16_t hash_alg) { LOG("[calc_policy_data_hash]\n"); size_t hash_size = get_lcp_hash_size(hash_alg); uint8_t hash_list[hash_size * LCP_MAX_LISTS]; lcp_policy_list_t2_1 *pollist21 = NULL; memset_s(hash_list, sizeof(hash_list), 0); /* accumulate each list's msmt to list */ lcp_hash_t2 *curr_hash = (lcp_hash_t2 *)hash_list; const lcp_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { uint16_t version ; memcpy_s((void*)&version,sizeof(version),(const void *)pollist,sizeof(uint16_t)); if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION) ) { LOG("calc_policy_data_hash:version=0x0100\n" ); calc_tpm12_policy_list_hash(&(pollist->tpm12_policy_list), curr_hash, hash_alg); pollist = (void *)pollist + get_tpm12_policy_list_size(&(pollist->tpm12_policy_list)); curr_hash = (void *)curr_hash + hash_size; } if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) ) { LOG("calc_policy_data_hash:version=0x0200\n" ); calc_tpm20_policy_list_hash(&(pollist->tpm20_policy_list), curr_hash, hash_alg); pollist = (void *)pollist + get_tpm20_policy_list_size(&(pollist->tpm20_policy_list)); curr_hash = (void *)curr_hash + hash_size; } if ( MAJOR_VER(version) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { LOG("calc_policy_data_hash:version=0x0300\n"); size_t list_base_size = offsetof(lcp_policy_list_t2_1, PolicyElements)+ pollist->tpm20_policy_list_2_1.PolicyElementsSize; /* Poldata has the 2.1 list in a contiguous buffer, we need to allign it to fit lcp_policy_list_t2_1 structure */ pollist21 = get_policy_list_2_1_data( (const void *) pollist, list_base_size, pollist->tpm20_policy_list_2_1.KeySignatureOffset ); if (!calc_tpm20_policy_list_2_1_hash(pollist21, curr_hash, hash_alg)) { ERROR("ERROR: cannot calculate policy list hash.\n"); free(pollist21); return; } pollist = (void *)pollist + get_raw_tpm20_list_2_1_size(&pollist->tpm20_policy_list_2_1); curr_hash = (void *) curr_hash + hash_size; } } /* hash list */ hash_buffer(hash_list, hash_size * poldata->num_lists, (tb_hash_t *)hash, hash_alg); if (pollist21 != NULL) free(pollist21); return; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/poldata.h0000644000000000000000000000533714210363175015046 0ustar 00000000000000/* * poldata.h: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POLDATA2_H__ #define __POLDATA2_H__ extern size_t list_21_sizes[LCP_MAX_LISTS]; extern size_t get_policy_data_size(const lcp_policy_data_t2 *poldata); extern bool verify_policy_data(const lcp_policy_data_t2 *poldata, size_t size); extern void display_policy_data(const char *prefix, const lcp_policy_data_t2 *poldata, bool brief); extern lcp_policy_data_t2 *add_tpm12_policy_list(lcp_policy_data_t2 *poldata, const lcp_policy_list_t *pollist); extern lcp_policy_data_t2 *add_tpm20_policy_list(lcp_policy_data_t2 *poldata, const lcp_policy_list_t2 *pollist); extern lcp_policy_data_t2 *add_tpm20_policy_list2_1(lcp_policy_data_t2 *poldata, size_t *list_size, const lcp_policy_list_t2_1 *pollist); extern void calc_policy_data_hash(const lcp_policy_data_t2 *poldata, lcp_hash_t2 *hash, uint16_t hash_alg); #endif /* __POLDATA_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/polelt.c0000644000000000000000000000755614210363175014721 0ustar 00000000000000/* * polelt.c: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define POLELT_MAX_PLUGINS 32 unsigned int nr_polelt_plugins; polelt_plugin_t *polelt_plugins[POLELT_MAX_PLUGINS]; polelt_plugin_t *find_polelt_plugin_by_type(uint32_t type) { for ( unsigned int i = 0; i < nr_polelt_plugins; i++ ) { if ( type == polelt_plugins[i]->type ) return polelt_plugins[i]; } return NULL; } polelt_plugin_t *find_polelt_plugin_by_type_string(const char *type_str) { for ( unsigned int i = 0; i < nr_polelt_plugins; i++ ) { if ( strcmp(type_str, polelt_plugins[i]->type_string) == 0 ) return polelt_plugins[i]; } return NULL; } bool verify_policy_element(const lcp_policy_element_t *elt, size_t size) { if ( size < sizeof(*elt) ) { ERROR("Error: data is too small\n"); return false; } if ( size != elt->size ) { ERROR("Error: data is too small\n"); return false; } return true; } void display_policy_element(const char *prefix, const lcp_policy_element_t *elt, bool brief) { DISPLAY("%s size: 0x%x (%u)\n", prefix, elt->size, elt->size); polelt_plugin_t *plugin = find_polelt_plugin_by_type(elt->type); const char *type_str = (plugin == NULL) ? "unknown" : plugin->type_string; DISPLAY("%s type: \'%s\' (%u)\n", prefix, type_str, elt->type); DISPLAY("%s policy_elt_control: 0x%08x\n", prefix, elt->policy_elt_control); /* don't display element data for brief output */ if ( brief ) return; char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), " "); DISPLAY("%s data:\n", prefix); if ( plugin == NULL ) print_hex(new_prefix, elt->data, elt->size - sizeof(*elt)); else (*plugin->display)(new_prefix, elt); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/polelt.h0000644000000000000000000000422214210363175014711 0ustar 00000000000000/* * polelt.h: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POLELT_H__ #define __POLELT_H__ extern polelt_plugin_t *find_polelt_plugin_by_type(uint32_t type); extern polelt_plugin_t *find_polelt_plugin_by_type_string(const char *type_str); extern bool verify_policy_element(const lcp_policy_element_t *elt, size_t size); extern void display_policy_element(const char *prefix, const lcp_policy_element_t *elt, bool brief); #endif /* __POLELT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/polelt_plugin.h0000644000000000000000000000554314210363175016276 0ustar 00000000000000/* * polelt_plugin.h: policy element plugin support * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POLELT_PLUGIN_H__ #define __POLELT_PLUGIN_H__ #define MAX_ELT_TYPE_STR_LEN 32 typedef struct { const char *type_string; struct option *cmdline_opts; const char *help_txt; uint32_t type; /* c = option char (or 0 for non-option args) */ bool (*cmdline_handler)(int c, const char *opt); /* uses state from cmdline_handler */ lcp_policy_element_t *(*create_elt)(void); void (*display)(const char *prefix, const lcp_policy_element_t *elt); } polelt_plugin_t; extern unsigned int nr_polelt_plugins; extern polelt_plugin_t *polelt_plugins[]; #define REG_POLELT_PLUGIN(plugin) \ static void reg_plugin(void) __attribute__ ((constructor)); \ static void reg_plugin(void) \ { \ polelt_plugins[nr_polelt_plugins++] = plugin; \ } /* users must define these: */ extern void ERROR(const char *fmt, ...); extern void LOG(const char *fmt, ...); extern void DISPLAY(const char *fmt, ...); #endif /* __POLELT_PLUGIN_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pollist1.c0000644000000000000000000005047414210363175015166 0ustar 00000000000000/* * pollist1.c: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include #include #include #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "../include/lcp3_hlp.h" #include "polelt_plugin.h" #include "lcputils.h" #include "pollist1.h" #include "pollist2.h" #include "polelt.h" bool verify_tpm12_policy_list(const lcp_policy_list_t *pollist, size_t size, bool *no_sigblock, bool size_is_exact) { if ( pollist == NULL ) return false; if ( size < sizeof(*pollist) ) { ERROR("Error: data is too small (%u)\n", size); return false; } if ( pollist->version != LCP_TPM12_POLICY_LIST_VERSION ) { ERROR("Error: unsupported version 0x%04x\n", pollist->version); return false; } if ( pollist->reserved != 0 ) { ERROR("Error: reserved field must be 0: %u\n", pollist->reserved); return false; } if ( pollist->sig_alg != LCP_POLSALG_NONE && pollist->sig_alg != LCP_POLSALG_RSA_PKCS_15 ) { ERROR("Error: unsupported sig_alg %u\n", pollist->sig_alg); return false; } /* verify policy_elements_size */ size_t base_size = offsetof(lcp_policy_list_t, policy_elements); /* no sig, so size should be exact */ if ( pollist->sig_alg == LCP_POLSALG_NONE ) { if ( size_is_exact && base_size + pollist->policy_elements_size != size ) { ERROR("Error: size incorrect (no sig): 0x%x != 0x%x\n", base_size + pollist->policy_elements_size, size); return false; } else if ( !size_is_exact && base_size + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (no sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size, size); return false; } } /* verify size exactly later, after check sig field */ else if ( base_size + sizeof(lcp_signature_t) + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (sig min): 0x%x > 0x%x\n", base_size + sizeof(lcp_signature_t) + pollist->policy_elements_size, size); return false; } /* verify sum of policy elements' sizes */ uint32_t elts_size = 0; const lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size < pollist->policy_elements_size ) { if ( elts_size + elt->size > pollist->policy_elements_size ) { ERROR("Error: size incorrect (elt size): 0x%x > 0x%x\n", elts_size + elt->size, pollist->policy_elements_size); return false; } elts_size += elt->size; elt = (void *)elt + elt->size; } if ( elts_size != pollist->policy_elements_size ) { ERROR("Error: size incorrect (elt size): 0x%x != 0x%x\n", elts_size, pollist->policy_elements_size); return false; } /* verify sig */ if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) { lcp_signature_t *sig = (lcp_signature_t *) ((void *)&pollist->policy_elements + pollist->policy_elements_size); /* check size w/ sig_block */ if ( !size_is_exact && base_size + pollist->policy_elements_size + get_tpm12_signature_size(sig) > size + sig->pubkey_size ) { ERROR("Error: size incorrect (sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size + get_tpm12_signature_size(sig), size + sig->pubkey_size); return false; } else if ( size_is_exact && base_size + pollist->policy_elements_size + get_tpm12_signature_size(sig) != size ) { /* check size w/o sig_block */ if ( base_size + pollist->policy_elements_size + get_tpm12_signature_size(sig) != size + sig->pubkey_size ) { ERROR("Error: size incorrect (sig exact): 0x%x != 0x%x\n", base_size + pollist->policy_elements_size + get_tpm12_signature_size(sig), size + sig->pubkey_size); return false; } else { if ( no_sigblock != NULL ) *no_sigblock = true; } } else { if ( no_sigblock != NULL ) *no_sigblock = false; if ( !verify_tpm12_pollist_sig(pollist) ) { ERROR("Error: signature does not verify\n"); return false; } } } else { if ( no_sigblock != NULL ) *no_sigblock = false; } return true; } void display_tpm12_policy_list(const char *prefix, const lcp_policy_list_t *pollist, bool brief) { static const char *sig_alg_str[] = { "LCP_POLSALG_NONE", "LCP_POLSALG_RSA_PKCS_15" }; if ( pollist == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pollist->version); DISPLAY("%s sig_alg: 0x%x, %s\n", prefix, pollist->sig_alg, sig_alg_str[pollist->sig_alg]); DISPLAY("%s policy_elements_size: 0x%x (%u)\n", prefix, pollist->policy_elements_size, pollist->policy_elements_size); char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), " "); unsigned int i = 0; size_t elts_size = pollist->policy_elements_size; const lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size > 0 ) { DISPLAY("%s policy_element[%u]:\n", prefix, i++); display_policy_element(new_prefix, elt, brief); elts_size -= elt->size; elt = (void *)elt + elt->size; } lcp_signature_t *sig = get_tpm12_signature(pollist); if ( sig != NULL ) { DISPLAY("%s signature:\n", prefix); display_tpm12_signature(new_prefix, sig, brief); } } lcp_policy_list_t *create_empty_tpm12_policy_list(void) { lcp_policy_list_t *pollist = malloc(offsetof(lcp_policy_list_t, policy_elements)); if ( pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); return NULL; } pollist->version = LCP_TPM12_POLICY_LIST_VERSION; pollist->reserved = 0; pollist->sig_alg = LCP_POLSALG_NONE; pollist->policy_elements_size = 0; return pollist; } lcp_policy_list_t *add_tpm12_policy_element(lcp_policy_list_t *pollist, const lcp_policy_element_t *elt) { if ( pollist == NULL || elt == NULL ) return NULL; /* adding a policy element requires growing the policy list */ size_t old_size = get_tpm12_policy_list_size(pollist); lcp_policy_list_t *new_pollist = realloc(pollist, old_size + elt->size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ /* we add at the beginning of the elements list (don't want to overwrite a signature) */ memmove_s((void *) &new_pollist->policy_elements + elt->size, old_size - offsetof(lcp_policy_list_t, policy_elements), &new_pollist->policy_elements, old_size - offsetof(lcp_policy_list_t, policy_elements)); memcpy_s(&new_pollist->policy_elements, elt->size, elt, elt->size); new_pollist->policy_elements_size += elt->size; return new_pollist; } bool del_tpm12_policy_element(lcp_policy_list_t *pollist, uint32_t type) { if ( pollist == NULL ) return false; /* find first element of specified type (there should only be one) */ size_t elts_size = pollist->policy_elements_size; lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size > 0 ) { if ( elt->type == type ) { /* move everything up */ size_t tot_size = get_tpm12_policy_list_size(pollist); size_t elt_size = elt->size; memmove_s(elt, pollist->policy_elements_size, (void *)elt + elt_size, tot_size - ((void *)elt + elt_size - (void *)pollist)); pollist->policy_elements_size -= elt_size; return true; } elts_size -= elt->size; elt = (void *)elt + elt->size; } return false; } bool verify_tpm12_pollist_sig(const lcp_policy_list_t *pollist) { LOG("[verify_tpm12_pollist_sig]\n"); sized_buffer *list_data = NULL; sized_buffer *public_key = NULL; sized_buffer *signature = NULL; bool result; if (pollist == NULL) { ERROR("Error: policy list is not defined.\n"); return false; } if (pollist->sig_alg != LCP_POLSALG_RSA_PKCS_15) { ERROR("Error: signature alg not supported.\n"); return false; } lcp_signature_t *sig = get_tpm12_signature(pollist); if ( sig == NULL ) { ERROR("Error: failed to allocate signature.\n"); return false; } if (sig->pubkey_size!=256&&sig->pubkey_size!=384) { ERROR("Error: pubkey size not supported.\n"); return false; } list_data = allocate_sized_buffer(get_tpm12_policy_list_size(pollist)); if (list_data == NULL) { ERROR("Error: failed to allocate buffer for list_data.\n"); return false; } public_key = allocate_sized_buffer(sig->pubkey_size); if (public_key == NULL) { ERROR("Error: failed to allocate buffer for public_key.\n"); free(list_data); return false; } signature = allocate_sized_buffer(sig->pubkey_size); if (signature == NULL) { ERROR("Error: failed to allocate buffer for signature.\n"); free(list_data); free(public_key); return false; } list_data->size = get_tpm12_policy_list_size(pollist) - sig->pubkey_size; public_key->size = sig->pubkey_size; signature->size = sig->pubkey_size; memcpy_s((void *) list_data->data, list_data->size, (const void *) pollist, list_data->size); memcpy_s((void *) public_key->data, public_key->size, (const void *) sig->pubkey_value, sig->pubkey_size); memcpy_s((void *) signature->data, signature->size, (const void *) get_tpm12_sig_block(pollist), sig->pubkey_size); //Key and sig must be BE for openssl, and are LE in list, so reverse: buffer_reverse_byte_order((uint8_t *) public_key->data, public_key->size); buffer_reverse_byte_order((uint8_t *) signature->data, signature->size); result = verify_rsa_signature(list_data, public_key, signature, TPM_ALG_NULL, pollist->sig_alg, pollist->version); free(signature); free(list_data); free(public_key); if (result) { LOG("List signature verified successfully.\n"); } else { LOG("Signature did not verify.\n"); } return result; } void display_tpm12_signature(const char *prefix, const lcp_signature_t *sig, bool brief) { char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), "\t"); DISPLAY("%s revocation_counter: 0x%x (%u)\n", prefix, sig->revocation_counter, sig->revocation_counter); DISPLAY("%s pubkey_size: 0x%x (%u)\n", prefix, sig->pubkey_size, sig->pubkey_size); if ( brief ) return; DISPLAY("%s pubkey_value:\n", prefix); print_hex(new_prefix, sig->pubkey_value, sig->pubkey_size); DISPLAY("%s sig_block:\n", prefix); print_hex(new_prefix, (void *)&sig->pubkey_value + sig->pubkey_size, sig->pubkey_size); } lcp_policy_list_t *add_tpm12_signature(lcp_policy_list_t *pollist, const lcp_signature_t *sig) { LOG("add_tpm12_signature\n"); if ( pollist == NULL || sig == NULL ) return NULL; /* adding a signature requires growing the policy list */ size_t old_size = get_tpm12_policy_list_size(pollist); size_t sig_size = sizeof(*sig) + 2*sig->pubkey_size; lcp_policy_list_t *new_pollist = realloc(pollist, old_size + sig_size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ size_t sig_begin = old_size; /* if a signature already exists, replace it */ lcp_signature_t *curr_sig = get_tpm12_signature(new_pollist); if ( curr_sig != NULL ) sig_begin = (void *)curr_sig - (void *)new_pollist; memcpy_s((void *)new_pollist + sig_begin, sig_size, sig, sig_size); return new_pollist; } unsigned char *get_tpm12_sig_block(const lcp_policy_list_t *pollist) { lcp_signature_t *sig = get_tpm12_signature(pollist); if ( sig == NULL ) return NULL; return (unsigned char *)&sig->pubkey_value + sig->pubkey_size; } void calc_tpm12_policy_list_hash(const lcp_policy_list_t *pollist, lcp_hash_t2 *hash, uint16_t hash_alg) { uint8_t *buf_start = (uint8_t *)pollist; size_t len = get_tpm12_policy_list_size(pollist); if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) { lcp_signature_t *sig = get_tpm12_signature(pollist); if ( sig == NULL ) return; buf_start = sig->pubkey_value; len = sig->pubkey_size; } hash_buffer(buf_start, len, (tb_hash_t *)hash, hash_alg); } bool write_tpm12_policy_list_file(const char *file, const lcp_policy_list_t *pollist) { size_t len = get_tpm12_policy_list_size(pollist); /* check if sig_block all 0's--if so then means there was no sig_block when file was read but empty one was added, so don't write it */ lcp_signature_t *sig = get_tpm12_signature(pollist); if ( sig != NULL ) { uint8_t *sig_block = (uint8_t *)&sig->pubkey_value + sig->pubkey_size; while ( sig_block < ((uint8_t *)pollist + len) ) { if ( *sig_block++ != 0 ) break; } /* all 0's */ if ( sig_block == ((uint8_t *)pollist + len) ) { LOG("output file has no sig_block\n"); len -= sig->pubkey_size; } } return write_file(file, pollist, len); } bool rsa_sign_list1_data(lcp_policy_list_t *pollist, const char *privkey_file) { lcp_signature_t *sig = NULL; size_t list_data_len; sized_buffer *signature_block = NULL; sized_buffer *digest = NULL; EVP_PKEY_CTX *private_key_context = NULL; bool status; LOG("rsa_sign_list1_data\n"); if (pollist == NULL || privkey_file == NULL) { ERROR("Pollist or privkey undefined.\n"); return false; } sig = get_tpm12_signature(pollist); if (sig == NULL) { ERROR("Error: failed to get signature.\n"); return false; } list_data_len = get_tpm12_policy_list_size(pollist) - sig->pubkey_size; digest = allocate_sized_buffer(SHA1_DIGEST_SIZE); if (digest == NULL) { ERROR("Error: failed to allocate buffer.\n"); goto ERROR; } signature_block = allocate_sized_buffer(sig->pubkey_size); if (signature_block == NULL) { ERROR("Error: failed to allocate buffer.\n"); goto ERROR; } digest->size = SHA1_DIGEST_SIZE; signature_block->size = sig->pubkey_size; if (verbose) { DISPLAY("Data to hash:\n"); print_hex(" ", (const unsigned char *) pollist, list_data_len); } status = hash_buffer((const unsigned char *) pollist, list_data_len, (tb_hash_t *) digest->data, TPM_ALG_SHA1); if ( !status ) { ERROR("Error: failed to hash list\n"); goto ERROR; } if ( verbose ) { LOG("digest:\n"); print_hex("", (const void *) digest->data, SHA1_DIGEST_SIZE); } private_key_context = rsa_get_sig_ctx(privkey_file, sig->pubkey_size); if (private_key_context == NULL) { ERROR("Error: failed to initialize EVP context.\n"); goto ERROR; } //Now do the signing status = rsa_ssa_pss_sign(signature_block, digest, pollist->sig_alg, TPM_ALG_SHA1, private_key_context); if (!status) { ERROR("Error: failed to sign list data.\n"); goto ERROR; } buffer_reverse_byte_order((uint8_t *) signature_block->data, signature_block->size); memcpy_s((void *) sig->pubkey_value + sig->pubkey_size, sig->pubkey_size, (const void *) signature_block->data, signature_block->size); if ( verbose ) { LOG("Signature: \n"); display_tpm12_signature(" ", sig, false); } //Free allocated memory if (signature_block != NULL) { free(signature_block); } if (digest != NULL) { free(digest); } OPENSSL_free((void *) private_key_context); return true; ERROR: if (signature_block != NULL) { free(signature_block); } if (digest != NULL) { free(digest); } OPENSSL_free((void *) private_key_context); return false; } bool sign_lcp_policy_list_t(sign_user_input user_input) { bool no_sigblock_ok = false; bool result; lcp_policy_list_t *pollist = NULL; lcp_signature_t2 *sig = NULL; pollist = (lcp_policy_list_t *) read_policy_list_file(user_input.list_file, false, &no_sigblock_ok); if (pollist == NULL) { ERROR("Error: failed to read policy list file.\n"); return false; } pollist->sig_alg = LCP_POLSALG_RSA_PKCS_15; sig = read_rsa_pubkey_file(user_input.pubkey_file); if (sig == NULL) { ERROR("Error: failed to read public key.\n"); free(pollist); return NULL; } if ( (sig->rsa_signature.pubkey_size != 128 /* 1024 bits */) && (sig->rsa_signature.pubkey_size != 256 /* 2048 bits */) && (sig->rsa_signature.pubkey_size != 384 /* 3072 bits */) ) { ERROR("Error: public key size is not 1024/2048/3072 bits\n"); free(sig); free(pollist); return NULL; } sig->rsa_signature.revocation_counter = user_input.rev_ctr; pollist = add_tpm12_signature(pollist, (const lcp_signature_t *) &sig->rsa_signature); if (pollist == NULL) { free(sig); free(pollist); return NULL; } result = rsa_sign_list1_data(pollist, user_input.privkey_file); if (!result) { free(sig); free(pollist); return NULL; } result = write_tpm12_policy_list_file(user_input.list_file, pollist); free(pollist); free(sig); return result ? 1 : 0; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pollist1.h0000644000000000000000000000616714210363175015173 0ustar 00000000000000/* * pollist1.h: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POLLIST1_H__ #define __POLLIST1_H__ extern bool verify_tpm12_policy_list(const lcp_policy_list_t *pollist, size_t size, bool *no_sigblock, bool size_is_exact); extern void display_tpm12_policy_list(const char *prefix, const lcp_policy_list_t *pollist, bool brief); extern lcp_policy_list_t *create_empty_tpm12_policy_list(void); extern lcp_policy_list_t *add_tpm12_policy_element(lcp_policy_list_t *pollist, const lcp_policy_element_t *elt); extern bool del_tpm12_policy_element(lcp_policy_list_t *pollist, uint32_t type); extern bool verify_tpm12_pollist_sig(const lcp_policy_list_t *pollist); extern void display_tpm12_signature(const char *prefix, const lcp_signature_t *sig, bool brief); extern lcp_policy_list_t *add_tpm12_signature(lcp_policy_list_t *pollist, const lcp_signature_t *sig); extern unsigned char *get_tpm12_sig_block(const lcp_policy_list_t *pollist); extern void calc_tpm12_policy_list_hash(const lcp_policy_list_t *pollist, lcp_hash_t2 *hash, uint16_t hash_alg); extern bool write_tpm12_policy_list_file(const char *file, const lcp_policy_list_t *pollist); extern bool sign_lcp_policy_list_t(sign_user_input user_input); #endif /* __POLLIST1_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pollist2.c0000644000000000000000000014556114210363175015171 0ustar 00000000000000/* * pollist2.c: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER >= 0x30000000L #include #include #endif #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "../include/lcp3_hlp.h" #include "polelt_plugin.h" #include "lcputils.h" #include "pollist2.h" #include "pollist2_1.h" #include "polelt.h" #include "pollist1.h" //F-ction prototypes: bool verify_tpm20_ec_sig(const lcp_policy_list_t2 *pollist); //Does both ecdsa and sm2 static bool verify_tpm20_rsa_sig(const lcp_policy_list_t2 *pollist); static lcp_signature_t2 *read_ecdsa_pubkey(const char *pubkey_file); static bool rsa_sign_list2_data(lcp_policy_list_t2 *pollist, const char *privkey_file, uint16_t hash_alg); static lcp_policy_list_t2 *policy_list2_ec_sign_init(lcp_policy_list_t2 *pollist, uint16_t sig_alg, uint16_t rev_ctr, const char *pubkey_file, const char *privkey_file); static lcp_policy_list_t2 *policy_list2_rsa_sign_init(lcp_policy_list_t2 *pollist, uint16_t rev_ctr, uint16_t hash_alg, const char *pubkey_file, const char *privkey_file); lcp_list_t *read_policy_list_file(const char *file, bool fail_ok, bool *no_sigblock_ok) { LOG("[read_policy_list_file]\n"); if ( file == NULL || *file == '\0' || no_sigblock_ok == NULL ) { return NULL; } /* read existing file, if it exists */ size_t len; lcp_list_t *pollist = read_file(file, &len, fail_ok); if ( pollist == NULL ) { return NULL; } uint16_t version; memcpy_s((void*)&version,sizeof(version),(const void *)pollist,sizeof(uint16_t)); if ( MAJOR_VER(version) == 1 ){ LOG("read_policy_list_file: version=0x0100\n"); bool no_sigblock; if ( !verify_tpm12_policy_list(&(pollist->tpm12_policy_list), len, &no_sigblock, true) ) { free(pollist); return NULL; } if ( !*no_sigblock_ok && no_sigblock ) { ERROR("Error: policy list does not have sig_block\n"); free(pollist); return NULL; } /* if there is no sig_block then create one w/ all 0s so that get_policy_list_size() will work correctly; it will be stripped when writing it back */ lcp_signature_t *sig = get_tpm12_signature(&(pollist->tpm12_policy_list)); if ( sig != NULL && no_sigblock ) { LOG("input file has no sig_block\n"); size_t keysize = sig->pubkey_size; pollist = realloc(pollist, len + keysize); if ( pollist == NULL ) return NULL; memset_s((void *)pollist + len, keysize, 0); } *no_sigblock_ok = no_sigblock; LOG("read policy list file succeed!\n"); return pollist; } else if ( MAJOR_VER(version) == 2 ) { LOG("read_policy_list_file: version=0x0200\n"); bool no_sigblock; if ( !verify_tpm20_policy_list(&(pollist->tpm20_policy_list), len, &no_sigblock, true) ) { free(pollist); return NULL; } if ( !*no_sigblock_ok && no_sigblock ) { ERROR("Error: policy list does not have sig_block\n"); free(pollist); return NULL; } /* if there is no sig_block then create one w/ all 0s so that get_policy_list_size() will work correctly; it will be stripped when writing it back */ lcp_signature_t2 *sig = get_tpm20_signature(&(pollist->tpm20_policy_list)); if ( sig != NULL && no_sigblock ) { LOG("input file has no sig_block\n"); size_t keysize = 0; if ( pollist->tpm20_policy_list.sig_alg == TPM_ALG_RSASSA ) { LOG("read_policy_list_file: sig_alg == TPM_ALG_RSASSA\n"); keysize = sig->rsa_signature.pubkey_size; pollist = realloc(pollist, len + keysize); } else if ( pollist->tpm20_policy_list.sig_alg == TPM_ALG_ECDSA ) { LOG("read_policy_list_file: sig_alg == TPM_ALG_ECDSA\n"); keysize = sig->ecc_signature.pubkey_size; pollist = realloc(pollist, len + keysize); } if ( pollist == NULL ) return NULL; memset_s((void *)pollist + len, keysize, 0); } *no_sigblock_ok = no_sigblock; LOG("read policy list file succeed!\n"); return pollist; } DISPLAY("ERROR: unknown version.\n"); return NULL; //if it got here, there must've been an error } bool verify_tpm20_policy_list(const lcp_policy_list_t2 *pollist, size_t size, bool *no_sigblock, bool size_is_exact) { LOG("[verify_tpm20_policy_list]\n"); if ( pollist == NULL ) return false; if ( size < sizeof(*pollist) ) { ERROR("Error: data is too small (%u)\n", size); return false; } if ( MAJOR_VER(pollist->version) != MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION) || MINOR_VER(pollist->version) > MINOR_VER(LCP_TPM20_POLICY_LIST2_MAX_MINOR) ) { ERROR("Error: unsupported version 0x%04x\n", pollist->version); return false; } if ( pollist->sig_alg != TPM_ALG_NULL && pollist->sig_alg != TPM_ALG_RSASSA && pollist->sig_alg != TPM_ALG_ECDSA && pollist->sig_alg != TPM_ALG_SM2 ) { ERROR("Error: unsupported sig_alg %u\n", pollist->sig_alg); return false; } /* verify policy_elements_size */ size_t base_size = offsetof(lcp_policy_list_t2, policy_elements); /* no sig, so size should be exact */ if ( pollist->sig_alg == TPM_ALG_NULL ) { if ( size_is_exact && base_size + pollist->policy_elements_size != size ) { ERROR("Error: size incorrect (no sig): 0x%x != 0x%x\n", base_size + pollist->policy_elements_size, size); return false; } else if ( !size_is_exact && base_size + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (no sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size, size); return false; } } /* verify size exactly later, after check sig field */ else if ( pollist->sig_alg == TPM_ALG_RSASSA ) { LOG("verify_tpm20_policy_list: sig_alg == TPM_ALG_RSASSA\n"); if ( base_size + sizeof(lcp_rsa_signature_t) + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (sig min): 0x%x > 0x%x\n", base_size + sizeof(lcp_rsa_signature_t) + pollist->policy_elements_size, size); return false; } } else if ( pollist->sig_alg == TPM_ALG_ECDSA || pollist->sig_alg == TPM_ALG_SM2) { LOG("verify_tpm20_policy_list: sig_alg == TPM_ALG_ECDSA\n"); if ( base_size + sizeof(lcp_ecc_signature_t) + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (sig min): 0x%x > 0x%x\n", base_size + sizeof(lcp_ecc_signature_t) + pollist->policy_elements_size, size); return false; } } /* verify sum of policy elements' sizes */ uint32_t elts_size = 0; const lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size < pollist->policy_elements_size ) { if ( elts_size + elt->size > pollist->policy_elements_size ) { ERROR("Error: size incorrect (elt size): 0x%x > 0x%x\n", elts_size + elt->size, pollist->policy_elements_size); return false; } elts_size += elt->size; elt = (void *)elt + elt->size; } if ( elts_size != pollist->policy_elements_size ) { ERROR("Error: size incorrect (elt size): 0x%x != 0x%x\n", elts_size, pollist->policy_elements_size); return false; } /* verify sig */ if ( pollist->sig_alg == TPM_ALG_RSASSA || pollist->sig_alg == TPM_ALG_ECDSA || pollist->sig_alg == TPM_ALG_SM2 ) { lcp_signature_t2 *sig = (lcp_signature_t2 *) ((void *)&pollist->policy_elements + pollist->policy_elements_size); /* check size w/ sig_block */ if ( !size_is_exact && (base_size + pollist->policy_elements_size + get_tpm20_signature_size(sig, pollist->sig_alg) > size + sig->rsa_signature.pubkey_size) ) { ERROR("Error: size incorrect (sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size + get_tpm20_signature_size(sig, pollist->sig_alg), size + sig->rsa_signature.pubkey_size); return false; } else if ( size_is_exact && base_size + pollist->policy_elements_size + get_tpm20_signature_size(sig,pollist->sig_alg) != size ) { /* check size w/o sig_block */ if ( base_size + pollist->policy_elements_size + get_tpm20_signature_size(sig, pollist->sig_alg) != size + sig->rsa_signature.pubkey_size ) { ERROR("Error: size incorrect (sig exact): 0x%x != 0x%x\n", base_size + pollist->policy_elements_size + get_tpm20_signature_size(sig, pollist->sig_alg), size + sig->rsa_signature.pubkey_size); return false; } else { if ( no_sigblock != NULL ) *no_sigblock = true; } } else { if ( no_sigblock != NULL ) *no_sigblock = false; if ( !verify_tpm20_pollist_sig(pollist) ) { ERROR("Error: signature does not verify\n"); return false; } } } else { if ( no_sigblock != NULL ) *no_sigblock = false; } LOG("verify tpm20 policy list succeed!\n"); return true; } void display_tpm20_policy_list(const char *prefix, const lcp_policy_list_t2 *pollist, bool brief) { if ( pollist == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pollist->version); DISPLAY("%s sig_alg: 0x%x, %s\n", prefix, pollist->sig_alg, sig_alg_to_str(pollist->sig_alg)); DISPLAY("%s policy_elements_size: 0x%x (%u)\n", prefix, pollist->policy_elements_size, pollist->policy_elements_size); char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), " "); unsigned int i = 0; size_t elts_size = pollist->policy_elements_size; const lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size > 0 ) { DISPLAY("%s policy_element[%u]:\n", prefix, i++); display_policy_element(new_prefix, elt, brief); elts_size -= elt->size; elt = (void *)elt + elt->size; } lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig != NULL ) { DISPLAY("%s signature:\n", prefix); display_tpm20_signature(new_prefix, sig, pollist->sig_alg, brief); } } lcp_policy_list_t2 *create_empty_tpm20_policy_list(void) { LOG("[create_empty_tpm20_policy_list]\n"); lcp_policy_list_t2 *pollist = malloc(offsetof(lcp_policy_list_t, policy_elements)); if ( pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); return NULL; } pollist->version = LCP_TPM20_POLICY_LIST_VERSION; pollist->sig_alg = TPM_ALG_NULL; pollist->policy_elements_size = 0; LOG("create policy list succeed!\n"); return pollist; } lcp_policy_list_t2 *add_tpm20_policy_element(lcp_policy_list_t2 *pollist, const lcp_policy_element_t *elt) { LOG("[add_tpm20_policy_element]\n"); if ( pollist == NULL || elt == NULL ) return NULL; /* adding a policy element requires growing the policy list */ size_t old_size = get_tpm20_policy_list_size(pollist); lcp_policy_list_t2 *new_pollist = realloc(pollist, old_size + elt->size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ /* we add at the beginning of the elements list (don't want to overwrite a signature) */ memmove_s((void *)&new_pollist->policy_elements + elt->size, old_size - offsetof(lcp_policy_list_t2, policy_elements), &new_pollist->policy_elements, old_size - offsetof(lcp_policy_list_t2, policy_elements)); memcpy_s(&new_pollist->policy_elements, elt->size, elt, elt->size); new_pollist->policy_elements_size += elt->size; LOG("add tpm20 policy element succeed\n"); return new_pollist; } bool del_tpm20_policy_element(lcp_policy_list_t2 *pollist, uint32_t type) { if ( pollist == NULL ) return false; /* find first element of specified type (there should only be one) */ size_t elts_size = pollist->policy_elements_size; lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size > 0 ) { if ( elt->type == type ) { /* move everything up */ size_t tot_size = get_tpm20_policy_list_size(pollist); size_t elt_size = elt->size; memmove_s(elt, pollist->policy_elements_size, (void *)elt + elt_size, tot_size - ((void *)elt + elt_size - (void *)pollist)); pollist->policy_elements_size -= elt_size; return true; } elts_size -= elt->size; elt = (void *)elt + elt->size; } return false; } bool verify_tpm20_ec_sig(const lcp_policy_list_t2 *pollist) { /* This functions prepares lcp policy list for verification, i.e. generates buffers for list data, public key components, signature components and passes all of it to ec_verify in lcputils In: pointer to properly allocated lcp_policy_list_t2 structure containing list and signature. Out: True on success, false on failure */ sized_buffer *pollist_data = NULL; sized_buffer *pubkey_x = NULL; sized_buffer *pubkey_y = NULL; sized_buffer *sig_r = NULL; sized_buffer *sig_s = NULL; lcp_signature_t2 *sig = NULL; size_t pollist_data_size, keysize; bool result; uint16_t sigalg; uint16_t hashalg; LOG("[verify_tpm20_ec_sig]\n"); if (pollist == NULL) { ERROR("Error: policy list is not defined.\n"); return false; } sigalg = pollist->sig_alg; sig = get_tpm20_signature(pollist); if (sig == NULL) { ERROR("Error: failed to get signature.\n"); return false; } keysize = sig->ecc_signature.pubkey_size; if (keysize != MIN_ECC_KEY_SIZE && keysize != MAX_ECC_KEY_SIZE) { ERROR("Error: incorrect key size.\n"); return false; } //Set hashalg - sm3 for sm2 sigs, sha384 for 384 bit keys and sha256 for 256 bit keys if (sigalg == TPM_ALG_SM2) { hashalg = TPM_ALG_SM3_256; } else if (keysize == MIN_ECC_KEY_SIZE){ // 32 hashalg = TPM_ALG_SHA256; } else { hashalg = TPM_ALG_SHA384; } //Data from beginning of the list up to but not including the signature. pollist_data_size = get_tpm20_policy_list_size(pollist) - (2 * keysize); pollist_data = allocate_sized_buffer(pollist_data_size); pubkey_x = allocate_sized_buffer(keysize); pubkey_y = allocate_sized_buffer(keysize); sig_r = allocate_sized_buffer(keysize); sig_s = allocate_sized_buffer(keysize); if (pollist_data == NULL || pubkey_x == NULL || pubkey_y == NULL || sig_r == NULL || sig_s == NULL) { ERROR("Error: failed to allocate data structure.\n"); result = false; goto EXIT; } pollist_data->size = pollist_data_size; pubkey_y->size = keysize; pubkey_x->size = keysize; sig_r->size = keysize; sig_s->size = keysize; //Copy data to buffers, in sig structure qx is contiguous and contains x, y, r and s //each comp is keysize long memcpy_s((void *) pubkey_x->data, pubkey_x->size, (const void *) sig->ecc_signature.qx, keysize); memcpy_s((void *) pubkey_y->data, pubkey_y->size, (const void *) sig->ecc_signature.qx + keysize, keysize); memcpy_s((void *) sig_r->data, sig_r->size, (const void *) sig->ecc_signature.qx + (2 * keysize), keysize); memcpy_s((void *) sig_s->data, sig_s->size, (const void *) sig->ecc_signature.qx + (3 * keysize), keysize); memcpy_s((void *) pollist_data->data, pollist_data->size, (const void *) pollist, pollist_data_size); //r, s, x, y are LE in lcp but openssl needs them BE, so we will flip them. buffer_reverse_byte_order((uint8_t *) pubkey_x->data, pubkey_x->size); buffer_reverse_byte_order((uint8_t *) pubkey_y->data, pubkey_y->size); buffer_reverse_byte_order((uint8_t *) sig_r->data, sig_r->size); buffer_reverse_byte_order((uint8_t *) sig_s->data, sig_s->size); //Now verify result = verify_ec_signature(pollist_data, pubkey_x, pubkey_y, sig_r, sig_s, sigalg, hashalg); if (!result) { ERROR("Error: failed to verify SM2 signature.\n"); } EXIT: if (pollist_data != NULL) { free(pollist_data); } if (pubkey_x != NULL) { free(pubkey_x); } if (pubkey_y != NULL) { free(pubkey_y); } if (sig_r != NULL) { free(sig_r); } if (sig_s != NULL) { free(sig_s); } return result; } bool verify_tpm20_rsa_sig(const lcp_policy_list_t2 *pollist) { sized_buffer *list_data = NULL; sized_buffer *public_key = NULL; sized_buffer *signature = NULL; lcp_signature_t2 *sig = NULL; bool result; LOG("[verify_tpm20_rsa_sig]"); if (pollist == NULL) { ERROR("Error: policy list is not defined.\n"); return false; } sig = get_tpm20_signature(pollist); if (sig == NULL) { ERROR("Error: failed to get signature.\n"); return false; } list_data = allocate_sized_buffer((get_tpm20_policy_list_size(pollist) - sig->rsa_signature.pubkey_size)); if (list_data == NULL) { ERROR("Error: failed to allocate buffer for list_data.\n"); return false; } public_key = allocate_sized_buffer(sig->rsa_signature.pubkey_size); if (public_key == NULL) { ERROR("Error: failed to allocate buffer for public_key.\n"); free(list_data); return false; } signature = allocate_sized_buffer(sig->rsa_signature.pubkey_size); if (signature == NULL) { ERROR("Error: failed to allocate buffer for signature.\n"); free(list_data); free(public_key); return false; } list_data->size = get_tpm20_policy_list_size(pollist) - sig->rsa_signature.pubkey_size; public_key->size = sig->rsa_signature.pubkey_size; signature->size = sig->rsa_signature.pubkey_size; memcpy_s((void *) list_data->data, list_data->size, (const void *) pollist, list_data->size); memcpy_s((void *) public_key->data, public_key->size, (const void *) sig->rsa_signature.pubkey_value, sig->rsa_signature.pubkey_size); memcpy_s((void *) signature->data, signature->size, (const void *) get_tpm20_sig_block(pollist), signature->size); //Key and sig must be BE for openssl, and are LE in list, so reverse: buffer_reverse_byte_order((uint8_t *) public_key->data, public_key->size); buffer_reverse_byte_order((uint8_t *) signature->data, signature->size); //Any value for hashalg, it will be overwritten inside function result = verify_rsa_signature(list_data, public_key, signature, TPM_ALG_NULL, pollist->sig_alg, pollist->version); free(list_data); free(public_key); free(signature); return result; } bool verify_tpm20_pollist_sig(const lcp_policy_list_t2 *pollist) { LOG("[verify_tpm20_pollist_sig]\n"); if (pollist == NULL) { ERROR("Error: policy list is not defined.\n"); return false; } lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return true; if ( pollist->sig_alg == TPM_ALG_RSASSA ) { return verify_tpm20_rsa_sig(pollist); } else if ( pollist->sig_alg == TPM_ALG_ECDSA || pollist->sig_alg == TPM_ALG_SM2) { return verify_tpm20_ec_sig(pollist); } return false; } void display_tpm20_signature(const char *prefix, const lcp_signature_t2 *sig, const uint16_t sig_alg, bool brief) { if( sig_alg == TPM_ALG_RSASSA) { char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), "\t"); DISPLAY("%s revocation_counter: 0x%x (%u)\n", prefix, sig->rsa_signature.revocation_counter, sig->rsa_signature.revocation_counter); DISPLAY("%s pubkey_size: 0x%x (%u)\n", prefix, sig->rsa_signature.pubkey_size, sig->rsa_signature.pubkey_size); if ( brief ) return; DISPLAY("%s pubkey_value:\n", prefix); print_hex(new_prefix, sig->rsa_signature.pubkey_value, sig->rsa_signature.pubkey_size); DISPLAY("%s sig_block:\n", prefix); print_hex(new_prefix, (void *)&sig->rsa_signature.pubkey_value + sig->rsa_signature.pubkey_size, sig->rsa_signature.pubkey_size); } else if ( sig_alg == TPM_ALG_ECDSA || sig_alg == TPM_ALG_SM2) { //Same for both char new_prefix[strnlen_s(prefix, 20)+8]; strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), "\t"); DISPLAY("%s revocation_counter: 0x%x (%u)\n", prefix, sig->ecc_signature.revocation_counter, sig->ecc_signature.revocation_counter); DISPLAY("%s pubkey_size: 0x%x (%u)\n", prefix, sig->ecc_signature.pubkey_size, sig->ecc_signature.pubkey_size); DISPLAY("%s reserved: 0x%x (%u)\n", prefix, sig->ecc_signature.reserved, sig->ecc_signature.reserved); if ( brief ) return; DISPLAY("%s qx:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx, sig->ecc_signature.pubkey_size); DISPLAY("%s qy:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx + sig->ecc_signature.pubkey_size, sig->ecc_signature.pubkey_size); DISPLAY("%s r:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx + (2*sig->ecc_signature.pubkey_size), sig->ecc_signature.pubkey_size); DISPLAY("%s s:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx + (3*sig->ecc_signature.pubkey_size), sig->ecc_signature.pubkey_size); } } lcp_policy_list_t2 *add_tpm20_signature(lcp_policy_list_t2 *pollist, const lcp_signature_t2 *sig, const uint16_t sig_alg) { LOG("[add_tpm20_signature]\n"); if ( pollist == NULL || sig == NULL ) { LOG("add_tpm20_signature: pollist == NULL || sig == NULL\n"); return NULL; } if ( sig_alg == TPM_ALG_RSASSA) { LOG("add_tpm20_signature: sig_alg == TPM_ALG_RSASSA\n"); /* adding a signature requires growing the policy list */ size_t old_size = get_tpm20_policy_list_size(pollist); size_t sig_size = sizeof(lcp_rsa_signature_t) + 2*sig->rsa_signature.pubkey_size; LOG("add_tpm20_signature: sizeof(lcp_rsa_signature_t)=%d\n", sizeof(lcp_rsa_signature_t)); lcp_policy_list_t2 *new_pollist = realloc(pollist, old_size + sig_size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ size_t sig_begin = old_size; /* if a signature already exists, replace it */ lcp_signature_t2 *curr_sig = get_tpm20_signature(new_pollist); if ( curr_sig != NULL ) sig_begin = (void *)curr_sig - (void *)new_pollist; memcpy_s((void *)new_pollist + sig_begin, sig_size, sig, sig_size); new_pollist->sig_alg = sig_alg; return new_pollist; } //Also works with SM2 else if ( sig_alg == TPM_ALG_ECDSA || sig_alg == TPM_ALG_SM2 ) { LOG("add_tpm20_signature: sig_alg == %s\n", sig_alg_to_str(sig_alg)); /* adding a signature requires growing the policy list */ size_t old_size = get_tpm20_policy_list_size(pollist); size_t sig_size = sizeof(lcp_ecc_signature_t) + 4*sig->ecc_signature.pubkey_size; lcp_policy_list_t2 *new_pollist = realloc(pollist, old_size + sig_size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ size_t sig_begin = old_size; /* if a signature already exists, replace it */ lcp_signature_t2 *curr_sig = get_tpm20_signature(new_pollist); if ( curr_sig != NULL ) sig_begin = (void *)curr_sig - (void *)new_pollist; memcpy_s((void *)new_pollist + sig_begin, sig_size, sig, sig_size); new_pollist->sig_alg = sig_alg; LOG("add tpm20 signature succeed!\n"); return new_pollist; } return NULL; } unsigned char *get_tpm20_sig_block(const lcp_policy_list_t2 *pollist) { if ( pollist->sig_alg == TPM_ALG_RSASSA ) { lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return NULL; return (unsigned char *)&sig->rsa_signature.pubkey_value + sig->rsa_signature.pubkey_size; } else if ( pollist->sig_alg == TPM_ALG_ECDSA ) { lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return NULL; return (unsigned char *)&sig->ecc_signature.qx + sig->ecc_signature.pubkey_size; } else if ( pollist->sig_alg == TPM_ALG_SM2 ) { LOG("get_tpm_20_sig_block: sig_alg == TPM_ALG_SM2\n"); return NULL; } return NULL; } void calc_tpm20_policy_list_hash(const lcp_policy_list_t2 *pollist, lcp_hash_t2 *hash, uint16_t hash_alg) { /* Calculate hash of this list. If unsigned - hash entire list. If signed - hash public key (rsa) or hash Qx and Qy (ec) */ LOG("[calc_tpm20_policy_list_hash]\n"); uint8_t *buf_start = (uint8_t *)pollist; size_t len = get_tpm20_policy_list_size(pollist); if ( pollist->sig_alg == TPM_ALG_RSASSA ) { LOG("calc_tpm20_policy_list_hash: sig_alg == TPM_ALG_RSASSA\n"); lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return; buf_start = sig->rsa_signature.pubkey_value; len = sig->rsa_signature.pubkey_size; } else if ( pollist->sig_alg == TPM_ALG_ECDSA || pollist->sig_alg == TPM_ALG_SM2) { LOG("calc_tpm20_policy_list_hash: sig_alg == TPM_ALG_ECDSA\n"); //Hash Qx and Qy lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return; buf_start = sig->ecc_signature.qx; len = 2 * sig->ecc_signature.pubkey_size; } hash_buffer(buf_start, len, (tb_hash_t *)hash, hash_alg); } bool write_tpm20_policy_list_file(const char *file, const lcp_policy_list_t2 *pollist) { LOG("[write_tpm20_policy_list_file]\n"); size_t len = get_tpm20_policy_list_size(pollist); /* check if sig_block all 0's--if so then means there was no sig_block when file was read but empty one was added, so don't write it */ lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig != NULL ) { if ( pollist->sig_alg == TPM_ALG_RSASSA ) { LOG("write_tpm20_policy_list_file: sig_alg == TPM_ALG_RSASSA\n"); uint8_t *sig_block = (uint8_t *)&sig->rsa_signature.pubkey_value + sig->rsa_signature.pubkey_size; while ( sig_block < ((uint8_t *)pollist + len) ) { if ( *sig_block++ != 0 ) break; } /* all 0's */ if ( sig_block == ((uint8_t *)pollist + len) ) { LOG("output file has no sig_block\n"); len -= sig->rsa_signature.pubkey_size; } } } return write_file(file, pollist, len); } lcp_signature_t2 *read_rsa_pubkey_file(const char *file) { LOG("read_rsa_pubkey_file\n"); FILE *fp = fopen(file, "rb"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", file, strerror(errno)); return NULL; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY *pubkey = NULL; OSSL_DECODER_CTX *dctx = OSSL_DECODER_CTX_new_for_pkey(&pubkey, "PEM", NULL, "RSA", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL); if ( dctx == NULL ) { ERROR("Error: no suitable potential decoders found\n"); fclose(fp); return NULL; } if ( !OSSL_DECODER_from_fp(dctx, fp) ) { ERROR("Error: decoding failure\n"); fclose(fp); return NULL; } OSSL_DECODER_CTX_free(dctx); #else RSA *pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); #endif if ( pubkey == NULL ) { ERR_load_crypto_strings(); ERROR("Error: failed to read .pem file %s: %s\n", file, ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); fclose(fp); return NULL; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L unsigned int keysize = EVP_PKEY_get_size(pubkey); #else unsigned int keysize = RSA_size(pubkey); #endif if ( keysize == 0 ) { ERROR("Error: public key size is 0\n"); OPENSSL_free((void *) pubkey); fclose(fp); return NULL; } lcp_signature_t2 *sig = malloc(sizeof(lcp_rsa_signature_t) + 2*keysize); if ( sig == NULL ) { ERROR("Error: failed to allocate sig\n"); OPENSSL_free((void *) pubkey); fclose(fp); return NULL; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L BIGNUM *modulus = NULL; #else const BIGNUM *modulus = NULL; #endif memset_s(sig, sizeof(lcp_rsa_signature_t) + 2*keysize, 0); sig->rsa_signature.pubkey_size = keysize; #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY_get_bn_param(pubkey, "n", &modulus); #elif OPENSSL_VERSION_NUMBER >= 0x10100000L RSA_get0_key(pubkey, &modulus, NULL, NULL); #else modulus = pubkey->n; #endif unsigned char key[keysize]; BN_bn2bin(modulus, key); /* openssl key is big-endian and policy requires little-endian, so reverse bytes */ for ( unsigned int i = 0; i < keysize; i++ ) sig->rsa_signature.pubkey_value[i] = *(key + (keysize - i - 1)); if ( verbose ) { LOG("read_rsa_pubkey_file: signature:\n"); display_tpm20_signature(" ", sig, TPM_ALG_RSASSA, false); } LOG("read rsa pubkey succeed!\n"); OPENSSL_free((void *) pubkey); fclose(fp); return sig; } lcp_signature_t2 *read_ecdsa_pubkey(const char *pubkey_file) { lcp_signature_t2 *sig = NULL; FILE *fp = NULL; BIGNUM *x = NULL; BIGNUM *y = NULL; uint8_t *qx = NULL; uint8_t *qy = NULL; uint16_t keySize; uint16_t keySizeBytes; int result; #if OPENSSL_VERSION_NUMBER < 0x30000000L const EC_KEY *pubkey = NULL; const EC_POINT *pubpoint = NULL; const EC_GROUP *pubgroup = NULL; BN_CTX *ctx = NULL; #else EVP_PKEY *pubkey; #endif LOG("read ecdsa pubkey file for list signature.\n"); fp = fopen(pubkey_file, "rb"); if ( fp == NULL) { ERROR("ERROR: cannot open file.\n"); goto ERROR; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L OSSL_DECODER_CTX *dctx; dctx = OSSL_DECODER_CTX_new_for_pkey(&pubkey, "PEM", NULL, "EC", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL); if ( dctx == NULL ) { goto OPENSSL_ERROR; } if ( !OSSL_DECODER_from_fp(dctx, fp) ) { goto OPENSSL_ERROR; } OSSL_DECODER_CTX_free(dctx); if ( pubkey == NULL ) { goto OPENSSL_ERROR; } fclose(fp); fp = NULL; EVP_PKEY_get_bn_param(pubkey, "qx", &x); EVP_PKEY_get_bn_param(pubkey, "qy", &y); if ( x == NULL || y == NULL ) { goto OPENSSL_ERROR; } #else pubkey = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL); if ( pubkey == NULL ) { goto OPENSSL_ERROR; } fclose(fp); fp = NULL; pubpoint = EC_KEY_get0_public_key(pubkey); if ( pubpoint == NULL ) { goto OPENSSL_ERROR; } pubgroup = EC_KEY_get0_group(pubkey); if ( pubgroup == NULL ) { goto OPENSSL_ERROR; } x = BN_new(); y = BN_new(); ctx = BN_CTX_new(); if ( x == NULL|| y == NULL || ctx == NULL) { goto OPENSSL_ERROR; } result = EC_POINT_get_affine_coordinates_GFp(pubgroup, pubpoint, x, y, ctx); if (result <= 0) { goto OPENSSL_ERROR; } #endif keySize = BN_num_bytes(x)*8; if (BN_num_bytes(x) != BN_num_bytes(y)) { ERROR("ERROR: key coordinates are not the same length."); goto ERROR; } if ( keySize != 256 && keySize != 384 ) { ERROR("ERROR: keySize 0x%X is not 0x%X or 0x%X.\n", keySize/8, MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE); goto ERROR; } keySizeBytes = BN_num_bytes(x); //BE arrays for data from openssl qx = malloc(sizeof(lcp_ecc_signature_t) + (2*keySizeBytes)); if (qx == NULL) { ERROR("Failed to allocate memory for public key.\n"); goto ERROR; } qy = malloc(sizeof(lcp_ecc_signature_t) + (2*keySizeBytes)); if (qy == NULL) { ERROR("Failed to allocate memory for public key.\n"); goto ERROR; } sig = calloc(1, sizeof(lcp_ecc_signature_t)+(4*keySizeBytes)); //qx, qy, r and s if (sig == NULL) { ERROR("Error: failed to allocate signature.\n"); return NULL; } sig->ecc_signature.pubkey_size = keySizeBytes; //in bytes sig->ecc_signature.reserved = 0x0; if (!BN_bn2bin(x, qx)) { goto OPENSSL_ERROR; } if (!BN_bn2bin(y, qy)) { goto OPENSSL_ERROR; } //Flip BE to LE buffer_reverse_byte_order((uint8_t *) qx, keySizeBytes); buffer_reverse_byte_order((uint8_t *) qy, keySizeBytes); //Start copying - ecc_signature.qx has length 4*keysize result = memcpy_s( (void *) sig->ecc_signature.qx, 4*keySizeBytes, qx, keySizeBytes ); if ( result != EOK ) { ERROR("ERROR: Cannot copy key data to LCP list\n"); goto ERROR; } result = memcpy_s( (void *) sig->ecc_signature.qx + keySizeBytes, 3*keySizeBytes, qy, keySizeBytes ); if ( result != EOK ) { ERROR("ERROR: Cannot copy key data to LCP list\n"); goto ERROR; } //All good, free resources: free(qx); free(qy); OPENSSL_free((void *) pubkey); OPENSSL_free((void *) x); OPENSSL_free((void *) y); #if OPENSSL_VERSION_NUMBER < 0x30000000L OPENSSL_free((void *) pubpoint); OPENSSL_free((void *) pubgroup); OPENSSL_free((void *) ctx); #endif return sig; //Errors: OPENSSL_ERROR: ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); ERROR: //Free all allocated mem if (fp != NULL) fclose(fp); if (sig != NULL) free(sig); if (qx != NULL) free(qx); if (qy != NULL) free(qy); if (pubkey != NULL) OPENSSL_free((void *) pubkey); if (x != NULL) OPENSSL_free((void *) x); if (y != NULL) OPENSSL_free((void *) y); #if OPENSSL_VERSION_NUMBER < 0x30000000L if (pubpoint != NULL) OPENSSL_free((void *) pubpoint); if (pubgroup != NULL) OPENSSL_free((void *) pubgroup); if (ctx != NULL) OPENSSL_free((void *) ctx); #endif return NULL; } bool ec_sign_list2_data(lcp_policy_list_t2 *pollist, const char *privkey) { /* This function: prepares lcp_policy_list_t2 structure for signing using private key file. Signing in ecdsa or sm2 In: pointer to correctly allocated policy list structure, path to private key Out: true on success, false on failure. */ sized_buffer *sig_r = NULL; sized_buffer *sig_s = NULL; sized_buffer *pollist_data = NULL; lcp_signature_t2 *sig = NULL; bool result; size_t pollist_data_size, keysize; uint16_t sigalg; uint16_t hashalg; LOG("[ec_sign_list2_data]\n"); if (pollist == NULL) { ERROR("Error: policy list is not defined.\n"); return false; } sig = get_tpm20_signature(pollist); if (sig == NULL) { ERROR("Error: failed to read signature.\n"); result = false; goto EXIT; } //Set hashalgs, sm2 gets sm3, ecdsa sha256 or sha384 depending on key size switch (pollist->sig_alg) { case TPM_ALG_ECDSA: hashalg = (sig->ecc_signature.pubkey_size == 32) ? TPM_ALG_SHA256 : TPM_ALG_SHA384; break; case TPM_ALG_SM2: hashalg = TPM_ALG_SM3_256; break; default: ERROR("Error: unsupported signature algorithm.\n"); result = false; goto EXIT; } sigalg = pollist->sig_alg; keysize = sig->ecc_signature.pubkey_size; pollist_data_size = get_tpm20_policy_list_size(pollist) - (2 * keysize); sig_r = allocate_sized_buffer(keysize); sig_s = allocate_sized_buffer(keysize); pollist_data = allocate_sized_buffer(pollist_data_size); if (sig_r == NULL || sig_s == NULL || pollist_data == NULL) { ERROR("Error: failed to allocate data buffers.\n"); result = false; goto EXIT; } sig_r->size = keysize; sig_s->size = keysize; pollist_data->size = pollist_data_size; memcpy_s((void *) pollist_data->data, pollist_data->size, (const void *) pollist, pollist_data_size); if (verbose) { LOG("Data to be signed:\n"); print_hex(" ", pollist_data->data, pollist_data->size); } result = ec_sign_data(pollist_data, sig_r, sig_s, sigalg, hashalg, privkey); if (!result) { ERROR("Error: failed to sign policy list data.\n"); goto EXIT; } //Openssl returns data in BE, lcp wants LE so flip endianness of r and s buffer_reverse_byte_order((uint8_t *)sig_r->data, sig_r->size); buffer_reverse_byte_order((uint8_t *)sig_s->data, sig_s->size); memcpy_s((void *) sig->ecc_signature.qx + (2 * keysize), keysize, (const void *)sig_r->data, sig_r->size); memcpy_s((void *) sig->ecc_signature.qx + (3 * keysize), keysize, (const void *)sig_s->data, sig_s->size); if (verbose) { display_tpm20_signature(" ", sig, TPM_ALG_SM2, false); } EXIT: if (sig_r != NULL) { free(sig_r); } if (sig_s != NULL) { free(sig_s); } if (pollist_data != NULL) { free(pollist_data); } return result; } bool rsa_sign_list2_data(lcp_policy_list_t2 *pollist, const char *privkey_file, uint16_t hash_alg) /* This function: Performs the signing operation on the policy list data using OpenSSL functions. In: pointer to policy list structure to sign, path to private key, hash algorithm to use. Out: True on success, false on failure */ { sized_buffer *signature_block = NULL; //Will hold signature block sized_buffer *data_to_sign = NULL; //Will hold digest of list data bool status; size_t key_size; size_t list_data_len; EVP_PKEY_CTX *private_key_context = NULL; LOG("rsa_sign_list_data\n"); if ( pollist == NULL || privkey_file == NULL ) { ERROR("Error: policy list or private key are not defined.\n"); return false; } lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) { ERROR("Error: failed to get lcp signature.\n"); return false; } key_size = sig->rsa_signature.pubkey_size; //List is signed up to but not including its signature block field. list_data_len = get_tpm20_policy_list_size(pollist) - key_size; signature_block = allocate_sized_buffer(key_size); if (signature_block == NULL) { ERROR("Error failed to allocate buffer.\n"); return false; } data_to_sign = allocate_sized_buffer(get_lcp_hash_size(hash_alg)); if (data_to_sign == NULL) { ERROR("Error failed to allocate buffer.\n"); status = false; goto END; } if (verbose) { DISPLAY("Data to hash:\n"); print_hex(" ", (const unsigned char *) pollist, list_data_len); } signature_block->size = key_size; data_to_sign->size = get_lcp_hash_size(hash_alg); status = hash_buffer((const unsigned char *) pollist, list_data_len, (tb_hash_t *) data_to_sign->data, hash_alg); if ( !status ) { ERROR("Error: failed to hash list\n"); //status is false goto END; } if ( verbose ) { LOG("digest:\n"); print_hex("", (const void *) data_to_sign->data, get_hash_size(hash_alg)); } private_key_context = rsa_get_sig_ctx(privkey_file, key_size); if (private_key_context == NULL) { ERROR("Error: failed to initialize EVP context.\n"); status = false; goto END; } //Now sign: status = rsa_ssa_pss_sign(signature_block, data_to_sign, pollist->sig_alg, hash_alg, private_key_context); if (!status) { ERROR("Error: failed to sign list data.\n"); //status is false goto END; } //Flip signature endianness buffer_reverse_byte_order((uint8_t *) signature_block->data, signature_block->size); memcpy_s((void *) sig->rsa_signature.pubkey_value+key_size, key_size, (const void *) signature_block->data, signature_block->size); if ( verbose ) { LOG("Signature: \n"); display_tpm20_signature(" ", sig, pollist->sig_alg, false); } END: //Free resources and return if (signature_block != NULL) { free(signature_block); } if (data_to_sign != NULL) { free(data_to_sign); } OPENSSL_free((void *) private_key_context); return status; } lcp_policy_list_t2 *policy_list2_ec_sign_init(lcp_policy_list_t2 *pollist, uint16_t rev_ctr, uint16_t sig_alg, const char *pubkey_file, const char *privkey_file) { /* This function: Initializes signing process using ECDSA algorithm: 1)Reads public key file 2)Generates signature structure and adds it to list 3)Calls a function to sign the list using private key In: Policy list structure, revocation counter (user input), paths to public and private key Out: policy list structure containing public key and signature data or NULL on failure. */ lcp_signature_t2 *sig = NULL; bool result; LOG("[policy_list2_ec_sign_init]\n"); if (pollist == NULL) { ERROR("Error: lcp policy list is not defined.\n"); return NULL; } sig = read_ecdsa_pubkey(pubkey_file); if (sig == NULL) { ERROR("Error: failed to read ec public key.\n"); return NULL; } sig->ecc_signature.revocation_counter = rev_ctr; if (verbose) { DISPLAY("lcp_signature_t2: \n"); display_tpm20_signature(" ", sig, sig_alg, false); } pollist = add_tpm20_signature(pollist, sig, sig_alg); if (pollist == NULL) { ERROR("Error: failed to add lcp_signature_2_1 to list.\n"); free(sig); return NULL; } result = ec_sign_list2_data(pollist, privkey_file); if (!result) { ERROR("Error: failed to sign list data.\n"); free(sig); return NULL; } free(sig); return pollist; } lcp_policy_list_t2 *policy_list2_rsa_sign_init(lcp_policy_list_t2 *pollist, uint16_t rev_ctr, uint16_t hash_alg, const char *pubkey_file, const char *privkey_file) { /* This function: Initializes signing process using RSA algorithm: 1)Reads public key file 2)Generates signature structure and adds it to list 3)Calls a function to sign the list using private key In: Policy list structure, revocation counter, hash alg, paths to public and private key Out: policy list structure containing public key and signature data or NULL on failure. */ lcp_signature_t2 *sig = NULL; bool result; LOG("LCP_POLICY_LIST2 sign using RSA-SSA\n"); if (pollist == NULL) { return NULL; } //pollist->sig_alg = sig_alg; sig = read_rsa_pubkey_file(pubkey_file); if (sig == NULL) { ERROR("Error: failed to read public key.\n"); free(pollist); return NULL; } if ( (sig->rsa_signature.pubkey_size != 128 /* 1024 bits */) && (sig->rsa_signature.pubkey_size != 256 /* 2048 bits */) && (sig->rsa_signature.pubkey_size != 384 /* 3072 bits */) ) { ERROR("Error: public key size is not 1024/2048/3072 bits\n"); free(sig); free(pollist); return NULL; } //Add signature to list sig->rsa_signature.revocation_counter = rev_ctr; pollist = add_tpm20_signature(pollist, sig, TPM_ALG_RSASSA); if (pollist == NULL) { free(sig); free(pollist); return NULL; } //Sign list data result = rsa_sign_list2_data(pollist, privkey_file, hash_alg); if (!result) { ERROR("Error: failed to sign policy list data.\n"); free(sig); free(pollist); return NULL; } free(sig); return pollist; } bool sign_lcp_policy_list_t2(sign_user_input user_input) { /* This function: starts signing procedure for the LCP list. In: structure with user input containing required info: pub and priv key paths, sig algs, list file. Out: true on success false on failure. */ bool no_sigblock_ok = false; bool write_ok; lcp_policy_list_t2 *pollist = NULL; pollist = (lcp_policy_list_t2 *) read_policy_list_file(user_input.list_file, false, &no_sigblock_ok); if (pollist == NULL) { ERROR("Error: failed to read policy list file.\n"); return false; } //We checked user-set sigalg in main, so just check if sigalg is not rsapss if (user_input.sig_alg == TPM_ALG_RSAPSS) { ERROR("Error: TPM_ALG_RSAPSS algorithm unsupported for LCP_POLICY_LIST2.\n" "Use LCP_POLICY_LIST2_1 (lcp list version 0x300).\n"); free(pollist); return false; } //Depending on the sig alg we call one of two functions if (user_input.sig_alg == TPM_ALG_RSASSA) { pollist = policy_list2_rsa_sign_init(pollist, user_input.rev_ctr, user_input.hash_alg, user_input.pubkey_file, user_input.privkey_file); } else if (user_input.sig_alg == TPM_ALG_ECDSA || user_input.sig_alg == TPM_ALG_SM2) { pollist = policy_list2_ec_sign_init(pollist, user_input.rev_ctr, user_input.sig_alg, user_input.pubkey_file, user_input.privkey_file); } else { //Error DISPLAY("Unsupported signature algorithm\n"); free(pollist); return false; } if (pollist == NULL) { ERROR("Error: failed to sign policy list\n"); return false; } write_ok = write_tpm20_policy_list_file(user_input.list_file, pollist); free(pollist); return write_ok; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pollist2.h0000644000000000000000000000673214210363175015172 0ustar 00000000000000/* * pollist2.h: * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POLLIST2_H__ #define __POLLIST2_H__ extern lcp_list_t *read_policy_list_file(const char *file, bool fail_ok, bool *no_sigblock_ok); extern bool sign_lcp_policy_list_t2(sign_user_input user_input); lcp_signature_t2 *read_rsa_pubkey_file(const char *file); extern bool verify_tpm20_policy_list(const lcp_policy_list_t2 *pollist, size_t size, bool *no_sigblock, bool size_is_exact); extern void display_tpm20_policy_list(const char *prefix, const lcp_policy_list_t2 *pollist, bool brief); extern lcp_policy_list_t2_1 *create_empty_tpm20_policy_list_2_1(void); extern lcp_policy_list_t2 *create_empty_tpm20_policy_list(void); extern lcp_policy_list_t2 *add_tpm20_policy_element(lcp_policy_list_t2 *pollist, const lcp_policy_element_t *elt); extern bool del_tpm20_policy_element(lcp_policy_list_t2 *pollist, uint32_t type); extern bool verify_tpm20_pollist_sig(const lcp_policy_list_t2 *pollist); extern void display_tpm20_signature(const char *prefix, const lcp_signature_t2 *sig, const uint16_t sig_alg, bool brief); extern lcp_policy_list_t2 *add_tpm20_signature(lcp_policy_list_t2 *pollist, const lcp_signature_t2 *sig, const uint16_t sig_alg); extern unsigned char *get_tpm20_sig_block(const lcp_policy_list_t2 *pollist); extern void calc_tpm20_policy_list_hash(const lcp_policy_list_t2 *pollist, lcp_hash_t2 *hash, uint16_t hash_alg); extern bool write_tpm20_policy_list_file(const char *file, const lcp_policy_list_t2 *pollist); #endif /* __POLLIST2_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pollist2_1.c0000644000000000000000000022545414210363175015411 0ustar 00000000000000/* * pollist2_1.c: * * Copyright (c) 2020, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER >= 0x30000000L #include #include #endif #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "../include/lcp3_hlp.h" #include "polelt_plugin.h" #include "lcputils.h" #include "pollist2_1.h" #include "polelt.h" //Function prototypes: static size_t get_tpm20_key_and_signature_2_1_real_size(const lcp_signature_2_1 *sig); static size_t get_tpm20_list_2_1_signature_size(const lcp_signature_2_1 *sig); static bool get_rsa_signature_2_1_data(lcp_signature_2_1 *sig, void *data); static bool get_ecc_signature_2_1_data(lcp_signature_2_1 *sig, void *data); static bool verify_tpm20_pollist_2_1_rsa_sig(lcp_policy_list_t2_1 *pollist); static bool verify_tpm20_pollist_2_1_ec_sig(const lcp_policy_list_t2_1 *pollist); static void display_tpm20_signature_2_1(const char *prefix, const lcp_signature_2_1 *sig, const uint16_t sig_alg); static lcp_policy_list_t2_1 *add_tpm20_signature_2_1(lcp_policy_list_t2_1 *pollist, lcp_signature_2_1 *sig, const uint16_t sig_alg); static lcp_signature_2_1 *read_rsa_pubkey_file_2_1(const char *pubkey_file); static lcp_signature_2_1 *read_ecdsa_pubkey_file_2_1(const char *pubkey_file); static bool ec_sign_list_2_1_data(lcp_policy_list_t2_1 *pollist, const char *privkey_file); static bool rsa_sign_list_2_1_data(lcp_policy_list_t2_1 *pollist, const char *privkey_file); static lcp_policy_list_t2_1 *policy_list2_1_rsa_sign(lcp_policy_list_t2_1 *pollist, uint16_t rev_ctr, uint16_t hash_alg, uint16_t sig_alg, const char *pubkey_file, const char *privkey_file); static lcp_policy_list_t2_1 *policy_list2_1_ec_sign(lcp_policy_list_t2_1 *pollist, uint16_t rev_ctr, uint16_t sig_alg, const char *pubkey_file, const char *privkey_file); ///////////////////////////////////////////// /* FUNCTIONS TO WORK WITH POLICY LISTS 2.1 */ ///////////////////////////////////////////// lcp_policy_list_t2_1 *get_policy_list_2_1_data(const void *raw_data, size_t base_size, uint16_t key_signature_offset) { /* This function: takes in raw policy list data and aligns it to lcp_policy_list_t2_1 structures. In: Pointer to contiguous policy list data buffer, base size of the list i.e. offset of PolicyElements and size of policy elements, key signature offset. Out: Pointer to aligned lcp_policy_list_t2_1 structure */ size_t sig_offset_in_data; lcp_policy_list_t2_1 *new_pollist = NULL; //Will return this sig_key_2_1_header *header; lcp_signature_2_1 *sig = NULL; int status; LOG("[get_policy_list_2_1_data]\n"); if (raw_data == NULL) { ERROR("Error: list data not defined.\n"); return NULL; } if (key_signature_offset == 0) { //No signature new_pollist = malloc(base_size); if (new_pollist == NULL) { ERROR("Error: failed to allocate policy list structure.\n"); return NULL; } //If no signature, just copy data to new_pollist status = memcpy_s(new_pollist, base_size, raw_data, base_size); if (status == EOK) return new_pollist; else { free(new_pollist); return NULL; } } new_pollist = malloc(key_signature_offset); sig = create_empty_rsa_signature_2_1(); if (sig == NULL || new_pollist == NULL ) { ERROR("ERROR: unable to create signature.\n"); return NULL; } //Remember that Revocation Counter size is added to to key signature offset sig_offset_in_data = key_signature_offset - offsetof(lcp_signature_2_1, KeyAndSignature); status = memcpy_s(new_pollist, key_signature_offset, raw_data, key_signature_offset); if (status != EOK) { ERROR("Error: failed to copy list data.\n"); return NULL; } header = (sig_key_2_1_header *) (raw_data+sig_offset_in_data); switch (header->key_alg) { case TPM_ALG_RSA: if (!get_rsa_signature_2_1_data(sig, (void *) raw_data+sig_offset_in_data)) { ERROR("ERROR: failed to get signature data.\n"); free(sig); free(new_pollist); return NULL; } new_pollist->KeySignatureOffset = 0x0; // Reset keysignatureoffset new_pollist = add_tpm20_signature_2_1(new_pollist, sig, TPM_ALG_RSAPSS); if (new_pollist == NULL ) { ERROR("ERROR: Cannot add TPM_signature_2_1"); free(sig); return NULL; } break; case TPM_ALG_ECC: if (!get_ecc_signature_2_1_data(sig, (void *) raw_data+sig_offset_in_data)) { ERROR("ERROR: failed to get signature data.\n"); free(sig); return NULL; } new_pollist->KeySignatureOffset = 0x0; // Reset keysignatureoffset new_pollist = add_tpm20_signature_2_1(new_pollist, sig, TPM_ALG_ECDSA); if (new_pollist == NULL ) { ERROR("ERROR: Cannot add TPM_signature_2_1"); free(sig); return NULL; } break; default: ERROR("Error: unknown key algorithm.\n"); free(sig); free(new_pollist); return NULL; } free(sig); return new_pollist; } lcp_policy_list_t2_1 *read_policy_list_2_1_file(bool sign_it, const char *list_file) { /* This function: reads policy list data from a file. In: sign_it to indicate whether we want the list to be later signed or not, path to list file (string) Out: Pointer to aligned lcp_policy_list_t2_1 structure */ LOG("read_policy_list_file: version 0x0300\n"); size_t file_length; //This is NOT always list size size_t elts_size; lcp_policy_list_t2_1 *pollist = NULL; //Helper - will be discarded lcp_policy_list_t2_1 *new_pollist = NULL; //Will be returned bool result; bool has_sig; size_t base_size = offsetof(lcp_policy_list_t2_1, PolicyElements); pollist = read_file(list_file, &file_length, false); if (pollist==NULL) { ERROR("ERROR: failed to read policy list file.\n"); return NULL; } result = verify_tpm20_policy_list_2_1(pollist, file_length, &has_sig); if (!result) { free(pollist); return NULL; } elts_size = pollist->PolicyElementsSize; if ( has_sig && !sign_it ) { //List has sig, but we don't want to sign it again. new_pollist = get_policy_list_2_1_data((const void *) pollist, base_size+ elts_size, pollist->KeySignatureOffset); if ( new_pollist == NULL ) { ERROR("ERROR: failed to read policy list structure.\n"); free(pollist); return NULL; } free(pollist); return new_pollist; } //List has signature and we want to sign it, disregard the signature it has //and return it without it. else { //Pass 0 as last arg to get_data func, this way we don't get sig. new_pollist = get_policy_list_2_1_data((const void *) pollist, base_size+ elts_size, 0); if ( new_pollist == NULL ) { ERROR("ERROR: failed to read policy list structure.\n"); free(pollist); return NULL; } free(pollist); return new_pollist; } } lcp_signature_2_1 *create_empty_ecc_signature_2_1(void) /* This function: returns empty ecc sig structure. Empty == just 0s inside In: None Out: Pointer to an empty structure */ { //Size of structure + size of revocation counter size_t sig_size = sizeof(ecc_key_and_signature) + offsetof(lcp_signature_2_1, KeyAndSignature); lcp_signature_2_1 *sig = malloc(sig_size); if (sig == NULL) { return NULL; } if (memset_s(sig, sig_size, 0x00) == EOK) { return sig; } else { return NULL; } } lcp_signature_2_1 *create_empty_rsa_signature_2_1(void) /* This function: returns empty rsa signature structure. Empty == just 0s inside In: None Out: Pointer to empty structure */ { //Size of structure + size of revocation counter size_t sig_size = sizeof(rsa_key_and_signature) + offsetof(lcp_signature_2_1, KeyAndSignature); lcp_signature_2_1 *sig = malloc(sig_size); if ( sig == NULL ) { return NULL; } if (memset_s(sig, sig_size, 0x00) == EOK) { return sig; } else { return NULL; } } size_t get_tpm20_list_2_1_signature_size(const lcp_signature_2_1 *sig) /* This function: calculates size of lcp_signature_2_1 structure In: pointer to signature structure whose size we want to calculate Out: Size */ { if ( sig == NULL ){ return 0; } //We need to know what type of key was used to sign it uint16_t key_alg = get_signature_2_1_key_alg(sig); switch ( key_alg ) { case TPM_ALG_RSA: return sizeof(sig->RevocationCounter) + sizeof(rsa_key_and_signature); case TPM_ALG_ECC: return sizeof(sig->RevocationCounter) + sizeof(ecc_key_and_signature); default: break; } return 0; } size_t get_tpm20_policy_list_2_1_size(const lcp_policy_list_t2_1 *pollist) /* This function: calculates size of lcp_policy_list_t2_1 structure In: pointer to the list structure whose size we want to calculate Out: lcp policy list size */ { size_t size = 0; if (pollist == NULL) { return 0; } size = offsetof(lcp_policy_list_t2_1, PolicyElements)+pollist->PolicyElementsSize; /* add signature size if it's present */ if ( pollist->KeySignatureOffset ) { size += get_tpm20_list_2_1_signature_size(get_tpm20_signature_2_1(pollist)); } return size; } bool verify_tpm20_policy_list_2_1(const lcp_policy_list_t2_1 *pollist, size_t size, bool *has_sig) /* This function: checks if policy list is correct. Verifies the list up to but not including the signature In: pointer to policy list structure, policy list file size, pointer to bool var that gets info whether list is signed. Out: True on success, false on error */ { size_t base_size; uint32_t elts_size; const lcp_policy_element_t *elt = NULL; LOG("[verify_tpm20_policy_list_2_1]\n"); if ( pollist == NULL ) { ERROR("Error: list is not defined.\n"); return false; } //Size read from file must not be smaller than the size of structure pointed to if ( size < sizeof(*pollist) ) { ERROR("Error: data is too small (%u)\n", size); return false; } if (verbose) { DISPLAY("Raw policy list data:\n"); print_hex(" ", (const void *) pollist, size); } //Major ver must be 3, minor ver must be 0 if ( MAJOR_VER(pollist->Version) != \ MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) || \ MINOR_VER(pollist->Version) > MINOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ) { ERROR("Error: unsupported version 0x%04x\n", pollist->Version); return false; } base_size = offsetof(lcp_policy_list_t2_1, PolicyElements); //KeySignatureOffset 0 means no signature in list file elts_size = 0; elt = pollist->PolicyElements; while ( elts_size < pollist->PolicyElementsSize) { if (elts_size + elt->size > pollist->PolicyElementsSize) { ERROR("Error: size is incorrect (elements size): 0x%x > 0x%x\n", elts_size+elt->size, pollist->PolicyElementsSize); return false; } elts_size += elt->size; elt = (void *) elt + elt->size; //go to the next one } if ( elts_size != pollist->PolicyElementsSize ) { ERROR("Error: size incorrect (elt size): 0x%x != 0x%x\n", elts_size, pollist->PolicyElementsSize); return false; } if ( pollist->KeySignatureOffset == 0) { //List isn't signed so base size and elements size must be the same number //of bytes as the file LOG("LCP list has no signature - skipping signature verification.\n"); if (base_size + pollist->PolicyElementsSize != size) { ERROR("Error: incorrect KeySignatureOffset == 0 (no sig): 0x%x != 0x%x\n", base_size + pollist->PolicyElementsSize, size); return false; } else { DISPLAY("Verify TPM2.0 Policy List 2.1 success\n"); if (has_sig != NULL) *has_sig = false; return true; //list unsigned, function enc } } else { if (has_sig != NULL) *has_sig = true; return true; //list signed, func end } return false; } void display_tpm20_policy_list_2_1(const char *prefix, const lcp_policy_list_t2_1 *pollist, bool brief) /* This function: Displays contents of a policy list in a readable form In: Prefix, pointer to a policy list, brief: if true only short info is shown Out: Nothing */ { sig_key_2_1_header *sig_header; size_t elts_size; const lcp_policy_element_t *elt = NULL; lcp_signature_2_1 *sig = NULL; size_t new_prefix_size; if (prefix == NULL) prefix = ""; new_prefix_size = strnlen_s(prefix, 20) + 8; char new_prefix[new_prefix_size]; if ( pollist == NULL ) { ERROR("Error: policy list is not defined.\n"); return; } DISPLAY("LCP_POLICY_LIST_2_1 structure:\n"); DISPLAY("%s Version: 0x%x\n", prefix, pollist->Version); DISPLAY("%s KeySignatureOffset: 0x%x\n", prefix, pollist->KeySignatureOffset); DISPLAY("%s PolicyElementsSize: 0x%x\n", prefix, pollist->PolicyElementsSize); strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), " "); elts_size = pollist->PolicyElementsSize; elt = pollist->PolicyElements; uint16_t i = 0; while ( elts_size > 0 ) { DISPLAY("%s policy_element[%u]:\n", prefix, i++); display_policy_element(new_prefix, elt, brief); elts_size -= elt->size; elt = (void *)elt + elt->size; } if ( pollist->KeySignatureOffset == 0 ) { return; } sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { return; } sig_header = (sig_key_2_1_header*) sig; if ( sig_header->key_alg == TPM_ALG_RSA) { display_tpm20_signature_2_1(" ", sig, TPM_ALG_RSASSA); return; } if (sig_header->key_alg == TPM_ALG_ECC) { display_tpm20_signature_2_1(" ", sig, TPM_ALG_ECDSA); return; } return; } lcp_policy_list_t2_1 *create_empty_tpm20_policy_list_2_1(void) /* This function: Creates lcp list 2.1 base and returns it In: No args Out: Returns a pointer to an empty policy list version 2.1 */ { LOG("[create_empty_tpm20_policy_list_2_1]\n"); lcp_policy_list_t2_1 *pollist = malloc(offsetof(lcp_policy_list_t2_1, PolicyElements)); if (pollist == NULL) { ERROR("Error: failed to allocate memory\n"); return NULL; } pollist->Version = LCP_TPM20_POLICY_LIST2_1_VERSION_300; pollist->KeySignatureOffset = 0; pollist->PolicyElementsSize = 0; LOG("Create empty policy list 2.1 success\n"); return pollist; } lcp_policy_list_t2_1 *add_tpm20_policy_element_2_1(lcp_policy_list_t2_1 *pollist, const lcp_policy_element_t *elt) /* This function: adds element elt to a list 2.1 - pollist In: pointer to an lcp list 2.1 and element Out: Pointer to a copy of the original list with the element appended. */ { LOG("[add_tpm20_policy_element_2_1]\n"); if ( pollist == NULL || elt == NULL ) return NULL; size_t old_size = get_tpm20_policy_list_2_1_size(pollist); lcp_policy_list_t2_1 *new_pollist = realloc(pollist, old_size + elt->size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } memmove_s( (void *) &new_pollist->PolicyElements + elt->size, // dest old_size - offsetof(lcp_policy_list_t2_1, PolicyElements), // dmax &new_pollist->PolicyElements, // src old_size - offsetof(lcp_policy_list_t2_1, PolicyElements) // smax ); memcpy_s (&new_pollist->PolicyElements,elt->size, elt, elt->size); new_pollist->PolicyElementsSize += elt->size; LOG("Add tpm20 policy element successful\n"); return new_pollist; } bool get_ecc_signature_2_1_data(lcp_signature_2_1 *empty_sig, void *raw_data) { size_t sigscheme_offset; size_t signature_struct_offset; size_t key_size_bytes; uint16_t sig_scheme; size_t key_and_sig_offset = offsetof(lcp_signature_2_1, KeyAndSignature); size_t key_struct_offset = key_and_sig_offset + offsetof(ecc_key_and_signature, Key); size_t qx_qy_offset = key_struct_offset + offsetof(ecc_public_key, QxQy); if (empty_sig == NULL || raw_data == NULL) { ERROR("Error: signature or signature data not allocated.\n"); return false; } sig_key_2_1_header *sig_header = (sig_key_2_1_header *) raw_data; key_size_bytes = sig_header->key_size / 8; sigscheme_offset = qx_qy_offset+(2*key_size_bytes); signature_struct_offset = sigscheme_offset + sizeof(empty_sig->KeyAndSignature.RsaKeyAndSignature.SigScheme); if ( key_size_bytes != 32 && key_size_bytes != 48 ) { ERROR("ERROR: Key size not supported.\n"); return false; } empty_sig->RevocationCounter = sig_header->revoc_counter; empty_sig->KeyAndSignature.EccKeyAndSignature.Version = sig_header->version; empty_sig->KeyAndSignature.EccKeyAndSignature.KeyAlg = sig_header->key_alg; empty_sig->KeyAndSignature.EccKeyAndSignature.Key.Version = sig_header->key_ver; empty_sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize = sig_header->key_size; memcpy_s(empty_sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy, 2*MAX_ECC_KEY_SIZE, raw_data+qx_qy_offset, 2*key_size_bytes); memcpy_s((void*)&sig_scheme, sizeof(sig_scheme), raw_data+sigscheme_offset, sizeof(sig_scheme)); empty_sig->KeyAndSignature.EccKeyAndSignature.SigScheme = sig_scheme; memcpy_s( (void *)&empty_sig->KeyAndSignature.EccKeyAndSignature.Signature, sizeof(ecc_signature),raw_data+signature_struct_offset,sizeof(ecc_signature) ); return true; } bool get_rsa_signature_2_1_data(lcp_signature_2_1 *empty_sig, void *raw_data) { size_t sigscheme_offset; size_t signature_struct_offset; size_t key_size_bytes; uint32_t exponent; uint16_t sig_scheme; size_t key_and_sig_offset = offsetof(lcp_signature_2_1, KeyAndSignature); size_t key_struct_offset = key_and_sig_offset + offsetof(rsa_key_and_signature, Key); size_t exponent_offset = key_struct_offset + offsetof(rsa_public_key, Exponent); size_t mod_offset = key_struct_offset + offsetof(rsa_public_key, Modulus); if (empty_sig == NULL || raw_data == NULL) { ERROR("Error: signature or signature data not allocated.\n"); return false; } sig_key_2_1_header *sig_header = (sig_key_2_1_header *) raw_data; key_size_bytes = sig_header->key_size / 8; sigscheme_offset = mod_offset+key_size_bytes; signature_struct_offset = sigscheme_offset + sizeof(empty_sig->KeyAndSignature.RsaKeyAndSignature.SigScheme); if ( key_size_bytes != 256 && key_size_bytes != 384 ) { ERROR("ERROR: Key size not supported.\n"); return false; } empty_sig->RevocationCounter = sig_header->revoc_counter; empty_sig->KeyAndSignature.RsaKeyAndSignature.Version = sig_header->version; empty_sig->KeyAndSignature.RsaKeyAndSignature.KeyAlg = sig_header->key_alg; empty_sig->KeyAndSignature.RsaKeyAndSignature.Key.Version = sig_header->key_ver; empty_sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize = sig_header->key_size; memcpy_s((void *)&exponent, sizeof(exponent), raw_data+exponent_offset, sizeof(exponent)); empty_sig->KeyAndSignature.RsaKeyAndSignature.Key.Exponent = exponent; memcpy_s(empty_sig->KeyAndSignature.RsaKeyAndSignature.Key.Modulus, MAX_RSA_KEY_SIZE, raw_data+mod_offset, key_size_bytes); memcpy_s((void*)&sig_scheme, sizeof(sig_scheme), raw_data+sigscheme_offset, sizeof(sig_scheme)); empty_sig->KeyAndSignature.RsaKeyAndSignature.SigScheme = sig_scheme; memcpy_s( (void *)&empty_sig->KeyAndSignature.RsaKeyAndSignature.Signature, sizeof(rsa_signature),raw_data+signature_struct_offset,sizeof(rsa_signature) ); return true; } bool verify_tpm20_pollist_2_1_sig(lcp_policy_list_t2_1 *pollist) { bool result; sig_key_2_1_header *header; size_t base_size = offsetof(lcp_policy_list_t2_1, PolicyElements); size_t elts_size; lcp_signature_2_1 *sig; LOG("[verify_tpm20_pollist_2_1_sig]\n"); if (pollist == NULL) { ERROR("Error: failed to get policy list structure.\n"); return false; } elts_size = pollist->PolicyElementsSize; sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("Error: failed to get list signature.\n"); return false; } header = (sig_key_2_1_header *) sig; uint16_t expected_sig_offset = base_size + elts_size + offsetof(lcp_signature_2_1, KeyAndSignature); if (expected_sig_offset != pollist->KeySignatureOffset) { ERROR("Error: KeySignatureOffset incorrect. Expected: 0x%x, found: 0x%x\n", expected_sig_offset, pollist->KeySignatureOffset); return false; } if ( header->key_alg == TPM_ALG_RSA ) { LOG("Verifying signature against list data.\n"); result = verify_tpm20_pollist_2_1_rsa_sig(pollist); } else if ( header->key_alg == TPM_ALG_ECC ) { //This works with SM2 too. result = verify_tpm20_pollist_2_1_ec_sig(pollist); } else { //Function end ERROR("Error: signature verification failed - unknown key algorithm\n"); result = false; } return result; } bool verify_tpm20_pollist_2_1_ec_sig(const lcp_policy_list_t2_1 *pollist) { /* This functions prepares lcp policy list for verification, i.e. generates buffers for list data, public key components, signature components and passes all of it to ec_verify in lcputils In: pointer to properly allocated lcp_policy_list_t2_1 structure containing list and signature. Out: True on success, false on failure */ sized_buffer *pollist_data = NULL; sized_buffer *pubkey_x = NULL; sized_buffer *pubkey_y = NULL; sized_buffer *sig_r = NULL; sized_buffer *sig_s = NULL; lcp_signature_2_1 *sig = NULL; size_t keysize, data_size; //Keysize is in bytes bool result; uint16_t sigalg; uint16_t hashalg; LOG("[verify_tpm20_pollist_2_1_ec_sig]\n"); if (pollist == NULL) { ERROR("Error: policy list not defined.\n"); return false; } //Set size of signed data: data_size = pollist->KeySignatureOffset; //Get sig; sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("Error: failed to get signature 2.1.\n"); return false; } //Read data from sig structure: keysize = sig->KeyAndSignature.EccKeyAndSignature.Signature.KeySize / 8; sigalg = sig->KeyAndSignature.EccKeyAndSignature.SigScheme; hashalg = sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg; //Verify signature components: if ( sig->KeyAndSignature.EccKeyAndSignature.Version != SIGNATURE_VERSION) { ERROR("ERROR: KeyAndSignature struct version not 0x%x.\n", SIGNATURE_VERSION); return false; } if ( sig->KeyAndSignature.EccKeyAndSignature.KeyAlg != TPM_ALG_ECC ) { ERROR("ERROR: KeyAlg not TPM_ALG_ECC 0x%x.\n", TPM_ALG_ECC); return false; } if ( sigalg != TPM_ALG_ECDSA && sigalg != TPM_ALG_SM2) { ERROR("ERROR: signature scheme 0x%x not supported.\nExpected 0x18 or 0x1B\n", sig->KeyAndSignature.EccKeyAndSignature.SigScheme); return false; } if ( sig->KeyAndSignature.EccKeyAndSignature.Signature.Version != SIGNATURE_VERSION) { ERROR("ERROR: signature structure version not supported. Expected 0x%x, found: 0x%x\n", SIGNATURE_VERSION, sig->KeyAndSignature.RsaKeyAndSignature.Signature.Version); return false; } if ( hashalg != TPM_ALG_SHA256 && hashalg != TPM_ALG_SHA384 && hashalg != TPM_ALG_SM3_256) { ERROR("ERROR: hash alg not supported. Expected 0x0B, 0x0C or 0x12, found: 0x%x\n", hashalg); return false; } if ( keysize != MIN_ECC_KEY_SIZE && keysize != MAX_ECC_KEY_SIZE) { ERROR("Error: incorrect keysize, must be 256 or 384 bits. Found: 0x%x.\n", keysize * 8); return false; } if ( keysize != sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize / 8 ) { ERROR("ERROR: keysize mismatch between key and signature. Expected:" " 0x%x, found: 0x%x\n", keysize*8, keysize); return false; } //Allocate buffers: pollist_data = allocate_sized_buffer(data_size); pubkey_x = allocate_sized_buffer(keysize); pubkey_y = allocate_sized_buffer(keysize); sig_r = allocate_sized_buffer(keysize); sig_s = allocate_sized_buffer(keysize); if (pollist_data == NULL || pubkey_x == NULL || pubkey_y == NULL || sig_r == NULL || sig_s == NULL) { ERROR("Error: failed to allocate data structure.\n"); result = false; goto EXIT; } pollist_data->size = data_size; pubkey_x->size = keysize; pubkey_y->size = keysize; sig_r->size = keysize; sig_s->size = keysize; //Copy data to buffers memcpy_s( (void *) pollist_data->data, pollist_data->size, (const void *) pollist, data_size ); memcpy_s( (void *) pubkey_x->data, pubkey_x->size, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy, keysize ); memcpy_s( (void *) pubkey_y->data, pubkey_y->size, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy + keysize, keysize ); memcpy_s( (void *) sig_r->data, sig_r->size, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Signature.sigRsigS, keysize ); memcpy_s( (void *) sig_s->data, sig_s->size, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Signature.sigRsigS + keysize, keysize ); //r, s, x, y are LE in lcp but openssl needs them BE, so we will flip them. buffer_reverse_byte_order((uint8_t *) pubkey_x->data, pubkey_x->size); buffer_reverse_byte_order((uint8_t *) pubkey_y->data, pubkey_y->size); buffer_reverse_byte_order((uint8_t *) sig_r->data, sig_r->size); buffer_reverse_byte_order((uint8_t *) sig_s->data, sig_s->size); //Now verify: result = verify_ec_signature(pollist_data, pubkey_x, pubkey_y, sig_r, sig_s, sigalg, hashalg); if (!result) { ERROR("Error: failed to verify SM2 signature.\n"); } EXIT: if (pollist_data != NULL) { free(pollist_data); } if (pubkey_x != NULL) { free(pubkey_x); } if (pubkey_y != NULL) { free(pubkey_y); } if (sig_r != NULL) { free(sig_r); } if (sig_s != NULL) { free(sig_s); } return result; } bool verify_tpm20_pollist_2_1_rsa_sig(lcp_policy_list_t2_1 *pollist) /* This function: verifies rsa signature block in policy list In: policy list data that was signed, data size, signature 2.1 structure Out: true if verifies false if not */ { LOG("[verify_tpm20_pollist_2_1_rsa_sig]\n"); bool result; size_t key_size_bytes; size_t sig_key_size; uint16_t sig_alg; uint16_t hash_alg_sig; lcp_signature_2_1 *sig = NULL; //Dynamic buffers: sized_buffer *list_data = NULL; //Free before return sized_buffer *key_buffer = NULL; //Free before return sized_buffer *signature_buffer = NULL; //Free before return if (pollist == NULL) { ERROR("Error: failed to get list data.\n"); return false; } sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("Error: failed to get signature.\n"); return false; } key_size_bytes = sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8; if ( sig->KeyAndSignature.RsaKeyAndSignature.Version != SIGNATURE_VERSION) { ERROR("ERROR: KeyAndSignature struct version not 0x%x.", SIGNATURE_VERSION); return false; } if ( sig->KeyAndSignature.RsaKeyAndSignature.KeyAlg != TPM_ALG_RSA ) { ERROR("ERROR: KeyAlg not TPM_ALG_RSA 0x%x.", TPM_ALG_RSA); return false; } if (key_size_bytes != 256 && key_size_bytes != 384) { ERROR("ERROR: key size %d not supported.\n", key_size_bytes); return false; } if ( sig->KeyAndSignature.RsaKeyAndSignature.Key.Exponent != LCP_SIG_EXPONENT ) { ERROR("ERROR: RSA exponent not 0x%x.", LCP_SIG_EXPONENT); return false; } sig_alg = sig->KeyAndSignature.RsaKeyAndSignature.SigScheme; if ( sig_alg != TPM_ALG_RSASSA && sig_alg != TPM_ALG_RSAPSS ) { ERROR("ERROR: signature scheme 0x%x not supported.\nExpected 0x14 or 0x16", sig_alg); return false; } if ( sig->KeyAndSignature.RsaKeyAndSignature.Signature.Version != SIGNATURE_VERSION) { ERROR("ERROR: signature structure version not supported. Expected 0x%x, found: 0x%x", SIGNATURE_VERSION, sig->KeyAndSignature.RsaKeyAndSignature.Signature.Version); return false; } hash_alg_sig = sig->KeyAndSignature.RsaKeyAndSignature.Signature.HashAlg; if ( hash_alg_sig != TPM_ALG_SHA256 && hash_alg_sig != TPM_ALG_SHA384 ) { ERROR("ERROR: hash alg not supported. Expected 0x0B or 0x0C, found: 0x%x\n", hash_alg_sig); return false; } sig_key_size = sig->KeyAndSignature.RsaKeyAndSignature.Signature.KeySize; if ( sig_key_size != sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize ) { ERROR("ERROR: keysize mismatch between key and signature. Expected:" " 0x%x, found: 0x%x", key_size_bytes, sig_key_size/8); return false; } list_data = allocate_sized_buffer(pollist->KeySignatureOffset); if (list_data == NULL) { ERROR("Error: failed to allocate memory for list data.\n"); return false; } key_buffer = allocate_sized_buffer(key_size_bytes); if (key_buffer == NULL){ ERROR("Error: failed to allocate memory for buffer.\n"); free(list_data); return false; } signature_buffer = allocate_sized_buffer(key_size_bytes); if (signature_buffer == NULL ){ ERROR("Error: failed to allocate memory for buffer.\n"); free(list_data); free(key_buffer); return false; } list_data->size = pollist->KeySignatureOffset; key_buffer->size = key_size_bytes; signature_buffer->size = key_size_bytes; memcpy_s( (void *) list_data->data, list_data->size, (const void *) pollist, pollist->KeySignatureOffset); memcpy_s( (void *) key_buffer->data, key_size_bytes, (const void *) sig->KeyAndSignature.RsaKeyAndSignature.Key.Modulus, key_size_bytes); memcpy_s( (void *)signature_buffer->data, key_size_bytes, (const void *) sig->KeyAndSignature.RsaKeyAndSignature.Signature.Signature, key_size_bytes); //Remember that key and sig are LE in pollist file, must be BE for openssll buffer_reverse_byte_order((uint8_t *) signature_buffer->data, signature_buffer->size); buffer_reverse_byte_order((uint8_t *) key_buffer->data, key_buffer->size); result = verify_rsa_signature(list_data, key_buffer, signature_buffer, hash_alg_sig, sig_alg, LCP_TPM20_POLICY_LIST2_1_VERSION_300); if (result) { DISPLAY("List signature verified positively.\n"); } else { DISPLAY("List signature did not verify.\n"); } free(key_buffer); free(signature_buffer); free(list_data); return result; } void display_tpm20_signature_2_1(const char *prefix, const lcp_signature_2_1 *sig, const uint16_t sig_alg) /* This function: prints sigblock nicely formatted In: Out: */ { LOG("[display_tpm20_signature_2_1]\n"); size_t new_prefix_len = 0; if (sig == NULL) { ERROR("Error: failed to get list signature.\n"); return; } if (*prefix == '\0') new_prefix_len = 8; else new_prefix_len = strnlen_s(prefix, 20) + 8; char new_prefix[new_prefix_len]; //To make digests indented. strcpy_s(new_prefix, sizeof(new_prefix), prefix); strcat_s(new_prefix, sizeof(new_prefix), "\t"); size_t keysize; DISPLAY ("%s revocation_counter: 0x%x (%u)\n", prefix, sig->RevocationCounter, sig->RevocationCounter); switch ( sig_alg ) { case TPM_ALG_RSASSA: case TPM_ALG_RSAPSS: ; DISPLAY("RSA_KEY_AND_SIGNATURE:\n"); keysize = sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8; DISPLAY ("%s Version: 0x%x\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Version); DISPLAY ("%s KeyAlg: 0x%x (%s)\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.KeyAlg, key_alg_to_str(sig->KeyAndSignature.RsaKeyAndSignature.KeyAlg) ); DISPLAY("RSA_PUBLIC_KEY:\n"); DISPLAY ("%s Version: 0x%x\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Key.Version); DISPLAY ("%s KeySize: 0x%x", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize); DISPLAY(" (%u)\n", sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize); DISPLAY ("%s Exponent: 0x%x\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Key.Exponent); DISPLAY ("%s Modulus:\n", prefix); print_hex( new_prefix, sig->KeyAndSignature.RsaKeyAndSignature.Key.Modulus, keysize ); DISPLAY("End of RSA_PUBLIC_KEY\n"); DISPLAY ( "%s SigScheme: 0x%x (%s)\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.SigScheme, sig_alg_to_str(sig->KeyAndSignature.RsaKeyAndSignature.SigScheme) ); DISPLAY("RSA_SIGNATURE:\n"); DISPLAY ("%s Version: 0x%x\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Signature.Version); DISPLAY ("%s KeySize: 0x%x", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Signature.KeySize); DISPLAY(" (%u)\n", sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize); DISPLAY ( "%s HashAlg: 0x%x (%s)\n", prefix, sig->KeyAndSignature.RsaKeyAndSignature.Signature.HashAlg, hash_alg_to_str(sig->KeyAndSignature.RsaKeyAndSignature.Signature.HashAlg) ); DISPLAY("%s sig_block:\n", prefix); print_hex( new_prefix, sig->KeyAndSignature.RsaKeyAndSignature.Signature.Signature, keysize ); break; case TPM_ALG_SM2: //Process is the same as for ECDSA case TPM_ALG_ECDSA: DISPLAY("ECC_KEY_AND_SIGNATURE:\n"); keysize = sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize / 8; DISPLAY ("%s Version: 0x%x\n", prefix, sig->KeyAndSignature.EccKeyAndSignature.Version); DISPLAY ( "%s KeyAlg: 0x%x (%s)\n", prefix, sig->KeyAndSignature.EccKeyAndSignature.KeyAlg, key_alg_to_str(sig->KeyAndSignature.EccKeyAndSignature.KeyAlg) ); DISPLAY("ECC_PUBLIC_KEY:\n"); DISPLAY ("%s Version: 0x%x\n", prefix, sig->KeyAndSignature.EccKeyAndSignature.Key.Version); DISPLAY ("%s KeySize: 0x%x", prefix, sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize); DISPLAY(" (%u)\n", sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize); DISPLAY ("Public key Qx: \n"); print_hex(new_prefix, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy, keysize); DISPLAY ("Public key Qy: \n"); print_hex(new_prefix, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy+ keysize, keysize); DISPLAY("End of ECC_PUBLIC_KEY\n"); DISPLAY ( "%s SigScheme: 0x%x (%s)\n", prefix, sig->KeyAndSignature.EccKeyAndSignature.SigScheme, sig_alg_to_str(sig->KeyAndSignature.EccKeyAndSignature.SigScheme) ); DISPLAY("ECC_SIGNATURE:\n"); DISPLAY ("%s Version: 0x%x\n", prefix, sig->KeyAndSignature.EccKeyAndSignature.Signature.Version); DISPLAY ("%s KeySize: 0x%x", prefix, sig->KeyAndSignature.EccKeyAndSignature.Signature.KeySize); DISPLAY(" (%u)\n", sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize); DISPLAY ( "%s HashAlg: 0x%x (%s)\n", prefix, sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg, hash_alg_to_str(sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg) ); DISPLAY ("Signature R part: \n"); print_hex(new_prefix, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Signature.sigRsigS, keysize); DISPLAY ("Signature S part: \n"); print_hex(new_prefix, (const void *) sig->KeyAndSignature.EccKeyAndSignature.Signature.sigRsigS+keysize, keysize); break; default: break; } } lcp_policy_list_t2_1 *add_tpm20_signature_2_1(lcp_policy_list_t2_1 *pollist, lcp_signature_2_1 *sig, const uint16_t sig_alg) /* This function: Adds signature fields to the list that hasn't got them In: pointer to LCP list, pointer to signature, signature alg Out: copy of a list with signature added */ { size_t old_size; size_t sig_size; size_t sig_begin; lcp_policy_list_t2_1 *new_pollist; LOG("[add_tpm20_signature_2_1]\n"); if ( pollist == NULL || sig == NULL ) { LOG("add_tpm20_signature_2_1 pollist or signature == NULL"); return NULL; } switch (sig_alg) { case TPM_ALG_RSASSA: case TPM_ALG_RSAPSS: old_size = get_tpm20_policy_list_2_1_size(pollist); if ( old_size != offsetof(lcp_policy_list_t2_1, PolicyElements) + pollist->PolicyElementsSize) { DISPLAY("List already signed"); return pollist; } sig_size = offsetof(lcp_signature_2_1, KeyAndSignature) + sizeof(rsa_key_and_signature); pollist->KeySignatureOffset = old_size + offsetof(lcp_signature_2_1, KeyAndSignature); new_pollist = realloc(pollist, old_size + sig_size); if ( new_pollist == NULL ){ ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } sig_begin = old_size; memcpy_s((void *)new_pollist + sig_begin, sig_size, sig, sig_size); return new_pollist; case TPM_ALG_SM2: // Process is the same as for ECDSA case TPM_ALG_ECDSA: old_size = get_tpm20_policy_list_2_1_size(pollist); if ( old_size != offsetof(lcp_policy_list_t2_1, PolicyElements) + pollist->PolicyElementsSize) { DISPLAY("ERROR: List already signed"); return pollist; } sig_size = offsetof(lcp_signature_2_1, KeyAndSignature) + sizeof(ecc_key_and_signature); pollist->KeySignatureOffset = old_size + offsetof(lcp_signature_2_1, KeyAndSignature); new_pollist = realloc(pollist, old_size + sig_size); if ( new_pollist == NULL ){ ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } sig_begin = old_size; memcpy_s((void *)new_pollist + sig_begin, sig_size, sig, sig_size); return new_pollist; default: return NULL; } } bool calc_tpm20_policy_list_2_1_hash(const lcp_policy_list_t2_1 *pollist, lcp_hash_t2 *hash, uint16_t hash_alg) /* This function: Hashes LCP_POLICY_LIST_2_1 data. If unsigned: entire list, else: modulus or qx qy In: policy list, hash t2 structure and hashalg Out: void */ { uint16_t key_alg; size_t buff_size; bool result; if (pollist == NULL) { ERROR("ERROR: LCP list not defined.\n"); return false; } if (hash == NULL) { ERROR("ERROR: Hash buffer not defined.\n"); return false; } LOG("[calc_tpm20_policy_list_2_1_hash]\n"); if (pollist->KeySignatureOffset == 0) { //Not signed buff_size = get_tpm20_policy_list_2_1_size(pollist); if (!hash_buffer((const unsigned char *) pollist, buff_size, (tb_hash_t *) hash, hash_alg)) { ERROR("ERROR: failed to hash list data.\n"); return false; } else { return true; } } else if ( pollist->KeySignatureOffset > 0 ) { lcp_signature_2_1 *sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("ERROR: failed to load LCP policy signature\n"); return false; } key_alg = get_signature_2_1_key_alg(sig); switch (key_alg) { case TPM_ALG_RSA: LOG("List signed: RSA\n"); //keysize in lcp signature 2.1 is in bits buff_size = sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8; result = hash_buffer( (const unsigned char *) sig->KeyAndSignature.RsaKeyAndSignature.Key.Modulus, buff_size, (tb_hash_t *) hash, hash_alg); if (!result) { ERROR("ERROR: failed to allocate buffer\n"); return false; } else { return true; } case TPM_ALG_ECC: LOG("List signed: ECC\n"); //keysize in lcp signature 2.1 is in bits //Qx and Qy are each KeySize buff_size = 2 * (sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize / 8); result = hash_buffer( (const unsigned char *) sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy, buff_size, (tb_hash_t *) hash, hash_alg); if (!result) { ERROR("ERROR: failed to allocate buffer\n"); return false; } else { return true; } default: ERROR("ERROR: unknown key_alg.\n"); return false; } } else { ERROR("KeySignatureOffset must be equal to or greater than zero.\n"); return false; } } unsigned char *fill_tpm20_policy_list_2_1_buffer(const lcp_policy_list_t2_1 *pollist, size_t *len) /* This function: writes LCP policy list 2.1 with or without signature to a buffer In: policy list 2.1 structure, pointer to var that will hold filled buffer size Out: handle to buffer containing contiguous policy list data. */ { int result; size_t list_size, buffer_size, key_size, bytes_written, bytes_to_copy; //Buffer_size will be decremented by amount of bytes_written each time we copy mem. uint16_t key_alg; lcp_signature_2_1 *sig; unsigned char *to_buffer; bytes_written = 0; LOG("[fill_tpm20_policy_list_2_1_buffer]\n"); if ( pollist == NULL ) { ERROR("Error: policy list not defined.\n"); return NULL; } list_size = get_tpm20_list_2_1_real_size(pollist); //NOT structure size but actual size if (!list_size) { ERROR("Error: failed to get list size.\n"); return NULL; } buffer_size = list_size; //They are the same *len = buffer_size; to_buffer = malloc(buffer_size); if (to_buffer == NULL) { ERROR("Error: failed to allocate buffer.\n"); return NULL; } if ( pollist->KeySignatureOffset == 0 ) { //No signature if (memcpy_s((void *)to_buffer, buffer_size, (const void*) pollist, list_size) != EOK) { ERROR("Error: failed to copy list data.\n"); free(to_buffer); return NULL; } return to_buffer; } sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("Error: signature not defined.\n"); free(to_buffer); return NULL; } key_alg = get_signature_2_1_key_alg(sig); //First copy list without signature bytes_to_copy = pollist->KeySignatureOffset - offsetof(lcp_signature_2_1, KeyAndSignature); result = memcpy_s((void *) to_buffer, buffer_size, (const void *)pollist, bytes_to_copy); if (result != EOK) { ERROR("Error: failed to copy list data.\n"); free(to_buffer); return NULL; } bytes_written += bytes_to_copy; buffer_size -= bytes_to_copy; //Signature: switch (key_alg) { case TPM_ALG_RSA: //Copy key part of the sig. key_size = sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8; bytes_to_copy = offsetof(lcp_signature_2_1, KeyAndSignature) + offsetof(rsa_key_and_signature, Key) + sizeof(rsa_public_key) - (MAX_RSA_KEY_SIZE - key_size); result = memcpy_s((void *)to_buffer+bytes_written, buffer_size, (const void *) sig, bytes_to_copy); if (result != EOK) { ERROR("Error: failed to copy list data.\n"); free(to_buffer); return NULL; } sig = (void *)sig + offsetof(lcp_signature_2_1, KeyAndSignature); //Move over revoc_counter sig = (void *)sig + offsetof(rsa_key_and_signature, SigScheme); //Move to sig scheme bytes_written += bytes_to_copy; buffer_size -= bytes_to_copy; //Copy rest of the sig bytes_to_copy = sizeof(sig->KeyAndSignature.RsaKeyAndSignature.SigScheme) + sizeof(rsa_signature) - (MAX_RSA_KEY_SIZE - key_size); result = memcpy_s((void *)to_buffer+bytes_written, buffer_size, (const void *) sig, bytes_to_copy); if (result != EOK) { ERROR("Error: failed to copy list data.\n"); free(to_buffer); return NULL; } break; case TPM_ALG_ECC: //Copy key part of the sig. key_size = sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize / 8; bytes_to_copy = offsetof(lcp_signature_2_1, KeyAndSignature) + offsetof(ecc_key_and_signature, Key) + sizeof(ecc_public_key) - 2*(MAX_ECC_KEY_SIZE - key_size); result = memcpy_s((void *)to_buffer+bytes_written, buffer_size, (const void *) sig, bytes_to_copy); if (result != EOK) { ERROR("Error: failed to copy list data.\n"); free(to_buffer); return NULL; } sig = (void *)sig + offsetof(lcp_signature_2_1, KeyAndSignature); //Move over revoc_counter sig = (void *)sig + offsetof(ecc_key_and_signature, SigScheme); //Move to sig scheme bytes_written += bytes_to_copy; buffer_size -= bytes_to_copy; //Copy rest of the sig bytes_to_copy = sizeof(sig->KeyAndSignature.EccKeyAndSignature.SigScheme) + sizeof(ecc_signature) - 2*(MAX_ECC_KEY_SIZE - key_size); result = memcpy_s((void *)to_buffer+bytes_written, buffer_size, (const void *) sig, bytes_to_copy); if (result != EOK) { ERROR("Error: failed to copy list data.\n"); free(to_buffer); return NULL; } break; default: ERROR("Error: unsupported key algorithm.\n"); free(to_buffer); return NULL; } return to_buffer; } uint16_t get_signature_2_1_key_alg(const lcp_signature_2_1 *sig) { return *(uint16_t *) ((void *)sig + SIG_KEY_SIG_KEY_ALG_OFFSET); } size_t get_tpm20_key_and_signature_2_1_real_size(const lcp_signature_2_1 *sig) /* This function: calculates real size of the signature structure In: signature structure handle Out: signature size, or 0 on error. */ { uint16_t key_alg; size_t key_size_bytes; size_t sig_size = 0; LOG("[get_tpm20_key_and_signature_2_1_real_size]\n"); if (sig == NULL) { return 0; } key_alg = get_signature_2_1_key_alg(sig); switch (key_alg) { case TPM_ALG_RSA: key_size_bytes = sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8; sig_size = sizeof(rsa_key_and_signature) - 2 * (MAX_RSA_KEY_SIZE - key_size_bytes); return sig_size; case TPM_ALG_ECC: key_size_bytes = sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize / 8; sig_size = sizeof(ecc_key_and_signature) - 4 * (MAX_ECC_KEY_SIZE - key_size_bytes); return sig_size; default: ERROR("Error: unknown key algorithm.\n"); return 0; } } size_t get_tpm20_list_2_1_real_size(const lcp_policy_list_t2_1 *pollist) /* This function: lcp list 2.1 has dynamic size, especially with signature. This calculates size of lcp list as if it is supposed to be written to a file In: pointer to a list structure Out: real size of a list, or 0 on failure */ { size_t size = 0; size_t sig_size = 0; LOG("[get_tpm20_list_2_1_real_size]\n"); if (pollist == NULL) { return size; } if (pollist->KeySignatureOffset == 0) //Not signed size = offsetof(lcp_policy_list_t2_1, PolicyElements)+pollist->PolicyElementsSize; else { //list signed lcp_signature_2_1 *sig = get_tpm20_signature_2_1(pollist); if ( sig == NULL ) { ERROR("Failed to get signature.\n"); size = 0; return size; } sig_size = get_tpm20_key_and_signature_2_1_real_size(sig); if (sig_size == 0) { ERROR("Failed to calculate signature size.\n"); return sig_size; } size = pollist->KeySignatureOffset + sig_size; return size; } return size; } bool write_tpm20_policy_list_2_1_file(const char *file, const lcp_policy_list_t2_1 *pollist) /* This function: writes LCP policy list 2.1 to a file In: file handle, list structure handle Out: true/false write success or failure */ { unsigned char *buffer = NULL; size_t buffer_size; //For unsigned list LOG("[write_tpm20_policy_list_2_1_file]\n"); if (pollist == NULL) { ERROR("Error: policy list undefined.\n"); return false; } //No sig: if ( pollist->KeySignatureOffset == 0 ) { if (!write_file(file, (const void *) pollist, get_tpm20_policy_list_2_1_size(pollist))) { ERROR("ERROR: Failed to write.\n"); return false; } else { return true; } } buffer = fill_tpm20_policy_list_2_1_buffer(pollist, &buffer_size); if ( buffer == NULL ) { ERROR("ERROR: Failed to allocate buffer.\n"); return false; } if (!write_file(file, buffer, buffer_size)) { ERROR("ERROR: Failed to write.\n"); free(buffer); return false; } else { LOG("Write successful.\n"); free(buffer); return true; } } static lcp_signature_2_1 *read_rsa_pubkey_file_2_1(const char *file) /* This function: extracts rsa data to a lcp_signature_2_1 structure In: path to file containing RSA public key Out: Pointer to signature structure. */ { FILE *fp = NULL; BIGNUM *modulus = NULL; #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY *pubkey = NULL; #else RSA *pubkey = NULL; #endif lcp_signature_2_1 *sig = NULL; unsigned char *key = NULL; int keysize = 0; int result = 0; LOG("read_rsa_pubkey_file_2_1\n"); fp = fopen(file, "rb"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", file, strerror(errno)); return NULL; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L OSSL_DECODER_CTX *dctx; dctx = OSSL_DECODER_CTX_new_for_pkey(&pubkey, "PEM", NULL, "RSA", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL); if ( dctx == NULL ) { goto OPENSSL_ERROR; } if ( !OSSL_DECODER_from_fp(dctx, fp) ) { goto OPENSSL_ERROR; } OSSL_DECODER_CTX_free(dctx); #else pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); #endif if ( pubkey == NULL ) { goto OPENSSL_ERROR; } //Close the file, won't need it anymore fclose(fp); fp = NULL; #if OPENSSL_VERSION_NUMBER >= 0x30000000L keysize = EVP_PKEY_get_size(pubkey); #else keysize = RSA_size(pubkey); #endif if ( keysize != 256 && keysize != 384 ) { ERROR("Error: public key size %d is not supported\n", keysize); goto ERROR; } sig = create_empty_rsa_signature_2_1(); //Sig has all 0-s if ( sig == NULL ) { ERROR("Error: failed to create empty lcp signature 2.1\n"); goto ERROR; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY_get_bn_param(pubkey, "n", &modulus); #elif OPENSSL_VERSION_NUMBER >= 0x10100000L RSA_get0_key(pubkey, (const BIGNUM **) &modulus, NULL, NULL); #else modulus = pubkey->n; #endif if (modulus == NULL) { goto OPENSSL_ERROR; } //Allocate for the key key = malloc(keysize); if (key == NULL) { ERROR("Error: failed to allocate memory for public key.\n"); goto ERROR; } //Save mod into key array result = BN_bn2bin(modulus, key); if (result <= 0 || result != keysize) { goto OPENSSL_ERROR; } /* openssl key is big-endian and policy requires little-endian, so reverse bytes and append to sig*/ for ( int i = 0; i < keysize; i++ ) { sig->KeyAndSignature.RsaKeyAndSignature.Key.Modulus[i] = key[keysize -i -1]; } sig->KeyAndSignature.RsaKeyAndSignature.KeyAlg = TPM_ALG_RSA; sig->KeyAndSignature.RsaKeyAndSignature.Version = SIGNATURE_VERSION; sig->KeyAndSignature.RsaKeyAndSignature.Key.Version= SIGNATURE_VERSION; sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize = keysize*8; //Must be in bits sig->KeyAndSignature.RsaKeyAndSignature.Key.Exponent = LCP_SIG_EXPONENT; sig->KeyAndSignature.RsaKeyAndSignature.Signature.Version = SIGNATURE_VERSION; sig->KeyAndSignature.RsaKeyAndSignature.Signature.KeySize = keysize*8; //Must be bits if ( verbose ) { LOG("read_rsa_pubkey_file: signature:\n"); display_tpm20_signature_2_1(" ", sig, TPM_ALG_RSAPSS); } //SUCCESS: OPENSSL_free((void *) pubkey); OPENSSL_free((void * )modulus); free(key); return sig; OPENSSL_ERROR: ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); goto ERROR; ERROR: if (fp != NULL) fclose(fp); if (key != NULL) free(key); if (sig != NULL) free(sig); if (modulus == NULL) OPENSSL_free((void *) modulus); if (pubkey != NULL) OPENSSL_free((void *) pubkey); return NULL; } bool rsa_sign_list_2_1_data(lcp_policy_list_t2_1 *pollist, const char *privkey_file) { /* This function: prepares policy list 2.1 for signing using either RSASSA PKCS1.5 or RSA-PSS algorithm. In: pointer to a policy list, path to a private key Out: True on success, false on failure */ uint16_t hashalg; uint16_t keysize; uint16_t sig_alg; bool status; lcp_signature_2_1 *sig = NULL; sized_buffer *digest = NULL; sized_buffer *sig_block = NULL; //Buffer for generated sig EVP_PKEY_CTX *context = NULL; //Context for openssl functions LOG("rsa_sign_list_2_1_data\n"); if ( pollist == NULL || privkey_file == NULL ) return false; //Get signature sig = get_tpm20_signature_2_1(pollist); if ( sig == NULL) { return false; } hashalg = sig->KeyAndSignature.RsaKeyAndSignature.Signature.HashAlg; //keysize var is in bytes, the one in structure is bits keysize = sig->KeyAndSignature.RsaKeyAndSignature.Signature.KeySize / 8; sig_alg = sig->KeyAndSignature.RsaKeyAndSignature.SigScheme; //Hash list data up to - but not including - keySignature structure. //KeySignatureOffset tells us how many bytes to hash if (verbose) { DISPLAY("Data to hash:\n"); print_hex(" ", (const unsigned char *) pollist, pollist->KeySignatureOffset); } digest = allocate_sized_buffer(get_lcp_hash_size(hashalg)); if (digest == NULL) { ERROR("Error: failed to allocate buffer.\n"); goto ERROR; } digest->size = get_lcp_hash_size(hashalg); status = hash_buffer((const unsigned char *) pollist, pollist->KeySignatureOffset, (tb_hash_t *) digest->data, hashalg); if ( !status ) { ERROR("Error: failed to hash list\n"); goto ERROR; } if ( verbose ) { LOG("digest:\n"); print_hex("", &digest, get_hash_size(hashalg)); } //Create context using key context = rsa_get_sig_ctx(privkey_file, keysize); if ( context == NULL) { ERROR("ERROR: failed to initialize EVP context.\n"); goto ERROR; } //Allocate mem for signature block: sig_block = allocate_sized_buffer(keysize); if (sig_block == NULL) { ERROR("ERROR: failed to allocate memory for signature block.\n"); goto ERROR; } sig_block->size = keysize; //Sign status = rsa_ssa_pss_sign(sig_block, digest, sig_alg, hashalg, context); if (!status) { ERROR("ERROR: failed to sign list data."); goto ERROR; } //Copy sig_block to signature, flip endianness buffer_reverse_byte_order((uint8_t *) sig_block->data, sig_block->size); memcpy_s((void *) sig->KeyAndSignature.RsaKeyAndSignature.Signature.Signature, keysize, (const void *) sig_block->data, sig_block->size); if ( verbose ) { LOG("Signature: \n"); display_tpm20_signature_2_1(" ", sig, sig_alg); } if (sig_block != NULL) { free(sig_block); } if (digest != NULL) { free(digest); } if (context != NULL) OPENSSL_free(context); return true; ERROR: if (sig_block != NULL) { free(sig_block); } if (digest != NULL) { free(digest); } if (context != NULL) OPENSSL_free(context); return false; } static lcp_signature_2_1 *read_ecdsa_pubkey_file_2_1(const char *pubkey_file) { int result; lcp_signature_2_1 *sig = NULL; FILE *fp = NULL; BIGNUM *x = NULL; BIGNUM *y = NULL; uint16_t bytes_in_x; uint16_t bytes_in_y; uint16_t keySize; uint16_t keySizeBytes; uint8_t qx[MAX_ECC_KEY_SIZE]; uint8_t qy[MAX_ECC_KEY_SIZE]; uint8_t qx_le[MAX_ECC_KEY_SIZE]; uint8_t qy_le[MAX_ECC_KEY_SIZE]; #if OPENSSL_VERSION_NUMBER < 0x30000000L const EC_KEY *pubkey = NULL; const EC_POINT *pubpoint = NULL; const EC_GROUP *pubgroup = NULL; BN_CTX *ctx = NULL; #else EVP_PKEY *pubkey = NULL; #endif fp = fopen(pubkey_file, "rb"); if ( fp == NULL) { ERROR("ERROR: cannot open file.\n"); goto ERROR; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L OSSL_DECODER_CTX *dctx; dctx = OSSL_DECODER_CTX_new_for_pkey(&pubkey, "PEM", NULL, "EC", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL); if ( dctx == NULL ) { goto OPENSSL_ERROR; } if ( !OSSL_DECODER_from_fp(dctx, fp) ) { goto OPENSSL_ERROR; } OSSL_DECODER_CTX_free(dctx); if ( pubkey == NULL ) { goto OPENSSL_ERROR; } EVP_PKEY_get_bn_param(pubkey, "qx", &x); EVP_PKEY_get_bn_param(pubkey, "qy", &y); if ( x == NULL|| y == NULL ) { goto OPENSSL_ERROR; } #else pubkey = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL); if ( pubkey == NULL ) { goto OPENSSL_ERROR; } pubpoint = EC_KEY_get0_public_key(pubkey); if ( pubpoint == NULL ) { goto OPENSSL_ERROR; } pubgroup = EC_KEY_get0_group(pubkey); if ( pubgroup == NULL ) { goto OPENSSL_ERROR; } x = BN_new(); y = BN_new(); if ( x == NULL|| y == NULL ) { goto OPENSSL_ERROR; } ctx = BN_CTX_new(); if ( ctx == NULL ) { goto OPENSSL_ERROR; } result = EC_POINT_get_affine_coordinates_GFp(pubgroup, pubpoint, x, y, ctx); if (result <= 0) { goto OPENSSL_ERROR; } #endif //Close the file fclose(fp); fp = NULL; bytes_in_x = BN_num_bytes(x); bytes_in_y = BN_num_bytes(y); keySize = bytes_in_x*8; if (bytes_in_x != bytes_in_y) { ERROR("ERROR: key coordinates are not the same length."); goto ERROR; } if ( keySize != 256 && keySize != 384 ) { ERROR("ERROR: keySize 0x%X is not 0x%X or 0x%X.\n", keySize/8, MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE); goto ERROR; } keySizeBytes = bytes_in_x; if ( keySize/8 != bytes_in_x || keySize/8 != bytes_in_y ) { ERROR("ERROR: keySize 0x%X is not 0x%X or 0x%X.\n", keySizeBytes, MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE); goto ERROR; } sig = create_empty_ecc_signature_2_1(); if ( sig == NULL ) { ERROR("ERROR: failed to generate ecc signature 2.1.\n"); goto ERROR; } sig->KeyAndSignature.EccKeyAndSignature.Version = SIGNATURE_VERSION; sig->KeyAndSignature.EccKeyAndSignature.KeyAlg = TPM_ALG_ECC; sig->KeyAndSignature.EccKeyAndSignature.Key.Version = SIGNATURE_VERSION; sig->KeyAndSignature.EccKeyAndSignature.Key.KeySize = keySize; //In bits! sig->KeyAndSignature.EccKeyAndSignature.Signature.Version = SIGNATURE_VERSION; sig->KeyAndSignature.EccKeyAndSignature.Signature.KeySize = keySize; if (keySize == 256) { //256 bit key with sha256 sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg = TPM_ALG_SHA256; } else { //384 bit key with sha384 sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg = TPM_ALG_SHA384; } if (!BN_bn2bin(x, qx)) { goto OPENSSL_ERROR; } if (!BN_bn2bin(y, qy)) { goto OPENSSL_ERROR; } for (uint8_t i = 0; i < keySizeBytes; i++) { //reverse qx_le[i] = qx[keySizeBytes-1-i]; qy_le[i] = qy[keySizeBytes-1-i]; } result = memcpy_s( (void*)sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy, 2*MAX_ECC_KEY_SIZE, qx_le, bytes_in_x ); if ( result != EOK ) { ERROR("ERROR: Cannot copy key data to LCP list\n"); goto ERROR; } result = memcpy_s( (void*)sig->KeyAndSignature.EccKeyAndSignature.Key.QxQy + bytes_in_x, (2*MAX_ECC_KEY_SIZE)-bytes_in_x, qy_le, bytes_in_y ); if ( result != EOK ) { ERROR("ERROR: Cannot copy key data to LCP list\n"); goto ERROR; } //Free resources: OPENSSL_free((void *) pubkey); OPENSSL_free((void *) x); OPENSSL_free((void *) y); #if OPENSSL_VERSION_NUMBER < 0x30000000L OPENSSL_free((void *) pubpoint); OPENSSL_free((void *) pubgroup); OPENSSL_free((void *) ctx); #endif return sig; //ERROR handling: OPENSSL_ERROR: ERR_load_crypto_strings(); ERROR("OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); ERROR: //Free all OPENSSL stuff if (fp != NULL) fclose(fp); if (sig != NULL) free(sig); if (pubkey != NULL) OPENSSL_free((void *) pubkey); if (x != NULL) OPENSSL_free((void *) x); if (y != NULL) OPENSSL_free((void *) y); #if OPENSSL_VERSION_NUMBER < 0x30000000L if (pubpoint != NULL) OPENSSL_free((void *) pubpoint); if (pubgroup != NULL) OPENSSL_free((void *) pubgroup); if (ctx != NULL) OPENSSL_free((void *) ctx); #endif return NULL; } bool ec_sign_list_2_1_data(lcp_policy_list_t2_1 *pollist, const char *privkey_file) { /* This function: prepares lcp_policy_list_t2_1 structure for signing using private key file. Signing in ecdsa or sm2 In: pointer to correctly allocated policy list structure, path to private key Out: true on success, false on failure. */ sized_buffer *sig_r = NULL; sized_buffer *sig_s = NULL; sized_buffer *pollist_data = NULL; lcp_signature_2_1 *sig = NULL; bool result; size_t data_len; size_t keysize; uint16_t hashalg; uint16_t sigalg; LOG("[ec_sign_list_2_1_data]\n"); if (pollist == NULL) { ERROR("Error: lcp policy list is not defined.\n"); return false; } sig = get_tpm20_signature_2_1(pollist); if (sig == NULL) { ERROR("Error: failed to get signature structure.\n"); return false; } sigalg = sig->KeyAndSignature.EccKeyAndSignature.SigScheme; hashalg = sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg; data_len = pollist->KeySignatureOffset; //This is how much data will be signed //Key size must be in bytes and is in bits in sig structure: keysize = sig->KeyAndSignature.EccKeyAndSignature.Signature.KeySize / 8; //Allocate buffers: sig_r = allocate_sized_buffer(keysize); sig_s = allocate_sized_buffer(keysize); pollist_data = allocate_sized_buffer(data_len); if (sig_r == NULL || sig_s == NULL || pollist_data == NULL) { ERROR("Error: failed to allocate one or more data buffers.\n"); result = false; goto EXIT; } sig_r->size = keysize; sig_s->size = keysize; pollist_data->size = data_len; //Copy list contents to buffer: memcpy_s((void *) pollist_data->data, pollist_data->size, (const void *) pollist, data_len); if (verbose) { LOG("Data to be signed:\n"); print_hex(" ", pollist_data->data, pollist_data->size); } //Do the signing result = ec_sign_data(pollist_data, sig_r, sig_s, sigalg, hashalg, privkey_file); if (!result) { ERROR("Error: failed to sign pollist data.\n"); result = false; goto EXIT; } //Openssl return data in BE, lcp needs LE so we change endianness of buffers: buffer_reverse_byte_order((uint8_t *)sig_r->data, sig_r->size); buffer_reverse_byte_order((uint8_t *)sig_s->data, sig_s->size); //And copy buffers to signature structure memcpy_s((void *) sig->KeyAndSignature.EccKeyAndSignature.Signature.sigRsigS, 2*MAX_ECC_KEY_SIZE, (const void *) sig_r->data, sig_r->size); memcpy_s((void *) sig->KeyAndSignature.EccKeyAndSignature.Signature.sigRsigS + keysize, (2*MAX_ECC_KEY_SIZE) - keysize, (const void *) sig_s->data, sig_s->size); if (verbose) { display_tpm20_signature_2_1(" ", sig, sigalg); } EXIT: if (sig_r != NULL) { free(sig_r); } if (sig_s != NULL) { free(sig_s); } if (pollist_data != NULL) { free(pollist_data); } return result; } lcp_policy_list_t2_1 *policy_list2_1_rsa_sign(lcp_policy_list_t2_1 *pollist, uint16_t rev_ctr, uint16_t hash_alg, uint16_t sig_alg, const char *pubkey_file, const char *privkey_file) { lcp_signature_2_1 *sig = NULL; bool result; if (pollist == NULL) { ERROR("Error: policy list is NULL.\n"); return NULL; } sig = read_rsa_pubkey_file_2_1(pubkey_file); if (sig == NULL) { ERROR("Error: cannot create lcp signature 2.1\n"); free(pollist); return NULL; } sig->KeyAndSignature.RsaKeyAndSignature.SigScheme = sig_alg; sig->KeyAndSignature.RsaKeyAndSignature.Signature.HashAlg = hash_alg; sig->RevocationCounter = rev_ctr; if ( sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8 != 256 && sig->KeyAndSignature.RsaKeyAndSignature.Key.KeySize / 8 != 384 ) { ERROR("Error: public key size is not 2048/3072 bits\n"); free(sig); free(pollist); return NULL; } pollist = add_tpm20_signature_2_1(pollist, sig, sig_alg); if (pollist == NULL) { ERROR("Error: failed to add lcp_signature_2_1 to list.\n"); free(sig); return NULL; } result = rsa_sign_list_2_1_data(pollist, privkey_file); if (!result) { ERROR("Error: failed to sign list data.\n"); free(sig); free(pollist); return NULL; } return pollist; } static lcp_policy_list_t2_1 *policy_list2_1_ec_sign(lcp_policy_list_t2_1 *pollist, uint16_t rev_ctr, uint16_t sig_alg, const char *pubkey_file, const char *privkey_file) { lcp_signature_2_1 *sig = NULL; bool result; if (pollist == NULL) { ERROR("Error: cannot create lcp signature 2.1.\n"); return NULL; } sig = read_ecdsa_pubkey_file_2_1(pubkey_file); if (sig == NULL) { ERROR("Error: failed to read ecc key.\n"); return NULL; } sig->RevocationCounter = rev_ctr; sig->KeyAndSignature.EccKeyAndSignature.SigScheme = sig_alg; if (sig_alg == TPM_ALG_SM2) { sig->KeyAndSignature.EccKeyAndSignature.Signature.HashAlg = TPM_ALG_SM3_256; } pollist = add_tpm20_signature_2_1(pollist, sig, sig_alg); if (pollist == NULL) { ERROR("Error: failed to add lcp_signature_2_1 to list.\n"); free(sig); return NULL; } result = ec_sign_list_2_1_data(pollist, privkey_file); if (!result) { ERROR("Error: failed to sign list data.\n"); free(sig); free(pollist); return NULL; } return pollist; } bool sign_lcp_policy_list_t2_1(sign_user_input user_input) { lcp_policy_list_t2_1 *pollist = NULL; bool result; pollist = read_policy_list_2_1_file(true, user_input.list_file); if (pollist == NULL) { ERROR("Error: failed to read policy list file.\n"); free(pollist); return false; } if (user_input.sig_alg == TPM_ALG_RSAPSS) { pollist = policy_list2_1_rsa_sign(pollist, user_input.rev_ctr, user_input.hash_alg, user_input.sig_alg, user_input.pubkey_file, user_input.privkey_file); } else if (user_input.sig_alg == TPM_ALG_RSASSA) { DISPLAY("TPM_ALG_RSASSA is not supported with policy list version 0x300." "Use TPM_ALG_RSAPSS.\n"); free(pollist); return false; } else if (user_input.sig_alg == TPM_ALG_ECDSA || user_input.sig_alg == TPM_ALG_SM2) { pollist = policy_list2_1_ec_sign(pollist, user_input.rev_ctr, user_input.sig_alg, user_input.pubkey_file, user_input.privkey_file); } else { DISPLAY("Signature algorithm not supported or not specified.\n"); free(pollist); return false; } if (pollist == NULL) { ERROR("Error: failed to sign policy list.\n"); return false; } result = write_tpm20_policy_list_2_1_file(user_input.list_file, pollist); free(pollist); return result; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/pollist2_1.h0000644000000000000000000000745514210363175015415 0ustar 00000000000000/* * pollist2_1.h: * * Copyright (c) 2020, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __POLLIST2_1_H__ #define __POLLIST2_1_H__ extern uint16_t signature_alg; //Set by user in CLI //Useful offsets #define SIG_REV_CNT_OFFSET 0x0 #define SIG_KEY_SIG_VER_OFFSET 0x2 #define SIG_KEY_SIG_KEY_ALG_OFFSET 0x3 typedef struct __packed { uint16_t revoc_counter; uint8_t version; uint16_t key_alg; uint8_t key_ver; uint16_t key_size; } sig_key_2_1_header; unsigned char *fill_tpm20_policy_list_2_1_buffer(const lcp_policy_list_t2_1 *pollist, size_t *len); size_t get_tpm20_list_2_1_real_size(const lcp_policy_list_t2_1 *pollist); uint16_t get_signature_2_1_key_alg(const lcp_signature_2_1 *sig); size_t get_tpm20_policy_list_2_1_size(const lcp_policy_list_t2_1 *pollist); lcp_policy_list_t2_1 *read_policy_list_2_1_file(bool sign_it, const char *list_file); bool verify_tpm20_policy_list_2_1(const lcp_policy_list_t2_1 *pollist, size_t size, bool *has_sig); void display_tpm20_policy_list_2_1(const char *prefix, const lcp_policy_list_t2_1 *pollist, bool brief); lcp_policy_list_t2_1 *create_empty_tpm20_policy_list_2_1(void); lcp_policy_list_t2_1 *add_tpm20_policy_element_2_1(lcp_policy_list_t2_1 *pollist, const lcp_policy_element_t *elt); bool verify_tpm20_pollist_2_1_sig(lcp_policy_list_t2_1 *pollist); bool calc_tpm20_policy_list_2_1_hash(const lcp_policy_list_t2_1 *pollist, lcp_hash_t2 *hash, uint16_t hash_alg); bool write_tpm20_policy_list_2_1_file(const char *file, const lcp_policy_list_t2_1 *pollist); lcp_signature_2_1 *create_empty_ecc_signature_2_1(void); lcp_signature_2_1 *create_empty_rsa_signature_2_1(void); lcp_policy_list_t2_1 *get_policy_list_2_1_data(const void *raw_data, size_t base_size, uint16_t key_signature_offset); bool sign_lcp_policy_list_t2_1(sign_user_input user_input); #endif /* * Local variables: * Global variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */tboot-1.10.5/lcptools-v2/sbios_elt.c0000644000000000000000000001421014210363175015366 0ustar 00000000000000/* * sbios_elt.c: SBIOS policy element (LCP_SBIOS_ELEMENT) plugin * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define MAX_HASHES 33 /* +1 for fallback_hash */ static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static char alg_name[32] = "sha1"; static uint16_t alg_type = TPM_ALG_SHA1; static uint16_t *get_num_hashes(lcp_sbios_element_t2 *sbios) { /* because fallback_hash is variable size, need to calculate this */ return (void *)&sbios->fallback_hash + get_hash_size(sbios->hash_alg) + sizeof(sbios->reserved2); } static lcp_hash_t2 *get_hashes(lcp_sbios_element_t2 *sbios) { /* because fallback_hash is variable size, need to calculate this */ return (void *)get_num_hashes(sbios) + sizeof(sbios->num_hashes); } static bool parse_sbios_line(const char *line) { if ( nr_hashes == MAX_HASHES ) return false; return parse_line_hashes(line, &hashes[nr_hashes++], alg_type); } static bool cmdline_handler(int c, const char *opt) { if (c == 'a') { strlcpy(alg_name, opt,sizeof(alg_name)); alg_type = str_to_hash_alg(alg_name); LOG("cmdline opt: hash alg: %s\n",alg_name); return true; } else if ( c != 0 ) { ERROR("Error: unknown option for sbios type\n"); return false; } /* BIOS hash files */ LOG("cmdline opt: sbios hash file: %s\n", opt); if ( !parse_file(opt, parse_sbios_line) ) return false; if ( nr_hashes == 0 ) { ERROR("Error: no hashes provided\n"); return false; } return true; } static lcp_policy_element_t *create(void) { LOG("[create]\n"); /* take entire struct size and subtract size of fallback_hash because sizeof(lcp_hash_t) is not accurate (hence get_hash_size()), then add it back in w/ 'nr_hashes' */ size_t data_size = sizeof(lcp_sbios_element_t2) - sizeof(lcp_hash_t2) + nr_hashes * get_hash_size(alg_type); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset_s(elt, sizeof(*elt) + data_size, 0); elt->size = sizeof(*elt) + data_size; lcp_sbios_element_t2 *sbios = (lcp_sbios_element_t2 *)&elt->data; sbios->hash_alg = alg_type; memcpy_s(&sbios->fallback_hash, get_hash_size(alg_type), &hashes[0], get_hash_size(alg_type)); *get_num_hashes(sbios) = nr_hashes - 1; lcp_hash_t2 *hash = get_hashes(sbios); for ( unsigned int i = 1; i < nr_hashes; i++ ) { memcpy_s(hash, get_hash_size(alg_type), &hashes[i], get_hash_size(alg_type)); hash = (void *)hash + get_hash_size(alg_type); } LOG("create SBIOS element succeed!\n"); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_sbios_element_t2 *sbios = (lcp_sbios_element_t2 *)elt->data; unsigned int hash_size = get_lcp_hash_size(sbios->hash_alg); DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(sbios->hash_alg)); DISPLAY("%s fallback_hash: ", prefix); print_hex("", (tb_hash_t *)&sbios->fallback_hash, hash_size); DISPLAY("%s num_hashes: %u\n", prefix, *get_num_hashes(sbios)); uint8_t *hash = (uint8_t *)get_hashes(sbios); for ( unsigned int i = 0; i < *get_num_hashes(sbios); i++ ) { DISPLAY("%s hashes[%u]: ", prefix, i); print_hex("", hash, hash_size); hash += hash_size; } } static struct option opts[] = { {"alg", required_argument, NULL, 'a'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "sbios", opts, " sbios\n" " [--alg ] hash alg of element\n" " [FILE2] ... one or more files containing BIOS\n" " hash(es); each file can contain\n" " multiple hashes; the first hash in\n" " the first file will be the fallback\n" " hash\n", LCP_POLELT_TYPE_SBIOS2, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/lcptools-v2/stm_elt.c0000644000000000000000000001163414210363175015061 0ustar 00000000000000/* * mle_elt.c: MLE policy element (LCP_MLE_ELEMENT) plugin * * Copyright (c) 2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "polelt_plugin.h" #include "lcputils.h" #define MAX_HASHES 32 static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static char alg_name[32] = "sha1"; static uint16_t alg_type = TPM_ALG_SHA1; static bool parse_stm_line(const char *line) { if ( nr_hashes == MAX_HASHES ) return false; return parse_line_hashes(line, &hashes[nr_hashes++], alg_type); } static bool cmdline_handler(int c, const char *opt) { if (c == 'a') { strlcpy(alg_name, opt,sizeof(alg_name)); alg_type = str_to_hash_alg(alg_name); LOG("cmdline opt: hash alg: %s\n",alg_name); return true; } else if ( c != 0 ) { ERROR("Error: unknown option for mle type\n"); return false; } /* MLE hash files */ LOG("cmdline opt: mle hash file: %s\n", opt); if ( !parse_file(opt, parse_stm_line) ) return false; return true; } static lcp_policy_element_t *create(void) { LOG("[create]\n"); size_t data_size = sizeof(lcp_stm_element_t2) + nr_hashes * get_hash_size(alg_type); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset_s(elt, sizeof(*elt) + data_size, 0); elt->size = sizeof(*elt) + data_size; lcp_stm_element_t2 *stm = (lcp_stm_element_t2 *)&elt->data; stm->hash_alg = alg_type; stm->num_hashes = nr_hashes; lcp_hash_t2 *hash = stm->hashes; for ( unsigned int i = 0; i < nr_hashes; i++ ) { memcpy_s(hash, get_hash_size(alg_type), &hashes[i], get_hash_size(alg_type)); hash = (void *)hash + get_hash_size(alg_type); } LOG("create stm element succeed!\n"); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_stm_element_t2 *stm = (lcp_stm_element_t2 *)elt->data; DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(stm->hash_alg)); DISPLAY("%s num_hashes: %u\n", prefix, stm->num_hashes); uint8_t *hash = (uint8_t *)&stm->hashes; unsigned int hash_size = get_hash_size(stm->hash_alg); for ( unsigned int i = 0; i < stm->num_hashes; i++ ) { DISPLAY("%s hashes[%u]: ", prefix, i); print_hex("", hash, hash_size); hash += hash_size; } } static struct option opts[] = { {"alg", required_argument, NULL, 'a'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "stm", opts, " stm\n" " [--alg ] hash alg of element\n" " [FILE2] ... one or more files containing STM\n" " hash(es); each file can contain\n" " multiple hashes\n", LCP_POLELT_TYPE_STM2, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/safestringlib/.cproject0000644000000000000000000002746714210363175015543 0ustar 00000000000000 tboot-1.10.5/safestringlib/.project0000644000000000000000000000463414210363175015367 0ustar 00000000000000 SafeStringStaticLibrary org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.buildLocation ${workspace_loc:/SafeStringStaticLibrary/Debug} org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature tboot-1.10.5/safestringlib/Debug/makefile0000644000000000000000000000176614210363175016451 0ustar 00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ -include ../makefile.init RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk -include safeclib/subdir.mk -include subdir.mk -include objects.mk ifneq ($(MAKECMDGOALS),clean) ifneq ($(strip $(C_DEPS)),) -include $(C_DEPS) endif endif -include ../makefile.defs # Add inputs and outputs from these tool invocations to the build variables # All Target all: libSafeString.a # Tool invocations libSafeString.a: $(OBJS) $(USER_OBJS) @echo 'Building target: $@' @echo 'Invoking: GCC Archiver' ar -r "libSafeString.a" $(OBJS) $(USER_OBJS) $(LIBS) @echo 'Finished building target: $@' @echo ' ' # Other Targets clean: -$(RM) $(OBJS)$(C_DEPS)$(ARCHIVES) libSafeString.a -@echo ' ' .PHONY: all clean dependents .SECONDARY: -include ../makefile.targets tboot-1.10.5/safestringlib/Debug/objects.mk0000644000000000000000000000034714210363175016725 0ustar 00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ USER_OBJS := LIBS := tboot-1.10.5/safestringlib/Debug/sources.mk0000644000000000000000000000061214210363175016752 0ustar 00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ O_SRCS := C_SRCS := S_UPPER_SRCS := OBJ_SRCS := ASM_SRCS := OBJS := C_DEPS := ARCHIVES := # Every subdirectory with source files must be described here SUBDIRS := \ safeclib \ tboot-1.10.5/safestringlib/LICENSE©ING.txt0000644000000000000000000000445714210363175016645 0ustar 00000000000000Safe C Library Copyright (c) 2014-2016, Intel Corporation. All rights reserved. * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. ================================================================================ Copyright (C) 2012, 2013 Cisco Systems All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tboot-1.10.5/safestringlib/README.md0000644000000000000000000000464414210363175015200 0ustar 00000000000000# safestringlib The Secure Development Lifecycle (SDL) recommends banning certain C Library functions because they directly contribute to security vulnerabilities such as buffer overflows. However routines for the manipulation of strings and memory buffers are common in software and firmware, and are essential to accomplish certain programming tasks. Safer replacements for these functions that avoid or prevent serious security vulnerabilities (e.g. buffer overflows, string format attacks, conversion overflows/underflows, etc.) are available in the SafeString Library. This library includes routines for safe string operations (like strcpy) and memory routines (like memcpy) that are recommended for Linux/Android operating systems, and will also work for Windows. This library is especially useful for cross-platform situations where one library for these routines is preferred. The Safe String Library is based on the Safe C Library by Cisco, and includes replacement C Library functions for the SDL banned functions, as well as a number of additional useful routines that are also susceptible to buffer overflows. This library continues to be made available under the MIT Open Source License. Cisco's Safe C Library was extended by Intel's Security Center of Excellence (SeCoE) to add additional routines, and include additional unit tests. LIST OF PRIMARY FUNCTIONS: ----------------------------- * memcmp_s() * memcpy_s() * memmove_s() * memset_s() * memzero_s() * stpcpy_s() * stpncpy_s() * strcat_s() * strcpy_s() * strcspn_s() * strncat_s() * strncpy_s() * strnlen_s() * strpbrk_s() * strspn_s() * strstr_s() * strtok_s() * wcpcpy_s() * wcscat_s() * wcscpy_s() * wcsncat_s() * wcsnlen_s() * wmemcmp_s() * wmemcpy_s() * wmemmove_s() * wmemset_s() LIST OF ADDITIONAL STRING ROUTINES: ------------------------------------ * strcasecmp_s() * strcasestr_s() * strcmp_s() * strcmpfld_s() * strcpyfld_s() * strcpyfldin_s() * strcpyfldout_s() * strfirstchar_s() * strfirstdiff_s() * strfirstsmae_s() * strisalphanumeric_s() * strisascii_s() * strisdigit_s() * strishes_s() * strislowercase_s() * strismixedcase_s() * strispassword_s() * strisuppercase_s() * strlastchar_s() * strlastdiff_s() * strlastsame_s() * strljustify_s() * strnterminate_s() * strprefix_s() * stremovews_s() * strtolowercase_s() * strtouppercase_s() * strzero_s() PLANNED ENHANCEMENTS: ---------------------- - Add full sprintf_s() support - Add full sscanf_s() support tboot-1.10.5/safestringlib/include/safe_lib.h0000644000000000000000000000442014210363175017251 0ustar 00000000000000/*------------------------------------------------------------------ * safe_lib.h -- Safe C Library * * October 2008, Bo Berry * Modified 2012, Jonathan Toppins * * Copyright (c) 2008-2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_LIB_H__ #define __SAFE_LIB_H__ #include "safe_types.h" #include "safe_lib_errno.h" /* C11 appendix K types - specific for bounds checking */ typedef size_t rsize_t; /* * We depart from the standard and allow memory and string operations to * have different max sizes. See the respective safe_mem_lib.h or * safe_str_lib.h files. */ /* #define RSIZE_MAX (~(rsize_t)0) - leave here for completeness */ typedef void (*constraint_handler_t) (const char * /* msg */, void * /* ptr */, errno_t /* error */); extern void abort_handler_s(const char *msg, void *ptr, errno_t error); extern void ignore_handler_s(const char *msg, void *ptr, errno_t error); #define sl_default_handler ignore_handler_s #include "safe_mem_lib.h" #include "safe_str_lib.h" #endif /* __SAFE_LIB_H__ */ tboot-1.10.5/safestringlib/include/safe_lib_errno.h0000644000000000000000000000576014210363175020466 0ustar 00000000000000/*------------------------------------------------------------------ * safe_lib_errno.h -- Safe C Lib Error codes * * October 2008, Bo Berry * Modified 2012, Jonathan Toppins * * Copyright (c) 2008-2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_LIB_ERRNO_H__ #define __SAFE_LIB_ERRNO_H__ #ifdef __KERNEL__ # include #else #include #endif /* __KERNEL__ */ /* * Safe Lib specific errno codes. These can be added to the errno.h file * if desired. */ #ifndef ESNULLP #define ESNULLP ( 400 ) /* null ptr */ #endif #ifndef ESZEROL #define ESZEROL ( 401 ) /* length is zero */ #endif #ifndef ESLEMIN #define ESLEMIN ( 402 ) /* length is below min */ #endif #ifndef ESLEMAX #define ESLEMAX ( 403 ) /* length exceeds max */ #endif #ifndef ESOVRLP #define ESOVRLP ( 404 ) /* overlap undefined */ #endif #ifndef ESEMPTY #define ESEMPTY ( 405 ) /* empty string */ #endif #ifndef ESNOSPC #define ESNOSPC ( 406 ) /* not enough space for s2 */ #endif #ifndef ESUNTERM #define ESUNTERM ( 407 ) /* unterminated string */ #endif #ifndef ESNODIFF #define ESNODIFF ( 408 ) /* no difference */ #endif #ifndef ESNOTFND #define ESNOTFND ( 409 ) /* not found */ #endif /* Additional for safe snprintf_s interfaces */ #ifndef ESBADFMT #define ESBADFMT ( 410 ) /* bad format string */ #endif #ifndef ESFMTTYP #define ESFMTTYP ( 411 ) /* bad format type */ #endif /* EOK may or may not be defined in errno.h */ #ifndef EOK #define EOK ( 0 ) #endif #endif /* __SAFE_LIB_ERRNO_H__ */ tboot-1.10.5/safestringlib/include/safe_lib_errno.h.in0000644000000000000000000000534414210363175021071 0ustar 00000000000000/*------------------------------------------------------------------ * safe_lib_errno.h -- Safe C Lib Error codes * * October 2008, Bo Berry * Modified 2012, Jonathan Toppins * * Copyright (c) 2008-2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_LIB_ERRNO_H__ #define __SAFE_LIB_ERRNO_H__ #ifdef __KERNEL__ # include #else @INSERT_ERRNO_H@ #endif /* __KERNEL__ */ /* * Safe Lib specific errno codes. These can be added to the errno.h file * if desired. */ #ifndef ESNULLP #define ESNULLP ( 400 ) /* null ptr */ #endif #ifndef ESZEROL #define ESZEROL ( 401 ) /* length is zero */ #endif #ifndef ESLEMIN #define ESLEMIN ( 402 ) /* length is below min */ #endif #ifndef ESLEMAX #define ESLEMAX ( 403 ) /* length exceeds max */ #endif #ifndef ESOVRLP #define ESOVRLP ( 404 ) /* overlap undefined */ #endif #ifndef ESEMPTY #define ESEMPTY ( 405 ) /* empty string */ #endif #ifndef ESNOSPC #define ESNOSPC ( 406 ) /* not enough space for s2 */ #endif #ifndef ESUNTERM #define ESUNTERM ( 407 ) /* unterminated string */ #endif #ifndef ESNODIFF #define ESNODIFF ( 408 ) /* no difference */ #endif #ifndef ESNOTFND #define ESNOTFND ( 409 ) /* not found */ #endif /* EOK may or may not be defined in errno.h */ #ifndef EOK #define EOK ( 0 ) #endif #endif /* __SAFE_LIB_ERRNO_H__ */ tboot-1.10.5/safestringlib/include/safe_mem_lib.h0000644000000000000000000000776714210363175020130 0ustar 00000000000000/*------------------------------------------------------------------ * safe_mem_lib.h -- Safe C Library Memory APIs * * October 2008, Bo Berry * Modified 2012, Jonathan Toppins * * Copyright (c) 2008-2012 by Cisco Systems, Inc. * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_MEM_LIB_H__ #define __SAFE_MEM_LIB_H__ #include "safe_lib.h" #include #define RSIZE_MAX_MEM ( 256UL << 20 ) /* 256MB */ #define RSIZE_MAX_MEM16 ( RSIZE_MAX_MEM/2 ) #define RSIZE_MAX_MEM32 ( RSIZE_MAX_MEM/4 ) /* set memory constraint handler */ extern constraint_handler_t set_mem_constraint_handler_s(constraint_handler_t handler); /* compare memory */ extern errno_t memcmp_s(const void *dest, rsize_t dmax, const void *src, rsize_t slen, int *diff); /* compare uint16_t memory */ extern errno_t memcmp16_s(const uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t slen, int *diff); /* compare uint32_t memory */ extern errno_t memcmp32_s(const uint32_t *dest, rsize_t dmax, const uint32_t *src, rsize_t slen, int *diff); /* copy memory */ extern errno_t memcpy_s(void *dest, rsize_t dmax, const void *src, rsize_t slen); /* copy uint16_t memory */ extern errno_t memcpy16_s(uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t slen); /* copy uint32_t memory */ extern errno_t memcpy32_s(uint32_t *dest, rsize_t dmax, const uint32_t *src, rsize_t slen); /* copy wchar_t memory */ extern errno_t wmemcpy_s(wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t slen); /* move memory, including overlapping memory */ extern errno_t memmove_s(void *dest, rsize_t dmax, const void *src, rsize_t slen); /* uint16_t move memory, including overlapping memory */ extern errno_t memmove16_s(uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t slen); /* uint32_t move memory, including overlapping memory */ extern errno_t memmove32_s(uint32_t *dest, rsize_t dmax, const uint32_t *src, rsize_t slen); /* copy wchar_t memory, including overlapping memory */ extern errno_t wmemmove_s(wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t slen); /* set bytes */ extern errno_t memset_s(void *dest, rsize_t dmax, uint8_t value); /* set uint16_t */ extern errno_t memset16_s(uint16_t *dest, rsize_t dmax, uint16_t value); /* set uint32_t */ extern errno_t memset32_s(uint32_t *dest, rsize_t dmax, uint32_t value); /* byte zero */ extern errno_t memzero_s(void *dest, rsize_t dmax); /* uint16_t zero */ extern errno_t memzero16_s(uint16_t *dest, rsize_t dmax); /* uint32_t zero */ extern errno_t memzero32_s(uint32_t *dest, rsize_t dmax); #endif /* __SAFE_MEM_LIB_H__ */ tboot-1.10.5/safestringlib/include/safe_str_lib.h0000644000000000000000000001456414210363175020153 0ustar 00000000000000/*------------------------------------------------------------------ * safe_str_lib.h -- Safe C Library String APIs * * October 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc. * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_STR_LIB_H__ #define __SAFE_STR_LIB_H__ #include "safe_lib.h" /* * The shortest string is a null string!! */ #define RSIZE_MIN_STR ( 1 ) /* maximum sring length */ #define RSIZE_MAX_STR ( 4UL << 10 ) /* 4KB */ /* The makeup of a password */ #define SAFE_STR_MIN_LOWERCASE ( 2 ) #define SAFE_STR_MIN_UPPERCASE ( 2 ) #define SAFE_STR_MIN_NUMBERS ( 1 ) #define SAFE_STR_MIN_SPECIALS ( 1 ) #define SAFE_STR_PASSWORD_MIN_LENGTH ( 6 ) #define SAFE_STR_PASSWORD_MAX_LENGTH ( 32 ) /* set string constraint handler */ extern constraint_handler_t set_str_constraint_handler_s(constraint_handler_t handler); /* string compare */ extern errno_t strcasecmp_s(const char *dest, rsize_t dmax, const char *src, int *indicator); /* find a substring _ case insensitive */ extern errno_t strcasestr_s(char *dest, rsize_t dmax, const char *src, rsize_t slen, char **substring); /* string concatenate */ extern errno_t strcat_s(char *dest, rsize_t dmax, const char *src); /* string compare */ extern errno_t strcmp_s(const char *dest, rsize_t dmax, const char *src, int *indicator); /* fixed field string compare */ extern errno_t strcmpfld_s(const char *dest, rsize_t dmax, const char *src, int *indicator); /* string copy */ extern errno_t strcpy_s(char *dest, rsize_t dmax, const char *src); /* string copy */ extern char * stpcpy_s(char *dest, rsize_t dmax, const char *src, errno_t *err); /* fixed char array copy */ extern errno_t strcpyfld_s(char *dest, rsize_t dmax, const char *src, rsize_t slen); /* copy from a null terminated string to fixed char array */ extern errno_t strcpyfldin_s(char *dest, rsize_t dmax, const char *src, rsize_t slen); /* copy from a char array to null terminated string */ extern errno_t strcpyfldout_s(char *dest, rsize_t dmax, const char *src, rsize_t slen); /* computes excluded prefix length */ extern errno_t strcspn_s(const char *dest, rsize_t dmax, const char *src, rsize_t slen, rsize_t *count); /* returns a pointer to the first occurrence of c in dest */ extern errno_t strfirstchar_s(char *dest, rsize_t dmax, char c, char **first); /* returns index of first difference */ extern errno_t strfirstdiff_s(const char *dest, rsize_t dmax, const char *src, rsize_t *index); /* validate alphanumeric string */ extern bool strisalphanumeric_s(const char *str, rsize_t slen); /* validate ascii string */ extern bool strisascii_s(const char *str, rsize_t slen); /* validate string of digits */ extern bool strisdigit_s(const char *str, rsize_t slen); /* validate hex string */ extern bool strishex_s(const char *str, rsize_t slen); /* validate lower case */ extern bool strislowercase_s(const char *str, rsize_t slen); /* validate mixed case */ extern bool strismixedcase_s(const char *str, rsize_t slen); /* validate password */ extern bool strispassword_s(const char *str, rsize_t slen); /* validate upper case */ extern bool strisuppercase_s(const char *str, rsize_t slen); /* returns a pointer to the last occurrence of c in s1 */ extern errno_t strlastchar_s(char *str, rsize_t smax, char c, char **first); /* returns index of last difference */ extern errno_t strlastdiff_s(const char *dest, rsize_t dmax, const char *src, rsize_t *index); /* left justify */ extern errno_t strljustify_s(char *dest, rsize_t dmax); /* fitted string concatenate */ extern errno_t strncat_s(char *dest, rsize_t dmax, const char *src, rsize_t slen); /* fitted string copy */ extern errno_t strncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t slen); /* string length */ extern rsize_t strnlen_s (const char *s, rsize_t smax); /* string terminate */ extern rsize_t strnterminate_s (char *s, rsize_t smax); /* get pointer to first occurrence from set of char */ extern errno_t strpbrk_s(char *dest, rsize_t dmax, char *src, rsize_t slen, char **first); extern errno_t strfirstsame_s(const char *dest, rsize_t dmax, const char *src, rsize_t *index); extern errno_t strlastsame_s(const char *dest, rsize_t dmax, const char *src, rsize_t *index); /* searches for a prefix */ extern errno_t strprefix_s(const char *dest, rsize_t dmax, const char *src); /* removes leading and trailing white space */ extern errno_t strremovews_s(char *dest, rsize_t dmax); /* computes inclusive prefix length */ extern errno_t strspn_s(const char *dest, rsize_t dmax, const char *src, rsize_t slen, rsize_t *count); /* find a substring */ extern errno_t strstr_s(char *dest, rsize_t dmax, const char *src, rsize_t slen, char **substring); /* string tokenizer */ extern char * strtok_s(char *s1, rsize_t *s1max, const char *src, char **ptr); /* convert string to lowercase */ extern errno_t strtolowercase_s(char *str, rsize_t slen); /* convert string to uppercase */ extern errno_t strtouppercase_s(char *str, rsize_t slen); /* zero an entire string with nulls */ extern errno_t strzero_s(char *dest, rsize_t dmax); #endif /* __SAFE_STR_LIB_H__ */ tboot-1.10.5/safestringlib/include/safe_types.h0000644000000000000000000000357514210363175017661 0ustar 00000000000000/*------------------------------------------------------------------ * safe_types.h - C99 std types & defs or Linux kernel equivalents * * March 2007, Bo Berry * Modified 2012, Jonathan Toppins * * Copyright (c) 2007-2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_TYPES_H__ #define __SAFE_TYPES_H__ #ifdef __KERNEL__ /* linux kernel environment */ #include #include #include /* errno_t isn't defined in the kernel */ typedef int errno_t; #else #include #include #include #include #include typedef int errno_t; #include #endif /* __KERNEL__ */ #endif /* __SAFE_TYPES_H__ */ tboot-1.10.5/safestringlib/include/safe_types.h.in0000644000000000000000000000356414210363175020264 0ustar 00000000000000/*------------------------------------------------------------------ * safe_types.h - C99 std types & defs or Linux kernel equivalents * * March 2007, Bo Berry * Modified 2012, Jonathan Toppins * * Copyright (c) 2007-2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_TYPES_H__ #define __SAFE_TYPES_H__ #ifdef __KERNEL__ /* linux kernel environment */ #include #include #include /* errno_t isn't defined in the kernel */ typedef int errno_t; #else #include @INSERT_SYS_TYPES_H@ @INSERT_INTTYPES_H@ @INSERT_STDINT_H@ @INSERT_ERRNO_H@ @FALLBACK_ERRNO_T@ @INSERT_BOOL_SUPPORT@ #endif /* __KERNEL__ */ #endif /* __SAFE_TYPES_H__ */ tboot-1.10.5/safestringlib/include/snprintf_s.h0000644000000000000000000000341414210363175017674 0ustar 00000000000000/*------------------------------------------------------------------ * sprintf_s.h -- Safe Sprintf Interfaces * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef SPRINTF_S_H_ #define SPRINTF_S_H_ #include #define SNPRFNEGATE(x) (-1*(x)) int snprintf_s_i(char *dest, rsize_t dmax, const char *format, int a); int snprintf_s_si(char *dest, rsize_t dmax, const char *format, char *s, int a); int snprintf_s_l(char *dest, rsize_t dmax, const char *format, long a); int snprintf_s_sl(char *dest, rsize_t dmax, const char *format, char *s, long a); #endif /* SPRINTF_S_H_ */ tboot-1.10.5/safestringlib/makefile0000644000000000000000000000721314210363175015414 0ustar 00000000000000IDIR = include CC ?= gcc CFLAGS += -I$(IDIR) -fstack-protector-strong -fPIE -fPIC -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -DSTDC_HEADERS -Wno-implicit-fallthrough LDFLAGS += -z noexecstack -z relo -z now ODIR=obj OTDIR=objtest SRCDIR=safeclib TESTDIR=unittests _DEPS = safe_lib_errno.h safe_lib.h safe_str_lib.h safe_types.h.in safe_lib_errno.h.in safe_mem_lib.h safe_types.h _ODEPS = mem_primitives_lib.h safeclib_private.h safe_mem_constraint.h safe_str_constraint.h DEPS = $(addprefix $(IDIR)/,$(_DEPS)) ODEPS = $(addprefix $(SRCDIR)/,$(_ODEPS)) _CLIB = abort_handler_s.c stpcpy_s.c strlastsame_s.c ignore_handler_s.c stpncpy_s.c strljustify_s.c memcmp16_s.c strcasecmp_s.c strncat_s.c memcmp32_s.c strcasestr_s.c strncpy_s.c memcmp_s.c strcat_s.c strnlen_s.c memcpy16_s.c strcmpfld_s.c strnterminate_s.c memcpy32_s.c strcmp_s.c strpbrk_s.c memcpy_s.c strcpyfldin_s.c strprefix_s.c memmove16_s.c strcpyfldout_s.c strremovews_s.c memmove32_s.c strcpyfld_s.c strspn_s.c memmove_s.c strcpy_s.c strstr_s.c mem_primitives_lib.c strcspn_s.c strtok_s.c strfirstchar_s.c strtolowercase_s.c memset16_s.c strfirstdiff_s.c strtouppercase_s.c memset32_s.c strfirstsame_s.c strzero_s.c memset_s.c strisalphanumeric_s.c wcpcpy_s.c memzero16_s.c strisascii_s.c wcscat_s.c memzero32_s.c strisdigit_s.c wcscpy_s.c memzero_s.c strishex_s.c wcsncat_s.c strislowercase_s.c wcsncpy_s.c safe_mem_constraint.c strismixedcase_s.c wcsnlen_s.c strispassword_s.c wmemcmp_s.c safe_str_constraint.c strisuppercase_s.c wmemcpy_s.c strlastchar_s.c wmemmove_s.c snprintf_support.c strlastdiff_s.c wmemset_s.c _TLIST = $(addprefix $(ODIR)/,$(_CLIB)) OBJ = $(patsubst %.c,%.o,$(_TLIST)) CLIB =$(addprefix $(SRCDIR)/,$(_CLIB)) $(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS) $(ODEPS) mkdir -p $(ODIR) $(CC) $(LDFLAGS) -c -o $@ $< $(CFLAGS) libsafestring.a: $(OBJ) ar rcs $@ $^ _TESTFUNCS = Safe_String_UnitTestMain.c test_strcmp_s.c test_strnlen_s.c test_memcmp16_s.c test_strcpyfldin_s.c test_strnterminate_s.c test_memcmp32_s.c test_strcpyfldout_s.c test_strpbrk_s.c test_memcmp_s.c test_strcpyfld_s.c test_strprefix_s.c test_memcpy16_s.c test_strcpy_s.c test_strremovews_s.c test_memcpy32_s.c test_strcspn_s.c test_strspn_s.c test_memcpy_s.c test_strfirstchar_s.c test_strstr_s.c test_memmove16_s.c test_strfirstdiff_s.c test_strtok_s.c test_memmove32_s.c test_strfirstsame_s.c test_strtolowercase_s.c test_memmove_s.c test_strisalphanumeric_s.c test_strtouppercase_s.c test_memset16_s.c test_strisascii_s.c test_strzero_s.c test_memset32_s.c test_strisdigit_s.c test_wcpcpy_s.c test_memset_s.c test_strishex_s.c test_wcscat_s.c test_memzero16_s.c test_strislowercase_s.c test_wcscpy_s.c test_memzero32_s.c test_strismixed_s.c test_wcsncat_s.c test_memzero_s.c test_strispassword_s.c test_wcsncpy_s.c test_strisuppercase_s.c test_wcsnlen_s.c test_stpcpy_s.c test_strlastchar_s.c test_wmemcmp_s.c test_stpncpy_s.c test_strlastdiff_s.c test_wmemcpy_s.c test_strcasecmp_s.c test_strlastsame_s.c test_wmemmove_s.c test_strcasestr_s.c test_strljustify_s.c test_wmemset_s.c test_strcat_s.c test_strncat_s.c test_strcmpfld_s.c test_strncpy_s.c _TLIST2 = $(addprefix $(OTDIR)/,$(_TESTFUNCS)) TOBJ = $(patsubst %.c,%.o,$(_TLIST2)) TCLIB =$(addprefix $(TESTDIR)/,$(_TESTFUNCS)) $(OTDIR)/%.o: $(TESTDIR)/%.c $(TESTDIR)/test_private.h mkdir -p $(OTDIR) $(CC) -c -o $@ $< $(CFLAGS) safestringtest: libsafestring.a $(TOBJ) $(CC) $(LDFLAGS) -static -o $@ $(TOBJ) libsafestring.a all: libsafestring.a safestringtest build: libsafestring.a install: build dist: build uninstall: distclean:clean .PHONY: clean clean: rm -rf $(ODIR) *~ core $(INCDIR)/*~ $(OTDIR) rm -f libsafestring.a rm -f safestringtest tboot-1.10.5/safestringlib/safeclib/abort_handler_s.c0000644000000000000000000000472114210363175020757 0ustar 00000000000000/*------------------------------------------------------------------ * abort_handler_s.c * * 2012, Jonathan Toppins * * Copyright (c) 2012 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" /** * NAME * abort_handler_s * * SYNOPSIS * #include "safe_lib.h" * void abort_handler_s(const char *msg, void *ptr, errno_t error) * * DESCRIPTION * This function writes a message on the standard error stream in * an implementation-defined format. The message shall include the * string pointed to by msg. The abort_handler_s function then calls * the abort function. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * msg Pointer to the message describing the error * * ptr Pointer to aassociated data. Can be NULL. * * error The error code encountered. * * RETURN VALUE * Does not return to caller. * * ALSO SEE * ignore_handler_s() * */ void abort_handler_s(const char *msg, void *ptr, errno_t error) { (void) ptr; slprintf("ABORT CONSTRAINT HANDLER: (%u) %s\n", error, (msg) ? msg : "Null message"); slabort(); } EXPORT_SYMBOL(abort_handler_s); tboot-1.10.5/safestringlib/safeclib/ignore_handler_s.c0000644000000000000000000000446714210363175021142 0ustar 00000000000000/*------------------------------------------------------------------ * ignore_handler_s.c * * 2012, Jonathan Toppins * * Copyright (c) 2012 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" /** * NAME * ignore_handler_s * * SYNOPSIS * #include "safe_lib.h" * void ignore_handler_s(const char *msg, void *ptr, errno_t error) * * DESCRIPTION * This function simply returns to the caller. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * msg Pointer to the message describing the error * * ptr Pointer to aassociated data. Can be NULL. * * error The error code encountered. * * RETURN VALUE * Returns no value. * * ALSO SEE * abort_handler_s() * */ void ignore_handler_s(const char *msg, void *ptr, errno_t error) { (void) ptr; (void) error; (void) msg; sldebug_printf("IGNORE CONSTRAINT HANDLER: (%u) %s\n", error, (msg) ? msg : "Null message"); return; } EXPORT_SYMBOL(ignore_handler_s); tboot-1.10.5/safestringlib/safeclib/mem_primitives_lib.c0000644000000000000000000005330314210363175021510 0ustar 00000000000000/*------------------------------------------------------------------ * mem_primitives_lib.c - Unguarded Memory Copy Routines * * February 2005, Bo Berry * * Copyright (c) 2005-2009 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "mem_primitives_lib.h" /* * mem_primitives_lib.c provides unguarded memory routines * that are used by the safe_mem_library. These routines * may also be used by an application, but the application * is responsible for all parameter validation and alignment. */ /** * NAME * mem_prim_set - Sets memory to value * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_set(void *dest, uint32_t len, uint8_t value) * * DESCRIPTION * Sets len bytes starting at dest to the specified value * * INPUT PARAMETERS * dest - pointer to memory that will be set to value * * len - number of bytes to be set * * value - byte value * * OUTPUT PARAMETERS * dest - is updated * * RETURN VALUE * none * */ void mem_prim_set (void *dest, uint32_t len, uint8_t value) { uint8_t *dp; uint32_t count; uint32_t lcount; uint32_t *lp; uint32_t value32; count = len; dp = dest; value32 = value | (value << 8) | (value << 16) | (value << 24); /* * First, do the few bytes to get uint32_t aligned. */ for (; count && ( (uintptr_t)dp & (sizeof(uint32_t)-1) ); count--) { *dp++ = value; } /* * Then do the uint32_ts, unrolled the loop for performance */ lp = (uint32_t *)dp; lcount = count >> 2; while (lcount != 0) { switch (lcount) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32; lcount -= 16; break; case 15: *lp++ = value32; case 14: *lp++ = value32; case 13: *lp++ = value32; case 12: *lp++ = value32; case 11: *lp++ = value32; case 10: *lp++ = value32; case 9: *lp++ = value32; case 8: *lp++ = value32; case 7: *lp++ = value32; case 6: *lp++ = value32; case 5: *lp++ = value32; case 4: *lp++ = value32; case 3: *lp++ = value32; case 2: *lp++ = value32; case 1: *lp++ = value32; lcount = 0; break; } } /* end while */ dp = (uint8_t *)lp; /* * compute the number of remaining bytes */ count &= (sizeof(uint32_t)-1); /* * remaining bytes */ for (; count; dp++, count--) { *dp = value; } return; } /** * NAME * mem_prim_set16 - Sets memory to value * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_set16(uint16_t *dp, uint32_t len, uint16_t value) * * DESCRIPTION * Sets len uint16_ts starting at dest to the specified value. * Pointers must meet system alignment requirements. * * INPUT PARAMETERS * dest - pointer to memory that will be set to value * * len - number of uint16_ts to be set * * value - uint16_t value * * OUTPUT PARAMETERS * dest - is updated * * RETURN VALUE * none * */ void mem_prim_set16 (uint16_t *dp, uint32_t len, uint16_t value) { while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; len -= 16; break; case 15: *dp++ = value; case 14: *dp++ = value; case 13: *dp++ = value; case 12: *dp++ = value; case 11: *dp++ = value; case 10: *dp++ = value; case 9: *dp++ = value; case 8: *dp++ = value; case 7: *dp++ = value; case 6: *dp++ = value; case 5: *dp++ = value; case 4: *dp++ = value; case 3: *dp++ = value; case 2: *dp++ = value; case 1: *dp++ = value; len = 0; break; } } /* end while */ return; } /** * NAME * mem_prim_set32 - Sets memory to the uint32_t value * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_set32(uint32_t *dp, uint32_t len, uint32_t value) * * DESCRIPTION * Sets len uint32_ts starting at dest to the specified value * Pointers must meet system alignment requirements. * * INPUT PARAMETERS * dest - pointer to memory that will be set to value * * len - number of uint32_ts to be set * * value - uint32_t value * * OUTPUT PARAMETERS * dest - is updated * * RETURN VALUE * none * */ void mem_prim_set32 (uint32_t *dp, uint32_t len, uint32_t value) { while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value; len -= 16; break; case 15: *dp++ = value; case 14: *dp++ = value; case 13: *dp++ = value; case 12: *dp++ = value; case 11: *dp++ = value; case 10: *dp++ = value; case 9: *dp++ = value; case 8: *dp++ = value; case 7: *dp++ = value; case 6: *dp++ = value; case 5: *dp++ = value; case 4: *dp++ = value; case 3: *dp++ = value; case 2: *dp++ = value; case 1: *dp++ = value; len = 0; break; } } /* end while */ return; } /** * NAME * mem_prim_move - Move (handles overlap) memory * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_move(void *dest, const void *src, uint32_t len) * * DESCRIPTION * Moves at most slen bytes from src to dest, up to dmax * bytes. Dest may overlap with src. * * INPUT PARAMETERS * dest - pointer to the memory that will be replaced by src. * * src - pointer to the memory that will be copied * to dest * * len - maximum number bytes of src that can be copied * * OUTPUT PARAMETERS * dest - is updated * * RETURN VALUE * none * */ void mem_prim_move (void *dest, const void *src, uint32_t len) { #define wsize sizeof(uint32_t) #define wmask (wsize - 1) uint8_t *dp = dest; const uint8_t *sp = src; uint32_t tsp; /* * Determine if we need to copy forward or backward (overlap) */ if ((uintptr_t)dp < (uintptr_t)sp) { /* * Copy forward. */ /* * get a working copy of src for bit operations */ tsp = (uintptr_t)sp; /* * Try to align both operands. This cannot be done * unless the low bits match. */ if ((tsp | (uintptr_t)dp) & wmask) { /* * determine how many bytes to copy to align operands */ if ((tsp ^ (uintptr_t)dp) & wmask || len < wsize) { tsp = len; } else { tsp = wsize - (tsp & wmask); } len -= tsp; /* * make the alignment */ do { *dp++ = *sp++; } while (--tsp); } /* * Now copy, then mop up any trailing bytes. */ tsp = len / wsize; if (tsp > 0) { do { *(uint32_t *)dp = *(uint32_t *)sp; sp += wsize; dp += wsize; } while (--tsp); } /* * copy over the remaining bytes and we're done */ tsp = len & wmask; if (tsp > 0) { do { *dp++ = *sp++; } while (--tsp); } } else { /* * This section is used to copy backwards, to handle any * overlap. The alignment requires (tps&wmask) bytes to * align. */ /* * go to end of the memory to copy */ sp += len; dp += len; /* * get a working copy of src for bit operations */ tsp = (uintptr_t)sp; /* * Try to align both operands. */ if ((tsp | (uintptr_t)dp) & wmask) { if ((tsp ^ (uintptr_t)dp) & wmask || len <= wsize) { tsp = len; } else { tsp &= wmask; } len -= tsp; /* * make the alignment */ do { *--dp = *--sp; } while (--tsp); } /* * Now copy in uint32_t units, then mop up any trailing bytes. */ tsp = len / wsize; if (tsp > 0) { do { sp -= wsize; dp -= wsize; *(uint32_t *)dp = *(uint32_t *)sp; } while (--tsp); } /* * copy over the remaining bytes and we're done */ tsp = len & wmask; if (tsp > 0) { tsp = len & wmask; do { *--dp = *--sp; } while (--tsp); } } return; } /** * NAME * mem_prim_move8 - Move (handles overlap) memory * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_move8(void *dest, const void *src, uint32_t len) * * DESCRIPTION * Moves at most len uint8_ts from sp to dp. * The destination may overlap with source. * * INPUT PARAMETERS * dp - pointer to the memory that will be replaced by sp. * * sp - pointer to the memory that will be copied * to dp * * len - maximum number uint8_t of sp that can be copied * * OUTPUT PARAMETERS * dp - pointer to the memory that will be replaced by sp. * * RETURN VALUE * none * */ void mem_prim_move8 (uint8_t *dp, const uint8_t *sp, uint32_t len) { /* * Determine if we need to copy forward or backward (overlap) */ if (dp < sp) { /* * Copy forward. */ while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; len -= 16; break; case 15: *dp++ = *sp++; case 14: *dp++ = *sp++; case 13: *dp++ = *sp++; case 12: *dp++ = *sp++; case 11: *dp++ = *sp++; case 10: *dp++ = *sp++; case 9: *dp++ = *sp++; case 8: *dp++ = *sp++; case 7: *dp++ = *sp++; case 6: *dp++ = *sp++; case 5: *dp++ = *sp++; case 4: *dp++ = *sp++; case 3: *dp++ = *sp++; case 2: *dp++ = *sp++; case 1: *dp++ = *sp++; len = 0; break; } } /* end while */ } else { /* * This section is used to copy backwards, to handle any * overlap. The alignment requires (tps&wmask) bytes to * align. */ /* * go to end of the memory to copy */ sp += len; dp += len; while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; len -= 16; break; case 15: *--dp = *--sp; case 14: *--dp = *--sp; case 13: *--dp = *--sp; case 12: *--dp = *--sp; case 11: *--dp = *--sp; case 10: *--dp = *--sp; case 9: *--dp = *--sp; case 8: *--dp = *--sp; case 7: *--dp = *--sp; case 6: *--dp = *--sp; case 5: *--dp = *--sp; case 4: *--dp = *--sp; case 3: *--dp = *--sp; case 2: *--dp = *--sp; case 1: *--dp = *--sp; len = 0; break; } } /* end while */ } return; } /** * NAME * mem_prim_move16 - Move (handles overlap) memory * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_move16(void *dest, const void *src, uint32_t len) * * DESCRIPTION * Moves at most len uint16_ts from sp to dp. * The destination may overlap with source. * * INPUT PARAMETERS * dp - pointer to the memory that will be replaced by sp. * * sp - pointer to the memory that will be copied * to dp * * len - maximum number uint16_t of sp that can be copied * * OUTPUT PARAMETERS * dp - is updated * * RETURN VALUE * none * */ void mem_prim_move16 (uint16_t *dp, const uint16_t *sp, uint32_t len) { /* * Determine if we need to copy forward or backward (overlap) */ if (dp < sp) { /* * Copy forward. */ while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; len -= 16; break; case 15: *dp++ = *sp++; case 14: *dp++ = *sp++; case 13: *dp++ = *sp++; case 12: *dp++ = *sp++; case 11: *dp++ = *sp++; case 10: *dp++ = *sp++; case 9: *dp++ = *sp++; case 8: *dp++ = *sp++; case 7: *dp++ = *sp++; case 6: *dp++ = *sp++; case 5: *dp++ = *sp++; case 4: *dp++ = *sp++; case 3: *dp++ = *sp++; case 2: *dp++ = *sp++; case 1: *dp++ = *sp++; len = 0; break; } } /* end while */ } else { /* * This section is used to copy backwards, to handle any * overlap. The alignment requires (tps&wmask) bytes to * align. */ /* * go to end of the memory to copy */ sp += len; dp += len; while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; len -= 16; break; case 15: *--dp = *--sp; case 14: *--dp = *--sp; case 13: *--dp = *--sp; case 12: *--dp = *--sp; case 11: *--dp = *--sp; case 10: *--dp = *--sp; case 9: *--dp = *--sp; case 8: *--dp = *--sp; case 7: *--dp = *--sp; case 6: *--dp = *--sp; case 5: *--dp = *--sp; case 4: *--dp = *--sp; case 3: *--dp = *--sp; case 2: *--dp = *--sp; case 1: *--dp = *--sp; len = 0; break; } } /* end while */ } return; } /** * NAME * mem_prim_move32 - Move (handles overlap) memory * * SYNOPSIS * #include "mem_primitives_lib.h" * void * mem_prim_move32(void *dest, const void *src, uint32_t len) * * DESCRIPTION * Moves at most len uint32_ts from sp to dp. * The destination may overlap with source. * * INPUT PARAMETERS * dp - pointer to the memory that will be replaced by sp. * * sp - pointer to the memory that will be copied * to dp * * len - maximum number uint32_t of sp that can be copied * * OUTPUT PARAMETERS * dp - is updated * * RETURN VALUE * none * */ void mem_prim_move32 (uint32_t *dp, const uint32_t *sp, uint32_t len) { /* * Determine if we need to copy forward or backward (overlap) */ if (dp < sp) { /* * Copy forward. */ while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; len -= 16; break; case 15: *dp++ = *sp++; case 14: *dp++ = *sp++; case 13: *dp++ = *sp++; case 12: *dp++ = *sp++; case 11: *dp++ = *sp++; case 10: *dp++ = *sp++; case 9: *dp++ = *sp++; case 8: *dp++ = *sp++; case 7: *dp++ = *sp++; case 6: *dp++ = *sp++; case 5: *dp++ = *sp++; case 4: *dp++ = *sp++; case 3: *dp++ = *sp++; case 2: *dp++ = *sp++; case 1: *dp++ = *sp++; len = 0; break; } } /* end while */ } else { /* * This section is used to copy backwards, to handle any * overlap. */ /* * go to end of the memory to copy */ sp += len; dp += len; while (len != 0) { switch (len) { /* * Here we do blocks of 8. Once the remaining count * drops below 8, take the fast track to finish up. */ default: *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp; len -= 16; break; case 15: *--dp = *--sp; case 14: *--dp = *--sp; case 13: *--dp = *--sp; case 12: *--dp = *--sp; case 11: *--dp = *--sp; case 10: *--dp = *--sp; case 9: *--dp = *--sp; case 8: *--dp = *--sp; case 7: *--dp = *--sp; case 6: *--dp = *--sp; case 5: *--dp = *--sp; case 4: *--dp = *--sp; case 3: *--dp = *--sp; case 2: *--dp = *--sp; case 1: *--dp = *--sp; len = 0; break; } } /* end while */ } return; } tboot-1.10.5/safestringlib/safeclib/mem_primitives_lib.h0000644000000000000000000000470414210363175021516 0ustar 00000000000000/*------------------------------------------------------------------ * mem_primitives_lib.h - Unguarded Memory Copy Routines * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __MEM_PRIMITIVES_LIB_H__ #define __MEM_PRIMITIVES_LIB_H__ #include "safeclib_private.h" /* * These are prototypes for _unguarded_ memory routines. The caller must * validate all parameters prior to invocation. Useful for diagnostics * and system initialization processing. */ /* moves (handles overlap) memory */ extern void mem_prim_move(void *dest, const void *src, uint32_t length); /* uint8_t moves (handles overlap) memory */ extern void mem_prim_move8(uint8_t *dest, const uint8_t *src, uint32_t length); /* uint16_t moves (handles overlap) memory */ extern void mem_prim_move16(uint16_t *dest, const uint16_t *src, uint32_t length); /* uint32_t moves (handles overlap) memory */ extern void mem_prim_move32(uint32_t *dest, const uint32_t *src, uint32_t length); /* set bytes */ extern void mem_prim_set(void *dest, uint32_t dmax, uint8_t value); /* set uint16_ts */ extern void mem_prim_set16(uint16_t *dest, uint32_t dmax, uint16_t value); /* set uint32_ts */ extern void mem_prim_set32(uint32_t *dest, uint32_t dmax, uint32_t value); #endif /* __MEM_PRIMITIVES_LIB_H__ */ tboot-1.10.5/safestringlib/safeclib/memcmp16_s.c0000644000000000000000000001152314210363175017576 0ustar 00000000000000/*------------------------------------------------------------------ * memcmp16_s.c - Compares memory * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "safe_mem_lib.h" /** * NAME * memcmp16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcmp16_s(const uint16_t *dest, rsize_t dmax, * const uint16_t *src, rsize_t smax, int *diff) * * DESCRIPTION * Compares memory until they differ, and their difference is * returned in diff. If the block of memory is the same, diff=0. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to compare against * * dmax maximum length of dest, in uint16_t * * src pointer to the source memory to compare with dest * * smax maximum length of src, in uint16_t * * *diff pointer to the diff which is an integer greater * than, equal to or less than zero according to * whether the object pointed to by dest is * greater than, equal to or less than the object * pointed to by src. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memcmp_s(), memcmp32_s() * */ errno_t memcmp16_s (const uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t smax, int *diff) { const uint16_t *dp; const uint16_t *sp; dp = dest; sp = src; /* * must be able to return the diff */ if (diff == NULL) { invoke_safe_mem_constraint_handler("memcmp16_s: diff is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } *diff = -1; /* default diff */ if (dp == NULL) { invoke_safe_mem_constraint_handler("memcmp16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (sp == NULL) { invoke_safe_mem_constraint_handler("memcmp16_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcmp16_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memcmp16_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { invoke_safe_mem_constraint_handler("memcmp16_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { invoke_safe_mem_constraint_handler("memcmp16_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * no need to compare the same memory */ if (dp == sp) { *diff = 0; return (RCNEGATE(EOK)); } /* * now compare sp to dp */ *diff = 0; while (dmax != 0 && smax != 0) { if (*dp != *sp) { *diff = *dp - *sp; break; } dmax--; smax--; dp++; sp++; } return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memcmp16_s); tboot-1.10.5/safestringlib/safeclib/memcmp32_s.c0000644000000000000000000001142614210363175017576 0ustar 00000000000000/*------------------------------------------------------------------ * memcmp32_s.c - Compares memory * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "safe_mem_lib.h" /** * NAME * memcmp32_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcmp32_s(const uint32_t *dest, rsize_t dmax, * const uint32_t *src, rsize_t smax, int *diff) * * DESCRIPTION * Compares memory until they differ, and their difference is * returned in diff. If the block of memory is the same, diff=0. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to compare against * * dmax maximum length of dest, in uint32_t * * src pointer to the source memory to compare with dest * * smax maximum length of src, in uint32_t * * *diff pointer to the diff which is an integer greater * than, equal to or less than zero according to * whether the object pointed to by dest is * greater than, equal to or less than the object * pointed to by src. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memcmp_s(), memcmp16_s() * */ errno_t memcmp32_s (const uint32_t *dest, rsize_t dmax, const uint32_t *src, rsize_t smax, int *diff) { /* * must be able to return the diff */ if (diff == NULL) { invoke_safe_mem_constraint_handler("memcmp32_s: diff is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } *diff = -1; /* default diff */ if (dest == NULL) { invoke_safe_mem_constraint_handler("memcmp32_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (src == NULL) { invoke_safe_mem_constraint_handler("memcmp32_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcmp32_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM32) { invoke_safe_mem_constraint_handler("memcmp32_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { invoke_safe_mem_constraint_handler("memcmp32_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { invoke_safe_mem_constraint_handler("memcmp32_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * no need to compare the same memory */ if (dest == src) { *diff = 0; return (RCNEGATE(EOK)); } /* * now compare src to dest */ *diff = 0; while (dmax != 0 && smax != 0) { if (*dest != *src) { *diff = *dest - *src; break; } dmax--; smax--; dest++; src++; } return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memcmp32_s); tboot-1.10.5/safestringlib/safeclib/memcmp_s.c0000644000000000000000000001152514210363175017431 0ustar 00000000000000/*------------------------------------------------------------------ * memcmp_s.c - Compares memory * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "safe_mem_lib.h" /** * NAME * memcmp_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcmp_s(const void *dest, rsize_t dmax, * const void *src, rsize_t smax, int *diff) * * DESCRIPTION * Compares memory until they differ, and their difference is * returned in diff. If the block of memory is the same, diff=0. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to compare against * * dmax maximum length of dest, in bytess * * src pointer to the source memory to compare with dest * * smax length of the source memory block * * *diff pointer to the diff which is an integer greater * than, equal to or less than zero according to * whether the object pointed to by dest is * greater than, equal to or less than the object * pointed to by src. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memcmp16_s(), memcmp32_s() * */ errno_t memcmp_s (const void *dest, rsize_t dmax, const void *src, rsize_t smax, int *diff) { const uint8_t *dp; const uint8_t *sp; dp = dest; sp = src; /* * must be able to return the diff */ if (diff == NULL) { invoke_safe_mem_constraint_handler("memcmp_s: diff is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } *diff = -1; /* default diff */ if (dp == NULL) { invoke_safe_mem_constraint_handler("memcmp_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (sp == NULL) { invoke_safe_mem_constraint_handler("memcmp_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcmp_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("memcmp_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { invoke_safe_mem_constraint_handler("memcmp_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { invoke_safe_mem_constraint_handler("memcmp_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * no need to compare the same memory */ if (dp == sp) { *diff = 0; return (RCNEGATE(EOK)); } /* * now compare sp to dp */ *diff = 0; while (dmax > 0 && smax > 0) { if (*dp != *sp) { /*** *diff = *dp - *sp; ***/ *diff = *dp < *sp ? -1 : 1; break; } dmax--; smax--; dp++; sp++; } return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memcmp_s); tboot-1.10.5/safestringlib/safeclib/memcpy16_s.c0000644000000000000000000001132014210363175017605 0ustar 00000000000000/*------------------------------------------------------------------ * memcpy16_s * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memcpy16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcpy16_s(uint16_t *dest, rsize_t dmax, * const uint16_t *src, rsize_t smax) * * DESCRIPTION * This function copies at most smax uint16_ts from src to dest, up to * dmax. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be replaced by src. * * dmax maximum length of the resulting dest * * src pointer to the memory that will be copied to dest * * smax maximum number uint16_t of src to copy * * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM16. * smax shall not be greater than dmax. * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, the memcpy_s function stores * zeros in the ï¬rst dmax bytes of the object pointed to by dest * if dest is not a null pointer and smax is valid. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP source memory overlaps destination * * ALSO SEE * memcpy_s(), memcpy32_s(), memmove_s(), memmove16_s(), memmove32_s() * */ errno_t memcpy16_s (uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t smax) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memcpy16_s: dest is NULL", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcpy16_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memcpy16_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (src == NULL) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: src is NULL", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * overlap is undefined behavior, do not allow */ if( ((dest > src) && (dest < (src+smax))) || ((src > dest) && (src < (dest+dmax))) ) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: overlap undefined", NULL, ESOVRLP); return (RCNEGATE(ESOVRLP)); } /* * now perform the copy */ mem_prim_move16(dest, src, smax); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memcpy16_s); tboot-1.10.5/safestringlib/safeclib/memcpy32_s.c0000644000000000000000000001130614210363175017607 0ustar 00000000000000/*------------------------------------------------------------------ * memcpy32_s * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memcpy32_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcpy32_s(uint32_t *dest, rsize_t dmax, * const uint32_t *src, rsize_t smax) * * DESCRIPTION * This function copies at most smax uint32_ts from src to dest, up to * dmax. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be replaced by src. * * dmax maximum length of the resulting dest * * src pointer to the memory that will be copied to dest * * smax maximum number uint32_t of src to copy * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM32. * smax shall not be greater than dmax. * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, the memcpy_s function stores * zeros in the ï¬rst dmax bytes of the object pointed to by dest * if dest is not a null pointer and smax is valid. * * RETURN VALUE * EOK operation sucessful * ESNULLP NULL pointer * ESZEROL length was zero * ESLEMAX length exceeds max * ESOVRLP source memory overlaps destination * * ALSO SEE * memcpy_s(), memcpy16_s(), memmove_s(), memmove16_s(), memmove32_s() * */ errno_t memcpy32_s (uint32_t *dest, rsize_t dmax, const uint32_t *src, rsize_t smax) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memcpy32_s: dest is NULL", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcpy32_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM32) { invoke_safe_mem_constraint_handler("memcpy32_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set32(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy32_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set32(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy32_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (src == NULL) { mem_prim_set32(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy32_s: src is NULL", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * overlap is undefined behavior, do not allow */ if( ((dest > src) && (dest < (src+smax))) || ((src > dest) && (src < (dest+dmax))) ) { mem_prim_set32(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy32_s: overlap undefined", NULL, ESOVRLP); return (RCNEGATE(ESOVRLP)); } /* * now perform the copy */ mem_prim_move32(dest, src, smax); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memcpy32_s); tboot-1.10.5/safestringlib/safeclib/memcpy_s.c0000644000000000000000000001125614210363175017446 0ustar 00000000000000/*------------------------------------------------------------------ * memcpy_s * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memcpy_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcpy_s(void *dest, rsize_t dmax, const void *src, rsize_t smax) * * DESCRIPTION * This function copies at most smax bytes from src to dest, up to * dmax. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be replaced by src. * * dmax maximum length of the resulting dest * * src pointer to the memory that will be copied to dest * * smax maximum number bytes of src to copy * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * Copying shall not take place between regions that overlap. * If there is a runtime-constraint violation, the memcpy_s function * stores zeros in the ï¬rst dmax bytes of the region pointed to * by dest if dest is not a null pointer and smax is valid. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP source memory overlaps destination * * ALSO SEE * memcpy16_s(), memcpy32_s(), memmove_s(), memmove16_s(), * memmove32_s() * */ errno_t memcpy_s (void *dest, rsize_t dmax, const void *src, rsize_t smax) { uint8_t *dp; const uint8_t *sp; dp = dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("memcpy_s: dest is NULL", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("memcpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (smax == 0) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: smax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (smax > dmax) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: smax exceeds dmax", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (sp == NULL) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: src is NULL", NULL, ESNULLP); return RCNEGATE(ESNULLP); } /* * overlap is undefined behavior, do not allow */ if( ((dp > sp) && (dp < (sp+smax))) || ((sp > dp) && (sp < (dp+dmax))) ) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: overlap undefined", NULL, ESOVRLP); return RCNEGATE(ESOVRLP); } /* * now perform the copy */ mem_prim_move(dp, sp, smax); return RCNEGATE(EOK); } EXPORT_SYMBOL(memcpy_s); tboot-1.10.5/safestringlib/safeclib/memmove16_s.c0000644000000000000000000001140114210363175017760 0ustar 00000000000000/*------------------------------------------------------------------ * memmove16_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memmove16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memmove16_s(uint16_t *dest, rsize_t dmax, * const uint16_t *src, rsize_t smax) * * DESCRIPTION * The memmove16_s function copies smax uint16_t from the region * pointed to by src into the region pointed to by dest. This * copying takes place as if the smax uint16_t from the region * pointed to by src are ï¬rst copied into a temporary array of * smax uint16_t that does not overlap the regions pointed to * by dest or src, and then the smax uint16_t from the temporary * array are copied into the region pointed to by dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to the memory that will be replaced by src. * * dmax maximum length of the resulting dest, in uint16_t * * src pointer to the memory that will be copied * to dest * * smax maximum number uint16_t of src that can be copied * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * If there is a runtime-constraint violation, the memmove_s function * stores zeros in the ï¬rst dmax characters of the regionpointed to * by dest if dest is not a null pointer and dmax is not greater * than RSIZE_MAX_MEM. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memmove_s(), memmove32_s(), memcpy_s(), memcpy16_s() memcpy32_s() * */ errno_t memmove16_s (uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t smax) { uint16_t *dp; const uint16_t *sp; dp= dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("memove16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memove16_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memove16_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set16(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove16_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set16(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove16_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (sp == NULL) { mem_prim_set16(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove16_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * now perform the copy */ mem_prim_move16(dp, sp, smax); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memmove16_s); tboot-1.10.5/safestringlib/safeclib/memmove32_s.c0000644000000000000000000001140714210363175017764 0ustar 00000000000000/*------------------------------------------------------------------ * memmove32_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memmove32_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memmove32_s(uint32_t *dest, rsize_t dmax, * const uint32_t *src, rsize_t smax) * * DESCRIPTION * The memmove32_s function copies smax uint32_ts from the region * pointed to by src into the region pointed to by dest. This * copying takes place as if the smax uint32_ts from the region * pointed to by src are ï¬rst copied into a temporary array of * smax uint32_ts that does not overlap the regions pointed to * by dest or src, and then the smax uint32_ts from the temporary * array are copied into the region pointed to by dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to the memory that will be replaced by src. * * dmax maximum length of the resulting dest, in uint32_t * * src pointer to the memory that will be copied * to dest * * smax maximum number uint32_t of src that can be copied * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * If there is a runtime-constraint violation, the memmove_s function * stores zeros in the ï¬rst dmax characters of the regionpointed to * by dest if dest is not a null pointer and dmax is not greater * than RSIZE_MAX_MEM. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memmove_s(), memmove16_s(), memcpy_s(), memcpy16_s() memcpy32_s() * */ errno_t memmove32_s (uint32_t *dest, rsize_t dmax, const uint32_t *src, rsize_t smax) { uint32_t *dp; const uint32_t *sp; dp= dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("memove32_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memove32_s: dest is zero", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM32) { invoke_safe_mem_constraint_handler("memove32_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set32(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove32_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set32(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove32_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (sp == NULL) { mem_prim_set32(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove32_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * now perform the copy */ mem_prim_move32(dp, sp, smax); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memmove32_s); tboot-1.10.5/safestringlib/safeclib/memmove_s.c0000644000000000000000000001125314210363175017616 0ustar 00000000000000/*------------------------------------------------------------------ * memmove_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memmove_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memmove_s(void *dest, rsize_t dmax, * const void *src, rsize_t smax) * * DESCRIPTION * The memmove_s function copies smax bytes from the region pointed * to by src into the region pointed to by dest. This copying takes place * as if the smax bytes from the region pointed to by src are ï¬rst copied * into a temporary array of smax bytes that does not overlap the region * pointed to by dest or src, and then the smax bytes from the temporary * array are copied into the object region to by dest. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to the memory that will be replaced by src. * * dmax maximum length of the resulting dest, in bytes * * src pointer to the memory that will be copied * to dest * * smax maximum number bytes of src that can be copied * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * If there is a runtime-constraint violation, the memmove_s function * stores zeros in the ï¬rst dmax characters of the regionpointed to * by dest if dest is not a null pointer and dmax is not greater * than RSIZE_MAX_MEM. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memmove16_s(), memmove32_s(), memcpy_s(), memcpy16_s() memcpy32_s() * */ errno_t memmove_s (void *dest, rsize_t dmax, const void *src, rsize_t smax) { uint8_t *dp; const uint8_t *sp; dp= dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("memmove_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memmove_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("memmove_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memmove_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memmove_s: smax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (sp == NULL) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memmove_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * now perform the copy */ mem_prim_move(dp, sp, smax); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memmove_s); tboot-1.10.5/safestringlib/safeclib/memset16_s.c0000644000000000000000000000623314210363175017614 0ustar 00000000000000/*------------------------------------------------------------------ * memset16_s * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memset16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memset16_s(uint16_t *dest, rsize_t len, uint16_t value) * * DESCRIPTION * Sets len uint16_t starting at dest to the specified value. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be set to the value * * len number of uint16_t to be set * * value uint16_t value to be written * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM16. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memset_s(), memset32_s() * */ errno_t memset16_s (uint16_t *dest, rsize_t len, uint16_t value) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memset16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memset16_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memset16_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } mem_prim_set16(dest, len, value); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memset16_s); tboot-1.10.5/safestringlib/safeclib/memset32_s.c0000644000000000000000000000627614210363175017621 0ustar 00000000000000/*------------------------------------------------------------------ * memset32_s * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memset32_s - Sets a block of memory to value * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memset32_s(uint32_t *dest, rsize_t len, uint32_t value) * * DESCRIPTION * Sets len uint32_t starting at dest to the specified value. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be set to the value * * len number of uint32_t to be set * * value uint32_t value to be written * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM32. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memset_s(), memset16_s() * */ errno_t memset32_s (uint32_t *dest, rsize_t len, uint32_t value) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memset32_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memset32_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM32) { invoke_safe_mem_constraint_handler("memset32_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } mem_prim_set32(dest, len, value); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memset32_s); tboot-1.10.5/safestringlib/safeclib/memset_s.c0000644000000000000000000000614514210363175017447 0ustar 00000000000000/*------------------------------------------------------------------ * memset_s * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memset_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memset_s(void *dest, rsize_t len, uint8_t value) * * DESCRIPTION * Sets len bytes starting at dest to the specified value. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be set to the value * * len number of bytes to be set * * value byte value * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memset16_s(), memset32_s() * */ errno_t memset_s (void *dest, rsize_t len, uint8_t value) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memset_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memset_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("memset_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } mem_prim_set(dest, len, value); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memset_s); tboot-1.10.5/safestringlib/safeclib/memzero16_s.c0000644000000000000000000000624514210363175020003 0ustar 00000000000000/*------------------------------------------------------------------ * memzero16_s - zeros memory * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memzero16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memzero16_s(uint16_t *dest, rsize_t len) * * DESCRIPTION * Zeros len uint16_ts starting at dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to be zeroed. * * len number of uint16_ts to be zeroed * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM16. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memzero_s(), memzero32_s() * */ errno_t memzero16_s (uint16_t *dest, rsize_t len) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memzero16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memzero16_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memzero16_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * mem_prim_set16(dest, len, 0xDEAD); * mem_prim_set16(dest, len, 0xBEEF); */ mem_prim_set16(dest, len, 0); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memzero16_s); tboot-1.10.5/safestringlib/safeclib/memzero32_s.c0000644000000000000000000000625614210363175020003 0ustar 00000000000000/*------------------------------------------------------------------ * memzero32_s - zeros memory * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memzero32_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memzero32_s(uint32_t *dest, rsize_t len) * * DESCRIPTION * Zeros len uint32_ts starting at dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to be zeroed. * * len number of uint32_ts to be zeroed * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM32. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memzero_s(), memzero16_s() * */ errno_t memzero32_s (uint32_t *dest, rsize_t len) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memzero32_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memzero32_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM32) { invoke_safe_mem_constraint_handler("memzero32_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * mem_prim_set32(dest, len, 0xDEADBEEF); * mem_prim_set32(dest, len, 0xBA5EBA11); */ mem_prim_set32(dest, len, 0); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memzero32_s); tboot-1.10.5/safestringlib/safeclib/memzero_s.c0000644000000000000000000000617114210363175017632 0ustar 00000000000000/*------------------------------------------------------------------ * memzero_s - zeros memory * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * memzero_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memzero_s(void *dest, rsize_t len) * * DESCRIPTION * Zeros len bytes starting at dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to be zeroed. * * len number of bytes to be zeroed * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memzero16_s(), memzero32_s() * */ errno_t memzero_s (void *dest, rsize_t len) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memzero_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memzero_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("memzero_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * mem_prim_set(dest, len, 0xA5); * mem_prim_set(dest, len, 0x5A); */ mem_prim_set(dest, len, 0); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(memzero_s); tboot-1.10.5/safestringlib/safeclib/safe_mem_constraint.c0000644000000000000000000001101714210363175021645 0ustar 00000000000000/*------------------------------------------------------------------ * safe_mem_constraint.c * * October 2008, Bo Berry * 2012, Jonathan Toppins * * Copyright (c) 2008-2012 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "safe_mem_lib.h" static constraint_handler_t mem_handler = NULL; /** * NAME * set_mem_constraint_handler_s * * SYNOPSIS * #include "safe_mem_lib.h" * constraint_handler_t * set_mem_constraint_handler_straint_handler_t handler) * * DESCRIPTION * The set_mem_constraint_handler_s function sets the runtime-constraint * handler to be handler. The runtime-constraint handler is the function to * be called when a library function detects a runtime-constraint * order: * 1. A pointer to a character string describing the * runtime-constraint violation. * 2. A null pointer or a pointer to an implementation defined * object. * 3. If the function calling the handler has a return type declared * as errno_t, the return value of the function is passed. * Otherwise, a positive value of type errno_t is passed. * The implementation has a default constraint handler that is used if no * calls to the set_constraint_handler_s function have been made. The * behavior of the default handler is implementation-defined, and it may * cause the program to exit or abort. If the handler argument to * set_constraint_handler_s is a null pointer, the implementation default * handler becomes the current constraint handler. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * *msg Pointer to the message describing the error * * *ptr Pointer to aassociated data. Can be NULL. * * error The error code encountered. * * OUTPUT PARAMETERS * none * * RETURN VALUE * none * * ALSO SEE * set_str_constraint_handler_s() */ constraint_handler_t set_mem_constraint_handler_s (constraint_handler_t handler) { constraint_handler_t prev_handler = mem_handler; if (NULL == handler) { mem_handler = sl_default_handler; } else { mem_handler = handler; } return prev_handler; } EXPORT_SYMBOL(set_mem_constraint_handler_s); /** * NAME * invoke_safe_mem_constraint_handler * * SYNOPSIS * #include "safe_mem_constraint.h" * void * invoke_safe_mem_constraint_handler(const char *msg, * void *ptr, * errno_t error) * * DESCRIPTION * Invokes the currently set constraint handler or the default. * * INPUT PARAMETERS * *msg Pointer to the message describing the error * * *ptr Pointer to aassociated data. Can be NULL. * * error The error code encountered. * * OUTPUT PARAMETERS * none * * RETURN VALUE * none * */ void invoke_safe_mem_constraint_handler (const char *msg, void *ptr, errno_t error) { if (NULL != mem_handler) { mem_handler(msg, ptr, error); } else { sl_default_handler(msg, ptr, error); } } tboot-1.10.5/safestringlib/safeclib/safe_mem_constraint.h0000644000000000000000000000337114210363175021656 0ustar 00000000000000/*------------------------------------------------------------------ * safe_mem_constraint.h * * October 2008, Bo Berry * * Copyright (c) 2008, 2009 by Cisco Systems, Inc. * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_MEM_CONSTRAINT_H__ #define __SAFE_MEM_CONSTRAINT_H__ #include "safeclib_private.h" /* * Function used by the libraries to invoke the registered * runtime-constraint handler. Always needed. */ extern void invoke_safe_mem_constraint_handler( const char *msg, void *ptr, errno_t error); #endif /* __SAFE_MEM_CONSTRAINT_H__ */ tboot-1.10.5/safestringlib/safeclib/safe_str_constraint.c0000644000000000000000000001142214210363175021677 0ustar 00000000000000/*------------------------------------------------------------------ * safe_str_constraint.c * * October 2008, Bo Berry * 2012, Jonathan Toppins * * Copyright (c) 2008, 2009, 2012 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" static constraint_handler_t str_handler = NULL; /** * NAME * set_str_constraint_handler_s * * SYNOPSIS * #include "safe_str_lib.h" * constraint_handler_t * set_str_constraint_handler_s(constraint_handler_t handler) * * DESCRIPTION * The set_str_constraint_handler_s function sets the runtime-constraint * handler to be handler. The runtime-constraint handler is the function to * be called when a library function detects a runtime-constraint * violation. Only the most recent handler registered with * set_str_constraint_handler_s is called when a runtime-constraint * violation occurs. * When the handler is called, it is passed the following arguments in * the following order: * 1. A pointer to a character string describing the * runtime-constraint violation. * 2. A null pointer or a pointer to an implementation defined * object. * 3. If the function calling the handler has a return type declared * as errno_t, the return value of the function is passed. * Otherwise, a positive value of type errno_t is passed. * The implementation has a default constraint handler that is used if no * calls to the set_constraint_handler_s function have been made. The * behavior of the default handler is implementation-defined, and it may * cause the program to exit or abort. If the handler argument to * set_constraint_handler_s is a null pointer, the implementation default * handler becomes the current constraint handler. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * *msg Pointer to the message describing the error * * *ptr Pointer to aassociated data. Can be NULL. * * error The error code encountered. * * OUTPUT PARAMETERS * none * * RETURN VALUE * none * * ALSO SEE * set_str_constraint_handler_s() */ constraint_handler_t set_str_constraint_handler_s (constraint_handler_t handler) { constraint_handler_t prev_handler = str_handler; if (NULL == handler) { str_handler = sl_default_handler; } else { str_handler = handler; } return prev_handler; } EXPORT_SYMBOL(set_str_constraint_handler_s); /** * NAME * invoke_safe_str_constraint_handler * * SYNOPSIS * #include "safe_str_constraint.h" * void * invoke_safe_str_constraint_handler (const char *msg, * void *ptr, * errno_t error) * * DESCRIPTION * Invokes the currently set constraint handler or the default. * * INPUT PARAMETERS * *msg Pointer to the message describing the error * * *ptr Pointer to aassociated data. Can be NULL. * * error The error code encountered. * * OUTPUT PARAMETERS * none * * RETURN VALUE * none * */ void invoke_safe_str_constraint_handler (const char *msg, void *ptr, errno_t error) { if (NULL != str_handler) { str_handler(msg, ptr, error); } else { sl_default_handler(msg, ptr, error); } } tboot-1.10.5/safestringlib/safeclib/safe_str_constraint.h0000644000000000000000000000524414210363175021711 0ustar 00000000000000/*------------------------------------------------------------------ * safe_str_constraint.h * * October 2008, Bo Berry * * Copyright (c) 2008-2011 Cisco Systems * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFE_STR_CONSTRAINT_H__ #define __SAFE_STR_CONSTRAINT_H__ #include "safeclib_private.h" /* * Function used by the libraries to invoke the registered * runtime-constraint handler. Always needed. */ extern void invoke_safe_str_constraint_handler( const char *msg, void *ptr, errno_t error); /* * Safe C Lib internal string routine to consolidate error handling */ static inline void handle_error(char *orig_dest, rsize_t orig_dmax, const char *err_msg, errno_t err_code) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to eliminate partial copy */ while (orig_dmax) { *orig_dest = '\0'; orig_dmax--; orig_dest++; } #else (void) orig_dmax; *orig_dest = '\0'; #endif invoke_safe_str_constraint_handler(err_msg, NULL, err_code); return; } static inline void handle_wc_error(wchar_t *orig_dest, rsize_t orig_dmax, const char *err_msg, errno_t err_code) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to eliminate partial copy */ while (orig_dmax) { *orig_dest = L'\0'; orig_dmax--; orig_dest++; } #else (void) orig_dmax; *orig_dest = L'\0'; #endif invoke_safe_str_constraint_handler(err_msg, NULL, err_code); return; } #endif /* __SAFE_STR_CONSTRAINT_H__ */ tboot-1.10.5/safestringlib/safeclib/safeclib_private.h0000644000000000000000000000477514210363175021151 0ustar 00000000000000/*------------------------------------------------------------------ * safeclib_private.h - Internal library references * * 2012, Jonathan Toppins * * Copyright (c) 2012, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __SAFECLIB_PRIVATE_H__ #define __SAFECLIB_PRIVATE_H__ #ifdef __KERNEL__ /* linux kernel environment */ #include #include #include #define RCNEGATE(x) ( -(x) ) #define slprintf(...) printk(KERN_EMERG __VA_ARGS__) #define slabort() #ifdef DEBUG #define sldebug_printf(...) printk(KERN_DEBUG __VA_ARGS__) #endif #else /* !__KERNEL__ */ #if HAVE_CONFIG_H #include "config.h" #endif #include #ifdef STDC_HEADERS # include # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_LIMITS_H # include #endif #define EXPORT_SYMBOL(sym) #define RCNEGATE(x) (x) #define slprintf(...) fprintf(stderr, __VA_ARGS__) #define slabort() abort() #ifdef DEBUG #define sldebug_printf(...) printf(__VA_ARGS__) #endif #endif /* __KERNEL__ */ #ifndef sldebug_printf #define sldebug_printf(...) #endif #include "safe_lib.h" #endif /* __SAFECLIB_PRIVATE_H__ */ tboot-1.10.5/safestringlib/safeclib/snprintf_support.c0000644000000000000000000002216314210363175021270 0ustar 00000000000000/*------------------------------------------------------------------ * snprintf_support.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" #include "snprintf_s.h" #define FMT_CHAR 'c' #define FMT_WCHAR 'C' #define FMT_SHORT 'h' #define FMT_INT 'd' #define FMT_LONG 'l' #define FMT_STRING 's' #define FMT_WSTRING 'S' #define FMT_DOUBLE 'g' #define FMT_LDOUBLE 'G' #define FMT_VOID 'p' #define FMT_PCHAR '1' #define FMT_PSHORT '2' #define FMT_PINT '3' #define FMT_PLONG '4' #define MAX_FORMAT_ELEMENTS 16 #define CHK_FORMAT(X,Y) (((X)==(Y))?1:0) unsigned int parse_format(const char *format, char pformatList[], unsigned int maxFormats) { unsigned int numFormats = 0; unsigned int index = 0; unsigned int start = 0; char lmod = 0; while (index < RSIZE_MAX_STR && format[index] != '\0' && numFormats < maxFormats) { if (format[index] == '%') { start = index; // remember where the format string started // Check for flags switch( format[++index]) { case '\0': continue; // skip - end of format string case '%' : continue; // skip - actually a percent character case '#' : // convert to alternate form case '0' : // zero pad case '-' : // left adjust case ' ' : // pad with spaces case '+' : // force a sign be used index++; // skip the flag character break; default: break; } // check for and skip the optional field width while ( format[index] != '\0' && format[index] >= '0' && format[index] <= '9') { index++; } // Check for an skip the optional precision if ( format[index] != '\0' && format[index] == '.') { index++; // skip the period while ( format[index] != '\0' && format[index] >= '0' && format[index] <= '9') { index++; } } // Check for and skip the optional length modifiers lmod = ' '; switch( format[index]) { case 'h' : if ( format[++index] == 'h') { ++index; //also recognize the 'hh' modifier lmod = 'H'; // for char } else { lmod = 'h'; // for short } break; case 'l' : if ( format[++index] == 'l') { ++index; //also recognize the 'll' modifier lmod = 'd'; // for long long } else { lmod = 'l'; // for long } break; case 'L' : lmod = 'L'; break; case 'j' : case 'z' : case 't' : index++; break; default: break; } // Recognize and record the actual modifier switch( format[index]) { case 'c' : if ( lmod == 'l') { pformatList[numFormats] = FMT_WCHAR; // store the format character } else { pformatList[numFormats] = FMT_CHAR; } numFormats++; index++; // skip the format character break; case 'd' : case 'i' : // signed case 'o' : case 'u' : // unsigned case 'x' : case 'X' : // unsigned if ( lmod == 'H') { pformatList[numFormats] = FMT_CHAR; // store the format character } else if ( lmod == 'l') { pformatList[numFormats] = FMT_LONG; // store the format character } else if ( lmod == 'h') { pformatList[numFormats] = FMT_SHORT; // store the format character } else{ pformatList[numFormats] = FMT_INT; } numFormats++; index++; // skip the format character break; case 'e' : case 'E' : case 'f' : case 'F' : case 'g' : case 'G' : case 'a' : case 'A' : if ( lmod == 'L') { pformatList[numFormats] = FMT_LDOUBLE; // store the format character } else{ pformatList[numFormats] = FMT_DOUBLE; } numFormats++; index++; // skip the format character break; case 's' : if ( lmod == 'l' || lmod == 'L') { pformatList[numFormats] = FMT_WSTRING; // store the format character } else { pformatList[numFormats] = FMT_STRING; } numFormats++; index++; // skip the format character break; case 'p' : pformatList[numFormats] = FMT_VOID; numFormats++; index++; // skip the format character break; case 'n' : if ( lmod == 'H') { pformatList[numFormats] = FMT_PCHAR; // store the format character } else if ( lmod == 'l') { pformatList[numFormats] = FMT_PLONG; // store the format character } else if ( lmod == 'h') { pformatList[numFormats] = FMT_PSHORT; // store the format character } else{ pformatList[numFormats] = FMT_PINT; } numFormats++; index++; // skip the format character break; case 'm' : // Does not represent an argument in the call stack index++; // skip the format character continue; default: printf("failed to recognize format string ["); for (;start RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("stpcpy_s: dmax exceeds max", NULL, ESLEMAX); *err = RCNEGATE(ESLEMAX); return NULL; } if (src == NULL) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif invoke_safe_str_constraint_handler("stpcpy_s: src is null", NULL, ESNULLP); *err = RCNEGATE(ESNULLP); return NULL; } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest == src) { /* look for the terminating null character, or return err if not found in dmax bytes */ while (dmax > 0) { if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif *err = RCNEGATE(EOK); return dest; } dmax--; dest++; } /* null terminator not found in src before end of dmax */ handle_error(orig_dest, orig_dmax, "stpcpy_s: not enough space for src", ESNOSPC); *err = RCNEGATE(ESNOSPC); return NULL; } if (dest < src) { overlap_bumper = src; /* Check that the dest buffer does not overlap src buffer */ while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "stpcpy_s: " "overlapping objects", ESOVRLP); *err = RCNEGATE(ESOVRLP); return NULL; } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif *err = RCNEGATE(EOK); return dest; } dmax--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { /* check that the src buffer does not run into the dest buffer - inifinite loop */ if (src == overlap_bumper) { /* NOTE (dmw) this condition guarantees that SRC has already been damaged! */ handle_error(orig_dest, orig_dmax, "stpcpy_s: overlapping objects", ESOVRLP); *err = RCNEGATE(ESOVRLP); return NULL; } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif *err = RCNEGATE(EOK); return dest; } dmax--; dest++; src++; } } /* * Ran out of space in dest, and did not find the null terminator in src */ handle_error(orig_dest, orig_dmax, "stpcpy_s: not " "enough space for src", ESNOSPC); *err = RCNEGATE(ESNOSPC); return NULL; } EXPORT_SYMBOL(stpcpy_s); tboot-1.10.5/safestringlib/safeclib/stpncpy_s.c0000644000000000000000000002274714210363175017663 0ustar 00000000000000/*------------------------------------------------------------------ * stpncpy_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * stpncpy_s * * SYNOPSIS * #include "safe_str_lib.h" * char * * stpncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t smax, errno_t *err); * * DESCRIPTION * The stpncpy_s function copies at most smax characters from the string * pointed to by src, including the terminating null byte ('\0'), to the * array pointed to by dest. Exactly smax characters are written at dest. * If the length strlen_s(src) is smaller than smax, the remaining smax * characters in the array pointed to by dest are filled with null bytes. * If the length strlen_s(src) is greater than or equal to smax, the string * pointed to by dest will contain smax characters from src plus a null * characters (dest will be null-terminated). * * Therefore, dmax must be at least smax+1 in order to contain the terminator. * * The function returns a pointer to the end of the string in dest - * that is to the null terminator of dest. If an error occurs, * NULL is returned and err is set to the error encountered. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * * dmax restricted maximum length of dest (must be at least smax+1) * * src pointer to the string that will be copied * to dest * * smax the maximum number of characters from src to copy into dest * * err the error code upon error, or EOK if successful * * OUTPUT PARAMETERS * dest updated * err updated as follows: * EOK successful operation, the characters in src were * copied into dest and the result is null terminated, * and dest is returned to point to the first null at end of dest. * On error, NULL is returned and err is set to one of hte following: * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not be greater than RSIZE_MAX_STR. * dmax shall not equal zero. * dmax must be at least smax+1 to allow filling dest with smax characters plus NULL. * If src and dest overlap, copying shall be stopped; destruction of src may have occurred. * If there is a runtime-constraint violation, then: * if dest is not a null pointer and dmax is greater than zero and * not greater than RSIZE_MAX_STR, then stpncpy_s shall fill dest with nulls, * if library was compiled with SAFECLIB_STR_NULL_SLACK. * * RETURN VALUE * a char pointer to the terminating null at the end of dest * or NULL pointer on error * * ALSO SEE * stpcpy_s(), strcpy_s(), strcat_s(), strncat_s(), strncpy_s() * */ char * stpncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t smax, errno_t *err) { rsize_t orig_dmax; char *orig_dest; if (dest == NULL) { invoke_safe_str_constraint_handler("stpncpy_s: dest is null", NULL, ESNULLP); *err = RCNEGATE(ESNULLP); return NULL; } if (src == NULL) { invoke_safe_str_constraint_handler("stpncpy_s: src is null", NULL, ESNULLP); *err = RCNEGATE(ESNULLP); dest[0] = '\0'; return NULL; } if (dmax == 0) { invoke_safe_str_constraint_handler("stpncpy_s: dmax is 0", NULL, ESZEROL); *err = RCNEGATE(ESZEROL); return NULL; } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("stpncpy_s: dmax exceeds max", NULL, ESLEMAX); *err = RCNEGATE(ESLEMAX); return NULL; } if (smax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("stpncpy_s: smax exceeds max", NULL, ESLEMAX); *err = RCNEGATE(ESLEMAX); return NULL; } if (dmax < (smax+1)) { invoke_safe_str_constraint_handler("stpncpy_s: dmax too short for smax", NULL, ESNOSPC); *err = RCNEGATE(ESNOSPC); dest[0] = '\0'; return NULL; } /* dmwheel1: Add check to prevent destruction of overlap into destination */ if ((src < dest) && ((src+smax) >= dest)) { invoke_safe_str_constraint_handler("stpncpy_s: src+smax overlaps into dest", NULL, ESOVRLP); *err = RCNEGATE(ESOVRLP); dest[0] = '\0'; return NULL; } /* dmwheel1: Add check to prevent destruction of overlap into source */ if ((dest < src) && ((dest+smax) >= src)) { invoke_safe_str_constraint_handler("stpncpy_s: dest+smax overlaps into src", NULL, ESOVRLP); *err = RCNEGATE(ESOVRLP); dest[0] = '\0'; return NULL; } #ifdef SAFECLIB_STR_NULL_SLACK /* dmwheel1: Add check to prevent destruction of overlap into destination */ if ((src < dest) && ((src+dmax) >= dest)) { invoke_safe_str_constraint_handler("stpncpy_s: src+dmax overlaps into dest", NULL, ESOVRLP); *err = RCNEGATE(ESOVRLP); return NULL; } /* dmwheel1: Add check to prevent destruction of overlap into source */ if ((dest < src) && ((dest+dmax) >= src)) { invoke_safe_str_constraint_handler("stpncpy_s: dest+dmax overlaps into src", NULL, ESOVRLP); *err = RCNEGATE(ESOVRLP); return NULL; } #endif if (src == NULL) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif invoke_safe_str_constraint_handler("stpncpy_s: src is null", NULL, ESNULLP); *err = RCNEGATE(ESNULLP); return NULL; } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest == src) { /* look for the terminating null character, or return err if not found in dmax bytes */ while (dmax > 0) { if (*dest == '\0') { /* add nulls to complete smax */ char *filler = dest; /* don't change dest, because we need to return it */ while (smax) { *filler = '\0'; dmax--; smax--; filler++; } #ifdef SAFECLIB_STR_NULL_SLACK /* null dmax slack to clear any data */ while (dmax) { *filler = '\0'; dmax--; filler++; } #endif *err = RCNEGATE(EOK); return dest; } dmax--; dest++; if (--smax == 0) { /* we have copied smax characters, add null terminator */ *dest = '\0'; } } /* null terminator not found in src before end of dmax */ handle_error(orig_dest, orig_dmax, "stpncpy_s: not enough space for src", ESNOSPC); *err = RCNEGATE(ESNOSPC); return NULL; } /* All checks for buffer overlaps were made, just do the copies */ while (dmax > 0) { *dest = *src; /* Copy the data into the destination */ /* Check for maximum copy from source */ if (smax == 0) { /* we have copied smax characters, add null terminator */ *dest = '\0'; } /* Check for end of copying */ if (*dest == '\0') { /* add nulls to complete smax, if fewer than smax characters * were in src when the NULL was encountered */ char *filler = dest; /* don't change dest, because we need to return it */ while (smax) { *filler = '\0'; dmax--; smax--; filler++; } #ifdef SAFECLIB_STR_NULL_SLACK /* null dmax slack to clear any data */ while (dmax) { *filler = '\0'; dmax--; filler++; } #endif *err = RCNEGATE(EOK); return dest; } dmax--; smax--; dest++; src++; } /* * Ran out of space in dest, and did not find the null terminator in src */ handle_error(orig_dest, orig_dmax, "stpncpy_s: not enough space for src", ESNOSPC); *err = RCNEGATE(ESNOSPC); return NULL; } EXPORT_SYMBOL(stpncpy_s); tboot-1.10.5/safestringlib/safeclib/strcasecmp_s.c0000644000000000000000000001046414210363175020320 0ustar 00000000000000/*------------------------------------------------------------------ * strcasecmp_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcasecmp_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcasecmp_s(const char *dest, rsize_t dmax, * const char *src, int *indicator) * * DESCRIPTION * Case insensitive string comparison by converting * to uppercase prior to the compare. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string dest * * src pointer to the string to be compared to dest * * indicator pointer to result indicator, greater than 0, * equal to 0 or less than 0, if the string pointed * to by dest is greater than, equal to or less * than the string pointed to by src respectively. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * indicator, when the return code is OK * >0 dest greater than src * 0 strings the same * <0 dest less than src * * EOK comparison complete * ESNULLP pointer was null * ESZEROL length was zero * ESLEMAX length exceeded max * * ALSO SEE * strcmp_s() * */ errno_t strcasecmp_s (const char *dest, rsize_t dmax, const char *src, int *indicator) { const unsigned char *udest = (const unsigned char *) dest; const unsigned char *usrc = (const unsigned char *) src; if (indicator == NULL) { invoke_safe_str_constraint_handler("strcasecmp_s: indicator is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *indicator = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strcasecmp_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strcasecmp_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcasecmp_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcasecmp_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } while (*udest && *usrc && dmax) { if (toupper(*udest) != toupper(*usrc)) { break; } udest++; usrc++; dmax--; } *indicator = (toupper(*udest) - toupper(*usrc)); return RCNEGATE(EOK); } EXPORT_SYMBOL(strcasecmp_s); tboot-1.10.5/safestringlib/safeclib/strcasestr_s.c0000644000000000000000000001172014210363175020345 0ustar 00000000000000/*------------------------------------------------------------------ * strcasestr_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcasestr_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcasestr_s(char *dest, rsize_t dmax, * const char *src, rsize_t slen, char **substring) * * DESCRIPTION * The strcasestr_s() function locates the first occurrence of * the substring pointed to by src which would be located in * the string pointed to by dest. The comparison is case * insensitive. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to be searched for the substring * * dmax restricted maximum length of dest string * * src pointer to the sub string * * slen maximum length of src string * * substring returned pointer to the substring * * OUTPUT PARAMETERS * substring pointer to the substring * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor slen shall equal zero. * Neither dmax nor slen shall be greater than RSIZE_MAX_STR. * * RETURN VALUE * EOK successful operation, substring found. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESNOTFND substring not found * * ALSO SEE * strstr_s(), strprefix_s() * */ errno_t strcasestr_s (char *dest, rsize_t dmax, const char *src, rsize_t slen, char **substring) { rsize_t len; rsize_t dlen; int i; if (substring == NULL) { invoke_safe_str_constraint_handler("strcasestr_s: substring is null", NULL, ESNULLP); return (ESNULLP); } *substring = NULL; if (dest == NULL) { invoke_safe_str_constraint_handler("strcasestr_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcasestr_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcasestr_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } if (src == NULL) { invoke_safe_str_constraint_handler("strcasestr_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (slen == 0) { invoke_safe_str_constraint_handler("strcasestr_s: slen is 0", NULL, ESZEROL); return (ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcasestr_s: slen exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* * src points to a string with zero length, or * src equals dest, return dest */ if (*src == '\0' || dest == src) { *substring = dest; return (EOK); } while (*dest && dmax) { i = 0; len = slen; dlen = dmax; while (dest[i] && dlen) { /* not a match, not a substring */ if (toupper(dest[i]) != toupper(src[i])) { break; } /* move to the next char */ i++; len--; dlen--; if (src[i] == '\0' || !len) { *substring = dest; return (EOK); } } dest++; dmax--; } /* * substring was not found, return NULL */ *substring = NULL; return (ESNOTFND); } tboot-1.10.5/safestringlib/safeclib/strcat_s.c0000644000000000000000000001620114210363175017447 0ustar 00000000000000/*------------------------------------------------------------------ * strcat_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcat_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcat_s(char *dest, rsize_t dmax, const char *src) * * DESCRIPTION * The strcat_s function appends a copy of the string pointed * to by src (including the terminating null character) to the * end of the string pointed to by dest. The initial character * from src overwrites the null character at the end ofdest. * * All elements following the terminating null character (if * any) written by strcat_s in the array of dmax characters * pointed to by dest take unspeciï¬ed values when strcat_s * returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be extended by src * if dmax allows. The string is null terminated. * If the resulting concatenated string is less * than dmax, the remaining slack space is nulled. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be concatenaed * to string dest * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer * dmax shall not equal zero * dmax shall not be greater than RSIZE_MAX_STR * dmax shall be greater than strnlen_s(src,m). * Copying shall not takeplace between objects that overlap * If there is a runtime-constraint violation, then if dest is * not a null pointer and dmax is greater than zero and not * greater than RSIZE_MAX_STR, then strcat_s nulls dest. * * RETURN VALUE * EOK successful operation, all the characters from src * were appended to dest and the result in dest is * null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max * ESUNTERM dest not terminated * * ALSO SEE * strncat_s(), strcpy_s(), strncpy_s() * */ errno_t strcat_s (char *dest, rsize_t dmax, const char *src) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strcat_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strcat_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcat_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcat_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; /* Find the end of dest */ while (*dest != '\0') { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } dest++; dmax--; if (dmax == 0) { handle_error(orig_dest, orig_dmax, "strcat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } else { overlap_bumper = dest; /* Find the end of dest */ while (*dest != '\0') { /* * NOTE: no need to check for overlap here since src comes first * in memory and we're not incrementing src here. */ dest++; dmax--; if (dmax == 0) { handle_error(orig_dest, orig_dmax, "strcat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } /* * the entire src was not copied, so null the string */ handle_error(orig_dest, orig_dmax, "strcat_s: not enough " "space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(strcat_s); tboot-1.10.5/safestringlib/safeclib/strcmp_s.c0000644000000000000000000001007614210363175017463 0ustar 00000000000000/*------------------------------------------------------------------ * strcmp_s.c -- string compare * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcmp_s * * Synpsos * #include "safe_str_lib.h" * errno_t * strcmp_s(const char *dest, rsize_t dmax, * const char *src, int *indicator) * * DESCRIPTION * Compares string src to string dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string dest * * src pointer to the string to be compared to dest * * indicator pointer to result indicator, greater than, * equal to or less than 0, if the string pointed * to by dest is greater than, equal to or less * than the string pointed to by src respectively. * * OUTPUT PARAMETERS * indicator updated result indicator * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * indicator, when the return code is OK * >0 dest greater than src * 0 strings the same * <0 dest less than src * * EOK * ESNULLP pointer was null * ESZEROL length was zero * ESLEMAX length exceeded max * * ALSO SEE * strcasecmp_s() * */ errno_t strcmp_s (const char *dest, rsize_t dmax, const char *src, int *indicator) { if (indicator == NULL) { invoke_safe_str_constraint_handler("strcmp_s: indicator is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *indicator = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strcmp_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strcmp_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcmp_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcmp_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } while (*dest && *src && dmax) { if (*dest != *src) { break; } dest++; src++; dmax--; } *indicator = *dest - *src; return RCNEGATE(EOK); } EXPORT_SYMBOL(strcmp_s); tboot-1.10.5/safestringlib/safeclib/strcmpfld_s.c0000644000000000000000000001043414210363175020147 0ustar 00000000000000/*------------------------------------------------------------------ * strcmpfld_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcmpfld_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcmpfld_s(const char *dest, rsize_t dmax, * const char *src, int *indicator) * * DESCRIPTION * Compares the character array pointed to by src to the character array * pointed to by dest for dmax characters. The null terminator does not * stop the comparison. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to character array to compare against * * dmax restricted maximum length of dest. The length is * used for the comparison of src against dest. * * src pointer to the character array to be compared to dest * * indicator pointer to result indicator, greater than, equal * to or less than 0, if the character array pointed * to by dest is greater than, equal to or less * than the character array pointed to by src. * OUTPUT * indicator updated result indicator * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * indicator, when the return code is OK * >0 dest greater than src * 0 strings the same * <0 dest less than src * * EOK * ESNULLP pointer was null * ESZEROL length was zero * ESLEMAX length exceeded max * * ALSO SEE * strcpyfld_s(), strcpyfldin_s(), strcpyfldout_s() * */ errno_t strcmpfld_s (const char *dest, rsize_t dmax, const char *src, int *indicator) { if (indicator == NULL) { invoke_safe_str_constraint_handler("strcmpfld_s: indicator is null", NULL, ESNULLP); return (ESNULLP); } *indicator = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strcmpfld_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strcmpfld_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcmpfld_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcmpfld_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* compare for dmax charactrers, not the null! */ while (dmax) { if (*dest != *src) { break; } dest++; src++; dmax--; } *indicator = *dest - *src; return (EOK); } tboot-1.10.5/safestringlib/safeclib/strcpy_s.c0000644000000000000000000001361614210363175017502 0ustar 00000000000000/*------------------------------------------------------------------ * strcpy_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcpy_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcpy_s(char *dest, rsize_t dmax, const char *src) * * DESCRIPTION * The strcpy_s function copies the string pointed to by src * (including the terminating null character) into the array * pointed to by dest. All elements following the terminating * null character (if any) written by strcpy_s in the array * of dmax characters pointed to by dest are nulled when * strcpy_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the string that will be copied * to dest * * OUTPUT PARAMETERS * dest updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not be greater than RSIZE_MAX_STR. * dmax shall not equal zero. * dmax shall be greater than strnlen_s(src, dmax). * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and destmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpy_s nulls dest. * * RETURN VALUE * EOK successful operation, the characters in src were * copied into dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * ALSO SEE * strcat_s(), strncat_s(), strncpy_s() * */ errno_t strcpy_s (char *dest, rsize_t dmax, const char *src) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strcpy_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (src == NULL) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif invoke_safe_str_constraint_handler("strcpy_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dest == src) { return RCNEGATE(EOK); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } /* * the entire src must have been copied, if not reset dest * to null the string. */ handle_error(orig_dest, orig_dmax, "strcpy_s: not " "enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(strcpy_s); tboot-1.10.5/safestringlib/safeclib/strcpyfld_s.c0000644000000000000000000001355514210363175020172 0ustar 00000000000000/*------------------------------------------------------------------ * strcpyfld_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcpyfld_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcpyfld_s(char *dest, rsize_t dmax, const char *src, rsize_t slen) * * DESCRIPTION * The strcpyfld_s function copies slen characters from the character * array pointed to by src into the character array pointed to by dest. * The copy operation does not stop on the null character as the * function copies slen characters. * * EXTENSION TO * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to character array that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the character array that will be copied * to dest * * slen maximum length of src * * OUTPUT PARAMETERS * dest updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * slen shall not equal zero. * slen shall not exceed dmax * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and destmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpyfld_s nulls dest. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * * ALSO SEE * strcpyfldin_s(), strcpyfldout_s() * */ errno_t strcpyfld_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strcpyfld_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcpyfld_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcpyfld_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } if (src == NULL) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfld_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (slen == 0) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfld_s: slen is 0", NULL, ESZEROL); return (ESZEROL); } if (slen > dmax) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfld_s: src exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (slen > 0) { if (dest == overlap_bumper) { dmax = orig_dmax; dest = orig_dest; /* null string to eliminate partial copy */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler( "strcpyfld_s: overlapping objects", NULL, ESOVRLP); return (ESOVRLP); } *dest++ = *src++; slen--; dmax--; } } else { overlap_bumper = dest; while (slen > 0) { if (src == overlap_bumper) { dmax = orig_dmax; dest = orig_dest; /* null string to eliminate partial copy */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler( "strcpyfld_s: overlapping objects", NULL, ESOVRLP); return (ESOVRLP); } *dest++ = *src++; slen--; dmax--; } } /* null slack space in the field */ while (dmax) { *dest = '\0'; dmax--; dest++; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strcpyfldin_s.c0000644000000000000000000001403114210363175020507 0ustar 00000000000000/*------------------------------------------------------------------ * strcpyfldin_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcpyfldin_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcpyfldin_s(char *dest, rsize_t dmax, * const char *src, rsize_t slen) * * DESCRIPTION * The strcpyfldin_s function copies at most slen characters from the * null terminated string pointed to by src into the fixed character * array pointed to by dest. The copy operation stops on the null * character if encountered and then continues to fill the field * with nulls up to dmax characters. * * EXTENSION TO * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to character array that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the null terminated string that will be copied * into the character array pointed to by dest * * slen length of source * * OUTPUT PARAMETERS * dest updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * slen shall not equal zero. * slen shall not exceed dmax * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and dmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpyfldin_s nulls dest. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * * ALSO SEE * strcpyfld_s(), strcpyfldout_s(), * */ errno_t strcpyfldin_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strcpyfldin_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcpyfldin_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcpyfldin_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } if (src == NULL) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfldin_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (slen == 0) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfldin_s: slen is 0", NULL, ESZEROL); return (ESZEROL); } if (slen > dmax) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfldin_s: slen exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (dmax > 0 && *src) { if (dest == overlap_bumper) { dmax = orig_dmax; dest = orig_dest; /* null string to eliminate partial copy */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler( "strcpyfldin_s: overlapping objects", NULL, ESOVRLP); return (ESOVRLP); } dmax--; *dest++ = *src++; } } else { overlap_bumper = dest; while (dmax > 0 && *src) { if (src == overlap_bumper) { dmax = orig_dmax; dest = orig_dest; /* null string to eliminate partial copy */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler( "strcpyfldin_s: overlapping objects", NULL, ESOVRLP); return (ESOVRLP); } dmax--; *dest++ = *src++; } } /* * finish filling in the field with nulls if there is slack space */ while (dmax) { *dest = '\0'; dmax--; dest++; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strcpyfldout_s.c0000644000000000000000000001407714210363175020722 0ustar 00000000000000/*------------------------------------------------------------------ * strcpyfldout_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcpyfldout_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcpyfldout_s(char *dest, rsize_t dmax, * const char *src, rsize_t slen) * * DESCRIPTION * The strcpyfldout_s function copies slen characters from * the character array pointed to by src into the string * pointed to by dest. A null is included to properly * termiante the dest string. The copy operation does not * stop on the null character as function copies dmax * characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the character array to be copied * to dest and null terminated. * * slen the maximum number of characters that will be * copied from the src field into the dest string. * * OUTPUT PARAMETERS * dest updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * slen shall not equal zero. * slen shall not exceed dmax * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and dmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpyfldout_s nulls dest. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * * ALSO SEE * strcpyfld_s(), strcpyfldin_s() * */ errno_t strcpyfldout_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strcpyfldout_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcpyfldout_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcpyfldout_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } if (src == NULL) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfldout_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (slen == 0) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfldout_s: slen is 0", NULL, ESZEROL); return (ESZEROL); } if (slen > dmax) { /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler("strcpyfldout_s: slen exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (dmax > 1 && slen) { if (dest == overlap_bumper) { dmax = orig_dmax; dest = orig_dest; /* null string to eliminate partial copy */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler( "strcpyfldout_s: overlapping objects", NULL, ESOVRLP); return (ESOVRLP); } dmax--; slen--; *dest++ = *src++; } } else { overlap_bumper = dest; while (dmax > 1 && slen) { if (src == overlap_bumper) { dmax = orig_dmax; dest = orig_dest; /* null string to eliminate partial copy */ while (dmax) { *dest = '\0'; dmax--; dest++; } invoke_safe_str_constraint_handler( "strcpyfldout_s: overlapping objects", NULL, ESOVRLP); return (ESOVRLP); } dmax--; slen--; *dest++ = *src++; } } /* null slack space */ while (dmax) { *dest = '\0'; dmax--; dest++; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strcspn_s.c0000644000000000000000000001136714210363175017653 0ustar 00000000000000/*------------------------------------------------------------------ * strcspn_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strcspn_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcspn_s(const char *dest, rsize_t dmax, * const char *src, rsize_t slen, rsize_t *count) * * DESCRIPTION * This function computes the prefix length of the string pointed * to by dest which consists entirely of characters that are * excluded from the string pointed to by src. The scanning stops * at the first null in dest or after dmax characters. The * exclusion string is checked to the null or after slen * characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to determine the prefix * * dmax restricted maximum length of string dest * * src pointer to exclusion string * * slen restricted maximum length of string src * * count pointer to a count variable that will be updated * with the dest substring length * * OUTPUT PARAMETERS * count updated count variable * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * count shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * EOK count * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strspn_s(), strpbrk_s(), strstr_s() * */ errno_t strcspn_s (const char *dest, rsize_t dmax, const char *src, rsize_t slen, rsize_t *count) { const char *scan2; rsize_t smax; if (count== NULL) { invoke_safe_str_constraint_handler("strcspn_s: count is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *count = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strcspn_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strcspn_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strcspn_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcspn_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (slen == 0 ) { invoke_safe_str_constraint_handler("strcspn_s: slen is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcspn_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } while (*dest && dmax) { /* * Scanning for exclusions, so if there is a match, * we're done! */ smax = slen; scan2 = src; while (*scan2 && smax) { if (*dest == *scan2) { return RCNEGATE(EOK); } scan2++; smax--; } (*count)++; dest++; dmax--; } return RCNEGATE(EOK); } EXPORT_SYMBOL(strcspn_s); tboot-1.10.5/safestringlib/safeclib/strfirstchar_s.c0000644000000000000000000000727714210363175020702 0ustar 00000000000000/*------------------------------------------------------------------ * strfirstchar_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strfirstchar_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strfirstchar_s(char *dest, rsize_t dmax, char c, char **first) * * DESCRIPTION * This function returns a pointer to the first occurrence * of character c in dest. The scanning stops at the first null * or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string * * c character to locate * * first returned pointer to first occurrence of c * * OUTPUT PARAMETERS * first updated pointer to first occurrence of c * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * first shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * pointer to first occurence of c, NULL if not found * * EOK pointer to first occurrence is returned * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strlastchar_s(), strfirstdiff_s(), strfirstsame_s(), * strlastdiff_s(), strlastsame_s(), * */ errno_t strfirstchar_s (char *dest, rsize_t dmax, char c, char **first) { if (first == NULL) { invoke_safe_str_constraint_handler("strfirstchar_s: index is null", NULL, ESNULLP); return (ESNULLP); } *first = NULL; if (dest == NULL) { invoke_safe_str_constraint_handler("strfirstchar_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strfirstchar_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strfirstchar_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } while (*dest && dmax) { if (*dest == c) { *first = dest; return (EOK); } dest++; dmax--; } return (ESNOTFND); } tboot-1.10.5/safestringlib/safeclib/strfirstdiff_s.c0000644000000000000000000001021514210363175020657 0ustar 00000000000000/*------------------------------------------------------------------ * strfirstdiff_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strfirstdiff_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strfirstdiff_s(const char *dest, rsize_t dmax, * const char *src, rsize_t *index) * * DESCRIPTION * Returns the index of the first character that is different * between dest and src. Index is valid only for OK. * The scanning stops at the first null in dest or src, or * after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string dest * * src pointer to the string to be compared to dest * * index pointer to returned index to first difference * * OUTPUT PARAMETERS * index returned index to first difference * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * index to first difference, when the return code is OK * * EOK index to first diff is returned * ESNODIFF no difference * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strfirstchar_s(), strfirstsame_s(), strlastchar_s(), * strlastdiff_s(), strlastsame_s() * */ errno_t strfirstdiff_s (const char *dest, rsize_t dmax, const char *src, rsize_t *index) { const char *rp; if (index == NULL) { invoke_safe_str_constraint_handler("strfirstdiff_s: index is null", NULL, ESNULLP); return (ESNULLP); } *index = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strfirstdiff_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strfirstdiff_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strfirstdiff_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strfirstdiff_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold reference point */ rp = dest; while (*dest && *src && dmax) { if (*dest != *src) { *index = dest - rp; return (EOK); } dmax--; dest++; src++; } return (ESNODIFF); } tboot-1.10.5/safestringlib/safeclib/strfirstsame_s.c0000644000000000000000000001016614210363175020701 0ustar 00000000000000/*------------------------------------------------------------------ * strfirstsame_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strfirstsame_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strfirstsame_s(const char *dest, rsize_t dmax, * const char *src, rsize_t *index) * * DESCRIPTION * Returns the index of the first character that is the * same between dest and src. The scanning stops at the * fisrt null in dest or src, or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string dest * * src pointer to the string to be compared to dest * * index pointer to returned index * * OUTPUT PARAMETERS * index updated index * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * index to first same char, when the return code is OK * * EOK index to first same char is returned * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESNOTFND not found * * ALSO SEE * strfirstchar_s(), strfirstdiff_s(), strlastchar_s(), * strlastdiff_s(), strlastsame_s() * */ errno_t strfirstsame_s (const char *dest, rsize_t dmax, const char *src, rsize_t *index) { const char *rp = 0; if (index == NULL) { invoke_safe_str_constraint_handler("strfirstsame_s: index is null", NULL, ESNULLP); return (ESNULLP); } *index = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strfirstsame_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strfirstsame_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strfirstsame_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strfirstsame_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold reference point */ rp = dest; /* * find the offset */ while (*dest && *src && dmax) { if (*dest == *src) { *index = (uint32_t)(dest - rp); return (EOK); } dest++; src++; dmax--; } return (ESNOTFND); } tboot-1.10.5/safestringlib/safeclib/strisalphanumeric_s.c0000644000000000000000000000667414210363175021721 0ustar 00000000000000/*------------------------------------------------------------------ * strisalphanumeric_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strisalphanumeric_s * * SYNOPSIS * #include "safe_dest_lib.h" * bool * strisalphanumeric_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks if the entire string contains * alphanumerics. The scanning stops at the first null * or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * Runtime-condestaints * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true dest is alphanumeric * false dest is not alphanumeric or an error occurred * * ALSO SEE * strisascii_s(), strisdigit_s(), strishex_s(), strislowercase_s(), * strismixedcase_s(), strisuppercase_s() * */ bool strisalphanumeric_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strisalphanumeric_s: " "dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strisalphanumeric_s: " "dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strisalphanumeric_s: " "dmax exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } while (*dest && dmax) { if (( (*dest >= '0') && (*dest <= '9') ) || ( (*dest >= 'a') && (*dest <= 'z') ) || ( (*dest >= 'A') && (*dest <= 'Z') )) { dest++; dmax--; } else { return (false); } } return (true); } tboot-1.10.5/safestringlib/safeclib/strisascii_s.c0000644000000000000000000000624314210363175020331 0ustar 00000000000000/*------------------------------------------------------------------ * strisascii_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /* *- * NAME * strisascii_s * * SYNOPSIS * #include "safe_str_lib.h" * bool * strisascii_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks if the entire string contains ascii * characters. The scanning stops at the first null or * at most dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true, string is ascii * false, string contains one or more non-ascii or an error occurred * * ALSO SEE * strisalphanumeric_s(), strisdigit_s(), strishex_s(), * strislowercase_s(), strismixedcase_s(), strisuppercase_s() *- */ bool strisascii_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strisascii_s: dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strisascii_s: dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strisascii_s: dmax " "exceeds max", NULL, ESLEMAX); return (false); } while (*dest && dmax) { if ((unsigned char)*dest > 127) { return (false); } dest++; dmax--; } return (true); } tboot-1.10.5/safestringlib/safeclib/strisdigit_s.c0000644000000000000000000000624314210363175020341 0ustar 00000000000000/*------------------------------------------------------------------ * strisdigit_s * * November 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strisdigit_s * * SYNOPSIS * #include "safe_str_lib.h" * bool * strisdigit_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks that the entire string contains digits. * The scanning stops at the first null or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true string is digit * false string is not digit or an error occurred * * ALSO SEE * strisalphanumeric_s(), strisascii_s(), strishex_s(), * strislowercase_s(), strismixedcase_s(), strisuppercase_s() * */ bool strisdigit_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strisdigit_s: dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strisdigit_s: dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strisdigit_s: dmax exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } while (*dest) { if ((*dest < '0') || (*dest > '9')) { return (false); } dest++; dmax--; } return (true); } tboot-1.10.5/safestringlib/safeclib/strishex_s.c0000644000000000000000000000646114210363175020027 0ustar 00000000000000/*------------------------------------------------------------------ * strishex_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strishex_s * * SYNOPSIS * #include "safe_str_lib.h" * bool * strishex_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks that the entire string contains * hex characters. The scanning stops at the first null * or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true string is hex * false string is not hex or an error occurred * * ALSO SEE * strisalphanumeric_s(), strisascii_s(), strisdigit_s(), * strislowercase_s(), strismixedcase_s(), * strisuppercase_s() * */ bool strishex_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strishex_s: dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strishex_s: dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strishex_s: dmax exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } while (*dest && dmax) { if (((*dest >= '0') && (*dest <= '9')) || ((*dest >= 'a') && (*dest <= 'f')) || ((*dest >= 'A') && (*dest <= 'F'))) { dest++; dmax--; } else { return (false); } } return (true); } tboot-1.10.5/safestringlib/safeclib/strislowercase_s.c0000644000000000000000000000646214210363175021230 0ustar 00000000000000/*------------------------------------------------------------------ * strislowercase_s.c * * February 2005, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strislowercase_s * * SYNOPSIS * #include "safe_str_lib.h" * bool * strislowercase_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks if entire string is lowercase. * The scanning stops at the first null or after dmax * characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dest shal be null terminated. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true string is lowercase * false string is not lowercase or an error occurred * * ALSO SEE * strisalphanumeric_s(), strisascii_s(), strisdigit_s(), * strishex_s(), strismixedcase_s(), * strisuppercase_s() * */ bool strislowercase_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strislowercase_s: " "dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strislowercase_s: " "dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strislowercase_s: " "dmax exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } while (*dest && dmax) { if ((*dest < 'a') || (*dest > 'z')) { return (false); } dest++; dmax--; } return (true); } tboot-1.10.5/safestringlib/safeclib/strismixedcase_s.c0000644000000000000000000000653014210363175021202 0ustar 00000000000000/*------------------------------------------------------------------ * strismixedcase_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strismixedcase_s * * SYNOPSIS * #include "safe_str_lib.h" * bool * strismixedcase_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks that the entire string is mixed * case. The scanning stops at the first null or after * dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true string is mixed case * false string is not mixed case or error * * ALSO SEE * strisalphanumeric_s(), strisascii_s(), strisdigit_s(), * strishex_s(), strislowercase_s(), * strisuppercase_s() * */ bool strismixedcase_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strismixedcase_s: " "dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strismixedcase_s: " "dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strismixedcase_s: " "dmax exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } while (*dest) { if (((*dest >= 'a') && (*dest <= 'z')) || ((*dest >= 'A') && (*dest <= 'Z'))) { dest++; dmax--; } else { return (false); } } return (true); } tboot-1.10.5/safestringlib/safeclib/strispassword_s.c0000644000000000000000000001164514210363175021105 0ustar 00000000000000/*------------------------------------------------------------------ * strispassword_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strispassword_s * * SYNOPSIS * #include "strlib.h" * bool * strispassword_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function validates the make-up of a password string. * -SAFE_STR_PASSWORD_MIN_LENGTH character minimum * -SAFE_STR_PASSWORD_MAX_LENGTH character maximum * -at least SAFE_STR_MIN_LOWERCASE lower case characters * -at least SAFE_STR_MIN_UPPERCASE upper case characters * -at least SAFE_STR_MIN_NUMBERS number * -at least SAFE_STR_MIN_SPECIALS special * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax length of password string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * length > SAFE_STR_PASSWORD_MIN_LENGTH * length < SAFE_STR_PASSWORD_MAX_LENGTH * dest shall not be unterminated * * RETURN VALUE * true, string has valid password makeup * false, string does not meet requirements or an error occurred * * ALSO SEE * strzero_s() * */ bool strispassword_s (const char *dest, rsize_t dmax) { uint32_t cnt_all; uint32_t cnt_lowercase; uint32_t cnt_uppercase; uint32_t cnt_numbers; uint32_t cnt_specials; if (!dest) { invoke_safe_str_constraint_handler("strispassword_s: " "dest is null", NULL, ESNULLP); return (false); } if (dmax < SAFE_STR_PASSWORD_MIN_LENGTH) { invoke_safe_str_constraint_handler("strispassword_s: " "dest is too short", NULL, ESLEMIN); return (false); } if (dmax > SAFE_STR_PASSWORD_MAX_LENGTH) { invoke_safe_str_constraint_handler("strispassword_s: " "dest exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } cnt_all = cnt_lowercase = cnt_uppercase = 0; cnt_numbers = cnt_specials = 0; while (*dest) { if (dmax == 0) { invoke_safe_str_constraint_handler( "strispassword_s: dest is unterminated", NULL, ESUNTERM); return (false); } dmax--; cnt_all++; if ((*dest >= '0') && (*dest <= '9')) { cnt_numbers++; } else if ((*dest >= 'a') && (*dest <= 'z')) { cnt_lowercase++; } else if ((*dest >= 'A') && (*dest <= 'Z')) { cnt_uppercase++; /* allow all specials */ } else if ((*dest >= 33) && (*dest <= 47)) { cnt_specials++; } else if ((*dest >= 58) && (*dest <= 64)) { cnt_specials++; } else if ((*dest >= 91) && (*dest <= 94)) { cnt_specials++; } else if ((*dest >= 95) && (*dest <= 96)) { cnt_specials++; } else if ((*dest >= 123) && (*dest <= 126)) { cnt_specials++; } else { /* illegal char in password string */ return (false); } dest++; } if (cnt_all < SAFE_STR_PASSWORD_MAX_LENGTH && cnt_numbers >= SAFE_STR_MIN_NUMBERS && cnt_lowercase >= SAFE_STR_MIN_LOWERCASE && cnt_uppercase >= SAFE_STR_MIN_UPPERCASE && cnt_specials >= SAFE_STR_MIN_SPECIALS ) { return (true); } else { return (false); } } tboot-1.10.5/safestringlib/safeclib/strisuppercase_s.c0000644000000000000000000000640014210363175021223 0ustar 00000000000000/*------------------------------------------------------------------ * strisuppercase_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strisuppercase_s * * SYNOPSIS * #include "safe_str_lib.h" * bool * strisuppercase_s(const char *dest, rsize_t dmax) * * DESCRIPTION * This function checks if entire string is uppercase * The scanning stops at the first null or after dmax * characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * true string is uppercase * false string is not uppercase or an error occurred * * ALSO SEE * strisalphanumeric_s(), strisascii_s(), strisdigit_s(), * strishex_s(), strislowercase_s(), strismixedcase_s(), * */ bool strisuppercase_s (const char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strisuppercase_s: " "dest is null", NULL, ESNULLP); return (false); } if (dmax == 0) { invoke_safe_str_constraint_handler("strisuppercase_s: " "dmax is 0", NULL, ESZEROL); return (false); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strisuppercase_s: " "dmax exceeds max", NULL, ESLEMAX); return (false); } if (*dest == '\0') { return (false); } while (*dest) { if ((*dest < 'A') || (*dest > 'Z')) { return (false); } dest++; dmax--; } return (true); } tboot-1.10.5/safestringlib/safeclib/strlastchar_s.c0000644000000000000000000000733614210363175020512 0ustar 00000000000000/*------------------------------------------------------------------ * strlastchar_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strlastchar_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strlastchar_s(char *dest, rsize_t dmax, char c, char **last) * * DESCRIPTION * Returns a pointer to the last occurrence of character c in * dest. The scanning stops at the first null or after dmax * characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax restricted maximum length of string * * c character to locate * * last returned pointer to last occurrence * * OUTPUT PARAMETERS * last updated pointer to last occurrence * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * last shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * pointer to the last occurrence, when the return code is OK * * EOK pointer to the last occurence is returned * ESNOTFND c not found in dest * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strfirstchar_s(), strfirstdiff_s(), strfirstsame_s(), * strlastdiff_s(), strlastsame_s() * */ errno_t strlastchar_s(char *dest, rsize_t dmax, char c, char **last) { if (last == NULL) { invoke_safe_str_constraint_handler("strlastchar_s: last is null", NULL, ESNULLP); return (ESNULLP); } *last = NULL; if (dest == NULL) { invoke_safe_str_constraint_handler("strlastchar_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strlastchar_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strlastchar_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } while (*dest && dmax) { if (*dest == c) { *last = dest; } dest++; dmax--; } if (*last == NULL) { return (ESNOTFND); } else { return (EOK); } } tboot-1.10.5/safestringlib/safeclib/strlastdiff_s.c0000644000000000000000000001042714210363175020500 0ustar 00000000000000/*------------------------------------------------------------------ * strlastdiff_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strlastdiff_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strlastdiff_s(const char *dest, rsize_t dmax, * const char *src, rsize_t *index) * * DESCRIPTION * Returns the index of the last character that is different * between dest and src. Index is valid only for EOK. * The scanning stops at the first null in dest or src, or * after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string dest * * src pointer to the string to be compared to dest * * index pointer to returned index of last difference * * OUTPUT PARAMETERS * index updated index of last difference * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * index to last difference, when the return code is OK * * EOK index to last diff is returned * ESNODIFF no difference * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strfirstchar_s(), strfirstdiff_s(), strfirstsame_s(), * strlastchar_s(), strlastsame_s() * */ errno_t strlastdiff_s(const char *dest, rsize_t dmax, const char *src, rsize_t *index) { const char *rp; bool there_is_a_diff = false; if (index == NULL) { invoke_safe_str_constraint_handler("strlastdiff_s: index is null", NULL, ESNULLP); return (ESNULLP); } *index = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strlastdiff_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strlastdiff_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strlastdiff_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strlastdiff_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold reference point */ rp = dest; /* * find the last diff */ while (*dest && *src && dmax) { if (*dest != *src) { there_is_a_diff = true; *index = dest - rp; } dest++; src++; dmax--; } if (there_is_a_diff) { return (EOK); } else { return (ESNODIFF); } } tboot-1.10.5/safestringlib/safeclib/strlastsame_s.c0000644000000000000000000001041114210363175020506 0ustar 00000000000000/*------------------------------------------------------------------ * strlastsame_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strlastsame_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strlastsame_s(const char *dest, rsize_t dmax, * const char *src, rsize_t *index) * * DESCRIPTION * Returns the index of the last character that is the * same between dest and src. The scanning stops at the * first nul in dest or src, or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of string dest * * src pointer to the string to be compared to dest * * index pointer to returned index * * OUTPUT PARAMETERS * index updated index * * RUNTIME CONSTRAINTS * Neither dest nor src shall not be a null pointer. * indicator shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * index to last same char, when the return code is OK * * EOK index to last same char is returned * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESNOTFND not found * ESUNTERM string unterminated * * ALSO SEE * strfirstchar_s(), strfirstdiff_s(), strfirstsame_s(), * strlastchar_s(), strlastdiff_s() * */ errno_t strlastsame_s (const char *dest, rsize_t dmax, const char *src, rsize_t *index) { const char *rp; bool similarity; if (index == NULL) { invoke_safe_str_constraint_handler("strlastsame_s: index is null", NULL, ESNULLP); return (ESNULLP); } *index = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strlastsame_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strlastsame_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strlastsame_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strlastsame_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* hold reference point */ rp = dest; /* * find the last offset */ similarity = false; while (*dest && *src && dmax) { if (*dest == *src) { similarity = true; *index = (uint32_t)(dest - rp); } dest++; src++; dmax--; } if (similarity) { return (EOK); } else { return (ESNOTFND); } } tboot-1.10.5/safestringlib/safeclib/strljustify_s.c0000644000000000000000000001046114210363175020553 0ustar 00000000000000/*------------------------------------------------------------------ * strljustify_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reseved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strljustify_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strljustify_s(char *dest, rsize_t dmax) * * DESCRIPTION * Removes beginning whitespace from the string pointed to by * dest by shifting the text left over writting the beginning * whitespace, left justifying the text. The left justified * text is null terminated. * * The text is shifted so the original pointer can continue * to be used. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to left justify * * dmax restricted maximum length of string * * OUTPUT PARAMETERS * dest left justified * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * dest shall be null terminated * * RETURN VALUE * EOK * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESUNTERM dest was not null terminated * * ALSO SEE * strremovews_s(), * */ errno_t strljustify_s (char *dest, rsize_t dmax) { char *orig_dest; rsize_t orig_dmax; if (dest == NULL) { invoke_safe_str_constraint_handler("strljustify_s_s: " "dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strljustify_s_s: " "dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strljustify_s_s: " "dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* * corner case, a dmax of one allows only for a null */ if (*dest == '\0' || dmax <= RSIZE_MIN_STR) { *dest = '\0'; return (EOK); } orig_dmax = dmax; orig_dest = dest; /* * scan the string to be sure it is properly terminated */ while (*dest) { if (dmax == 0) { while (orig_dmax) { *orig_dest++ = '\0'; orig_dmax--; } invoke_safe_str_constraint_handler( "strljustify_s: dest is unterminated", NULL, ESUNTERM); return (ESUNTERM); } dmax--; dest++; } /* * find first non-white space char */ dest = orig_dest; while ((*dest == ' ') || (*dest == '\t')) { dest++; } /* * shift text, removing spaces, to left justify */ if (orig_dest != dest && *dest) { while (*dest) { *orig_dest++ = *dest; *dest++ = ' '; } *orig_dest = '\0'; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strncat_s.c0000644000000000000000000002005214210363175017624 0ustar 00000000000000/*------------------------------------------------------------------ * strncat_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strncat_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strncat_s(char *dest, rsize_t dmax, const char *src, rsize_t slen) * * DESCRIPTION * The strncat_s function appends a copy of the string pointed * to by src (including the terminating null character) to the * end of the string pointed to by dest. The initial character * from src overwrites the null character at the end of dest. * * All elements following the terminating null character (if * any) written by strncat_s in the array of dmax characters * pointed to by dest take unspeciï¬ed values when strncat_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be extended by src * if dmax allows. The string is null terminated. * If the resulting concatenated string is less * than dmax, the remaining slack space is nulled. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be concatenaed * to string dest * * slen maximum characters to append * * OUTPUT PARAMETERS * dest updated string * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer * dmax shall not equal zero * dmax shall not be greater than RSIZE_STR_MAX * dmax shall be greater than strnlen_s(src,m). * Copying shall not takeplace between objects that overlap * If there is a runtime-constraint violation, then if dest is * not a null pointer and dmax is greater than zero and not * greater thanRSIZE_MAX, then strncat_s sets dest[0] to the * null character. * * RETURN VALUE * EOK successful operation, all the characters from src * were appended to dest and the result in dest is * null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESUNTERM dest not terminated * * */ errno_t strncat_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strncat_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strncat_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strncat_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (dmax == 0) { invoke_safe_str_constraint_handler("strncat_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strncat_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; /* Find the end of dest */ while (*dest != '\0') { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } dest++; dmax--; if (dmax == 0) { handle_error(orig_dest, orig_dmax, "strncat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } /* * Copying truncated before the source null is encountered */ if (slen == 0) { #ifdef SAFECLIB_STR_NULL_SLACK /* null remaining string */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } else { overlap_bumper = dest; /* Find the end of dest */ while (*dest != '\0') { /* * NOTE: no need to check for overlap here since src comes first * in memory and we're not incrementing src here. */ dest++; dmax--; if (dmax == 0) { handle_error(orig_dest, orig_dmax, "strncat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } /* * Copying truncated */ if (slen == 0) { #ifdef SAFECLIB_STR_NULL_SLACK /* null remaining string */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } /* * the entire src was not copied, so the string will be nulled. */ handle_error(orig_dest, orig_dmax, "strncat_s: not enough " "space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(strncat_s); tboot-1.10.5/safestringlib/safeclib/strncpy_s.c0000644000000000000000000001642314210363175017657 0ustar 00000000000000/*------------------------------------------------------------------ * strncpy_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /* * NAME * strncpy_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t slen) * * DESCRIPTION * The strncpy_s function copies not more than slen successive characters * (characters that follow a null character are not copied) from the * array pointed to by src to the array pointed to by dest. If no null * character was copied from src, then dest[n] is set to a null character. * * All elements following the terminating null character (if any) * written by strncpy_s in the array of dmax characters pointed to * by dest take on the null value when strncpy_s returns. * * Specicified in: * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * The resulting string is null terminated. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be copied * to string dest * * slen the maximum number of characters to copy from src * * OUTPUT PARAMETERS * dest updated with src string * * RUNTIME CONSTRAINTS * Neither dmax nor slen shall be equal to zero. * Neither dmax nor slen shall be equal zero. * Neither dmax nor slen shall be greater than RSIZE_MAX_STR. * If slen is either greater than or equal to dmax, then dmax * should be more than strnlen_s(src,dmax) * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and dmax greater than RSIZE_MAX_STR, * then strncpy_s nulls dest. * * RETURN VALUE * EOK successful operation, the characters in src were copied * to dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * ALSO SEE * strcat_s(), strncat_s(), strcpy_s() *- */ errno_t strncpy_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strncpy_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strncpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strncpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (src == NULL) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "src is null", ESNULLP); return RCNEGATE(ESNULLP); } if (slen == 0) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "slen is zero", ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "slen exceeds max", ESLEMAX); return RCNEGATE(ESLEMAX); } if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } if (slen == 0) { /* * Copying truncated to slen chars. Note that the TR says to * copy slen chars plus the null char. We null the slack. */ #ifdef SAFECLIB_STR_NULL_SLACK while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } if (slen == 0) { /* * Copying truncated to slen chars. Note that the TR says to * copy slen chars plus the null char. We null the slack. */ #ifdef SAFECLIB_STR_NULL_SLACK while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } /* * the entire src was not copied, so zero the string */ handle_error(orig_dest, orig_dmax, "strncpy_s: not enough " "space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(strncpy_s); tboot-1.10.5/safestringlib/safeclib/strnlen_s.c0000644000000000000000000000633514210363175017643 0ustar 00000000000000/*------------------------------------------------------------------ * strnlen_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strnlen_s * * SYNOPSIS * #include "safe_str_lib.h" * rsize_t * strnlen_s(const char *dest, rsize_t dmax) * * DESCRIPTION * The strnlen_s function computes the length of the string pointed * to by dest. * * SPECIFIED IN * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax restricted maximum length. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer * dmax shall not be greater than RSIZE_MAX_STR * dmax shall not equal zero * * RETURN VALUE * The function returns the string length, excluding the terminating * null character. If dest is NULL, then strnlen_s returns 0. * * Otherwise, the strnlen_s function returns the number of characters * that precede the terminating null character. If there is no null * character in the first dmax characters of dest then strnlen_s returns * dmax. At most the first dmax characters of dest are accessed * by strnlen_s. * * ALSO SEE * strnterminate_s() * */ rsize_t strnlen_s (const char *dest, rsize_t dmax) { rsize_t count; if (dest == NULL) { return RCNEGATE(0); } if (dmax == 0) { invoke_safe_str_constraint_handler("strnlen_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(0); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strnlen_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(0); } count = 0; while (*dest && dmax) { count++; dmax--; dest++; } return RCNEGATE(count); } EXPORT_SYMBOL(strnlen_s); tboot-1.10.5/safestringlib/safeclib/strnterminate_s.c0000644000000000000000000000613314210363175021051 0ustar 00000000000000/*------------------------------------------------------------------ * strnterminate_s.c * * February 2011, Bo Berry * * Copyright (c) 2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strnterminate_s * * SYNOPSIS * #include "safe_str_lib.h" * rsize_t * strnterminate_s(char *dest, rsize_t dmax) * * DESCRIPTION * The strnterminate_s function will terminate the string if a * null is not encountered before dmax characters. * * EXTENSION TO * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest - pointer to string * * dmax - restricted maximum length * * OUTPUT PARAMETERS * dest - dest is terminated if needed * * RUNTIME CONSTRAINTS * dest shall not be a null pointer * dmax shall not be greater than RSIZE_MAX_STR * dmax shall not equal zero * * RETURN VALUE * The function returns a terminated string. If a null is not * encountered prior to dmax characters, the dmax character is * set to null terminating the string. The string length is * also returned. * * ALSO SEE * strnlen_s() * */ rsize_t strnterminate_s (char *dest, rsize_t dmax) { rsize_t count; if (dest == NULL) { return (0); } if (dmax == 0) { invoke_safe_str_constraint_handler("strnterminate_s: dmax is 0", NULL, ESZEROL); return (0); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strnterminate_s: dmax exceeds max", NULL, ESLEMAX); return (0); } count = 0; while (dmax > 1) { if (*dest) { count++; dmax--; dest++; } else { break; } } *dest = '\0'; return (count); } tboot-1.10.5/safestringlib/safeclib/strpbrk_s.c0000644000000000000000000001101614210363175017635 0ustar 00000000000000/*------------------------------------------------------------------ * strpbrk_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strpbrk_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strpbrk_s(char *dest, rsize_t dmax, * char *src, rsize_t slen, char **first) * * DESCRIPTION * Returns a pointer, first, to the first ocurrence of any character * in src which is contained in dest. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax restricted maximum length of string dest * * src pointer to string * * slen restricted length of string src * * first returned pointer to first occurence * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * first shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * pointer to the first ocurrence of any character * contained in src * * EOK count * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strfirstchar_s(), strlastchar_s(), strfirstdiff_s(), * strfirstsame_s(), strlastdiff_s(), strlastsame_s() * */ errno_t strpbrk_s (char *dest, rsize_t dmax, char *src, rsize_t slen, char **first) { char *ps; rsize_t len; if (first == NULL) { invoke_safe_str_constraint_handler("strpbrk_s: count is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *first = NULL; if (dest == NULL) { invoke_safe_str_constraint_handler("strpbrk_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strpbrk_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strpbrk_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strpbrk_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (slen == 0 ) { invoke_safe_str_constraint_handler("strpbrk_s: slen is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strpbrk_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* * look for a matching char in the substring src */ while (*dest && dmax) { ps = src; len = slen; while (*ps) { /* check for a match with the substring */ if (*dest == *ps) { *first = dest; return RCNEGATE(EOK); } ps++; len--; } dest++; dmax--; } return RCNEGATE(ESNOTFND); } EXPORT_SYMBOL(strpbrk_s); tboot-1.10.5/safestringlib/safeclib/strprefix_s.c0000644000000000000000000000722614210363175020204 0ustar 00000000000000/*------------------------------------------------------------------ * strprefix_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strprefix_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strprefix_s(const char *dest, rsize_t dmax, const char *src) * * DESCRIPTION * Determines if the prefix pointed to by src is at the * beginning of string pointed to by dest. The prefix * must be a complete match in dest. Useful for command * or user input parsing. The scanning stops at the first * null in dest or src, or after dmax characters. * * EXTENSION TO * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to compare against * * dmax restricted maximum length of dest * * src pointer to the prefix * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * EOK successful operation, prefix present in dest * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESNOTFND prefix not found in dest * * ALSO SEE * strspn_s(), strcspn_s(), strpbrk_s(), strstr_s() * */ errno_t strprefix_s (const char *dest, rsize_t dmax, const char *src) { if (dest == NULL) { invoke_safe_str_constraint_handler("strprefix_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strprefix_s: src is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strprefix_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strprefix_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } if (*src == '\0') { return (ESNOTFND); } while (*src && dmax) { if (*dest != *src) { return (ESNOTFND); } dmax--; dest++; src++; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strremovews_s.c0000644000000000000000000001064314210363175020553 0ustar 00000000000000/*------------------------------------------------------------------ * strremovews_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights resevered. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strremovews_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strremovews_s(char *dest, rsize_t dmax) * * DESCRIPTION * Removes beginning and trailing whitespace from the string pointed to by * dest by shifting the text left over writting the beginning whitespace. * The shifted-trimmed text is null terminated. * * The text is shifted so the original pointer can continue to be used. This * is useful when the memory was malloc'ed and will need to be freed. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to remove whitespace * * dmax restricted maximum length of string * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * dest shall be null terminated * * RETURN VALUE * EOK * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESUNTERM dest was not null terminated * * SEE ALSO * strljustify_s(), * */ errno_t strremovews_s (char *dest, rsize_t dmax) { char *orig_dest; char *orig_end; rsize_t orig_dmax; if (dest == NULL) { invoke_safe_str_constraint_handler("strremovews_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strremovews_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strremovews_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* * corner case, a dmax of one requires a null */ if (*dest == '\0' || dmax <= RSIZE_MIN_STR) { *dest = '\0'; return (EOK); } orig_dest = dest; orig_dmax = dmax; /* * scan the string to be sure it is properly terminated */ while (*dest) { if (dmax == 0) { while (orig_dmax) { *orig_dest++ = '\0'; orig_dmax--; } invoke_safe_str_constraint_handler( "strremovews_s: dest is unterminated", NULL, ESUNTERM); return (ESUNTERM); } dmax--; dest++; } /* * find first non-white space char */ orig_end = dest-1; dest = orig_dest; while ((*dest == ' ') || (*dest == '\t')) { dest++; } /* * shift the text over the leading spaces */ if (orig_dest != dest && *dest) { while (*dest) { *orig_dest++ = *dest; *dest++ = ' '; } *dest = '\0'; } /* * strip trailing whitespace */ dest = orig_end; while ((*dest == ' ') || (*dest == '\t')) { *dest = '\0'; dest--; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strspn_s.c0000644000000000000000000001136414210363175017505 0ustar 00000000000000/*------------------------------------------------------------------ * strspn_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strspn_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strspn_s(const char *dest, rsize_t dmax, * const char *src, rsize_t slen, rsize_t *count) * * DESCRIPTION * This function computes the prefix length of the string * pointed to by dest which consists entirely of characters * that are included from the string pointed to by src. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to determine the prefix * * dmax restricted maximum length of string dest * * src pointer to exclusion string * * slen restricted maximum length of string src * * count pointer to a count variable that will be updated * with the dest substring length * * OUTPUT PARAMETERS * count updated count * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * count shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * EOK count * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strcspn_s(), strpbrk_s(), strstr_s(), strprefix_s() * */ errno_t strspn_s (const char *dest, rsize_t dmax, const char *src, rsize_t slen, rsize_t *count) { const char *scan2; rsize_t smax; bool match_found; if (count== NULL) { invoke_safe_str_constraint_handler("strspn_s: count is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *count = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strspn_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strspn_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strspn_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strspn_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (slen == 0 ) { invoke_safe_str_constraint_handler("strspn_s: slen is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strspn_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } while (*dest && dmax) { /* * Scan the entire src string for each dest character, counting * inclusions. */ match_found = false; smax = slen; scan2 = src; while (*scan2 && smax) { if (*dest == *scan2) { match_found = true; break; } scan2++; smax--; } if (match_found) { (*count)++; } else { break; } dest++; dmax--; } return RCNEGATE(EOK); } EXPORT_SYMBOL(strspn_s); tboot-1.10.5/safestringlib/safeclib/strstr_s.c0000644000000000000000000001177614210363175017524 0ustar 00000000000000/*------------------------------------------------------------------ * strstr_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strstr_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strstr_s(char *dest, rsize_t dmax, * const char *src, rsize_t slen, char **substring) * * DESCRIPTION * The strstr_s() function locates the first occurrence of the * substring pointed to by src which would be located in the * string pointed to by dest. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to be searched for the substring * * dmax restricted maximum length of dest string * * src pointer to the sub string * * slen the maximum number of characters to copy from src * * substring the returned substring pointer * * OUTPUT PARAMETERS * substring returned substring pointer * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Meither dmax nor slen shall be zero. * Neither dmax nor slen shall be greater than RSIZE_MAX_STR. * * RETURN VALUE * EOK successful operation, substring found. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESNOTFND substring not found * * ALSO SEE * strprefix_s(), strspn_s(), strcspn_s(), strpbrk_s() * */ errno_t strstr_s (char *dest, rsize_t dmax, const char *src, rsize_t slen, char **substring) { rsize_t len; rsize_t dlen; int i; if (substring == NULL) { invoke_safe_str_constraint_handler("strstr_s: substring is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *substring = NULL; if (dest == NULL) { invoke_safe_str_constraint_handler("strstr_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strstr_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strstr_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (src == NULL) { invoke_safe_str_constraint_handler("strstr_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (slen == 0) { invoke_safe_str_constraint_handler("strstr_s: slen is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strstr_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* * src points to a string with zero length, or * src equals dest, return dest */ if (*src == '\0' || dest == src) { *substring = dest; return RCNEGATE(EOK); } while (*dest && dmax) { i = 0; len = slen; dlen = dmax; while (src[i] && dlen) { /* not a match, not a substring */ if (dest[i] != src[i]) { break; } /* move to the next char */ i++; len--; dlen--; if (src[i] == '\0' || !len) { *substring = dest; return RCNEGATE(EOK); } } dest++; dmax--; } /* * substring was not found, return NULL */ *substring = NULL; return RCNEGATE(ESNOTFND); } EXPORT_SYMBOL(strstr_s); tboot-1.10.5/safestringlib/safeclib/strtok_s.c0000644000000000000000000002407114210363175017501 0ustar 00000000000000/*------------------------------------------------------------------ * strtok_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strtok_s * * SYNOPSIS * #include "safe_str_lib.h" * char * * strtok_s(char *dest, rsize_t *dmax, char *src, char **ptr) * * DESCRIPTION * A sequence of calls to the strtok_s function breaks the string * pointed to by dest into a sequence of tokens, each of which is * delimited by a character from the string pointed to by src. The * fourth argument points to a caller-provided char pointer into * which the strtok_s function stores information necessary for * it to continue scanning the same string. * * The first call in a sequence has a non-null first argument and * dmax points to an object whose value is the number of elements * in the character array pointed to by the first argument. The * first call stores an initial value in the object pointed to by * ptr and updates the value pointed to by dmax to reflect the * number of elements that remain in relation to ptr. Subsequent * calls in the sequence have a null first argument and the objects * pointed to by dmax and ptr are required to have the values * stored by the previous call in the sequence, which are then * updated. The separator string pointed to by src may be different * from call to call. * * The first call in the sequence searches the string pointed to * by dest for the first character that is not contained in the * current separator string pointed to by src. If no such character * is found, then there are no tokens in the string pointed to * by dest and the strtok_s function returns a null pointer. If * such a character is found, it is the start of the first token. * * The strtok_s function then searches from there for the first * character in dest that is contained in the current separator * string. If no such character is found, the current token * extends to the end of the string pointed to by dest, and * subsequent searches in the same string for a token return * a null pointer. If such a character is found, it is * overwritten by a null character, which terminates the * current token. * * In all cases, the strtok_s function stores sufï¬cient information * in the pointer pointed to by ptr so that subsequent calls, * with a null pointer for dest and the unmodiï¬ed pointer value * for ptr, shall start searching just past the element overwritten * by a null character (if any). * * SPECIFIED IN * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to tokenize * * dmax restricted maximum length of dest string * * src pointer to delimiter string (len < 255) * * ptr returned pointer to token * * OUTPUT PARAMETERS * dmax update length * * ptr update pointer to token * * RUNTIME CONSTRAINTS * src shall not be a null pointer. * ptr shall not be a null pointer. * dmax shall not be a null pointer. * *dmax shall not be 0. * * If dest is a null pointer, then *ptr shall not be a null pointer. * * dest must not be unterminated. * * The value of *dmax shall not be greater than RSIZE_MAX_STR. The * end of the token found shall occur within the first *dmax * characters of dest for the first call, and shall occur within * the first *dmax characters of where searching resumes on * subsequent calls. * * RETURN VALUE * The strtok_s function returns a pointer to the first character * of a token; or a null pointer if there is no token or there * is a runtime-constraint violation. * * EOK * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESUNTERM unterminated string * * EXAMPLES * [1] Sequencial strtok_s() calls to tokenize a string * * String to tokenize str1 = ",.:*one,two;three,;four*.*.five-six***" * len=38 * String of delimiters str2 = ",.;*" * * p2tok = strtok_s(str1, &len, str2, &p2str); * token -one- remaining -two;three,;four*.*.five-six***- len=30 * * p2tok = strtok_s(NULL, &len, str2, &p2str); * token -two- remaining -three,;four*.*.five-six***- len=26 * * p2tok = strtok_s(NULL, &len, str2, &p2str); * token -three- remaining -;four*.*.five-six***- len=20 * * p2tok = strtok_s(NULL, &len, str2, &p2str); * token -four- remaining -.*.five-six***- len=14 * * p2tok = strtok_s(NULL, &len, str2, &p2str); * token -five-six- remaining -**- len=2 * * p2tok = strtok_s(NULL, &len, str2, &p2str); * token -(null)- remaining -**- len=0 * * * [2] While loop with same entry data as [1] * * p2tok = str1; * while (p2tok && len) { * p2tok = strtok_s(NULL, &len, str2, &p2str); * printf(" token -- remaining -- len=0 \n", * p2tok, p2str, (int)len ); * } * *- */ char * strtok_s(char *dest, rsize_t *dmax, const char *src, char **ptr) { /* * CONFIGURE: The spec does not call out a maximum for the src * string, so one is defined here. */ #define STRTOK_DELIM_MAX_LEN ( 16 ) const char *pt; char *ptoken; rsize_t dlen; rsize_t slen; if (dmax == NULL) { invoke_safe_str_constraint_handler("strtok_s: dmax is NULL", NULL, ESNULLP); return (NULL); } if (*dmax == 0) { invoke_safe_str_constraint_handler("strtok_s: dmax is 0", NULL, ESZEROL); return (NULL); } if (*dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strtok_s: dmax exceeds max", NULL, ESLEMAX); return (NULL); } if (src == NULL) { invoke_safe_str_constraint_handler("strtok_s: src is null", NULL, ESNULLP); return (NULL); } if (ptr == NULL) { invoke_safe_str_constraint_handler("strtok_s: ptr is null", NULL, ESNULLP); return (NULL); } /* if the source was NULL, use the tokenizer context */ if (dest == NULL) { dest = *ptr; } /* * scan dest for a delimiter */ dlen = *dmax; ptoken = NULL; while (*dest != '\0' && !ptoken) { if (dlen == 0) { *ptr = NULL; invoke_safe_str_constraint_handler( "strtok_s: dest is unterminated", NULL, ESUNTERM); return (NULL); } /* * must scan the entire delimiter list * ISO should have included a delimiter string limit!! */ slen = STRTOK_DELIM_MAX_LEN; pt = src; while (*pt != '\0') { if (slen == 0) { *ptr = NULL; invoke_safe_str_constraint_handler( "strtok_s: src is unterminated", NULL, ESUNTERM); return (NULL); } slen--; if (*dest == *pt) { ptoken = NULL; break; } else { pt++; ptoken = dest; } } dest++; dlen--; } /* * if the beginning of a token was not found, then no * need to continue the scan. */ if (ptoken == NULL) { *dmax = dlen; return (ptoken); } /* * Now we need to locate the end of the token */ while (*dest != '\0') { if (dlen == 0) { *ptr = NULL; invoke_safe_str_constraint_handler( "strtok_s: dest is unterminated", NULL, ESUNTERM); return (NULL); } slen = STRTOK_DELIM_MAX_LEN; pt = src; while (*pt != '\0') { if (slen == 0) { *ptr = NULL; invoke_safe_str_constraint_handler( "strtok_s: src is unterminated", NULL, ESUNTERM); return (NULL); } slen--; if (*dest == *pt) { /* * found a delimiter, set to null * and return context ptr to next char */ *dest = '\0'; *ptr = (dest + 1); /* return pointer for next scan */ *dmax = dlen - 1; /* account for the nulled delimiter */ return (ptoken); } else { /* * simply scanning through the delimiter string */ pt++; } } dest++; dlen--; } *dmax = dlen; return (ptoken); } tboot-1.10.5/safestringlib/safeclib/strtolowercase_s.c0000644000000000000000000000637514210363175021242 0ustar 00000000000000/*------------------------------------------------------------------ * strtolowercase_s.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strtolowercase_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strlolowercase_s(char *dest, rsize_t dmax) * * DESCRIPTION * Scans the string converting uppercase characters to * lowercase, leaving all other characters unchanged. * The scanning stops at the first null or after dmax * characters. * * Extenstion to: * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * dest updated string * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strtouppercase_s() * */ errno_t strtolowercase_s (char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strtolowercase_s: " "dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strtolowercase_s: " "dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strtolowercase_s: " "dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } while (*dest && dmax) { if ( (*dest >= 'A') && (*dest <= 'Z')) { *dest = (char)(*dest + (char)32); } dest++; dmax--; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strtouppercase_s.c0000644000000000000000000000637114210363175021241 0ustar 00000000000000/*------------------------------------------------------------------ * safe_str_touppercase.c * * November 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strtouppercase_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strlouppercase_s(char *dest, rsize_t dmax) * * DESCRIPTION * Scans the string converting lowercase characters to * uppercase, leaving all other characters unchanged. * The scanning stops at the first null or after dmax * characters. * * Extenstion to: * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax maximum length of string * * OUTPUT PARAMETERS * dest updated string * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * dmax shall not equal zero. * dmax shall not be greater than RSIZE_MAX_STR. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strtolowercase_s() * */ errno_t strtouppercase_s (char *dest, rsize_t dmax) { if (!dest) { invoke_safe_str_constraint_handler("strtouppercase_s: " "dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strtouppercase_s: " "dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strtouppercase_s: " "dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } while (*dest && dmax) { if ((*dest >= 'a') && (*dest <= 'z')) { *dest = (char)(*dest - 32); } dest++; dmax--; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/strzero_s.c0000644000000000000000000000561714210363175017670 0ustar 00000000000000/*------------------------------------------------------------------ * strzero_s.c * * October 2008, Bo Berry * * Copyright (c) 2008-2011 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * strzero_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strzero_s(char *dest, rsize_t dmax) * * DESCRIPTION * Nulls dmax characters of dest. This function can be used * to clear strings that contained sensitive data. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be nulled. * * dmax restricted maximum length of dest * * OUTPUT PARAMETERS * dest updated string * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strispassword_s() * */ errno_t strzero_s (char *dest, rsize_t dmax) { if (dest == NULL) { invoke_safe_str_constraint_handler("strzero_s: dest is null", NULL, ESNULLP); return (ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strzero_s: dmax is 0", NULL, ESZEROL); return (ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strzero_s: dmax exceeds max", NULL, ESLEMAX); return (ESLEMAX); } /* null string to eliminate data */ while (dmax) { *dest = '\0'; dmax--; dest++; } return (EOK); } tboot-1.10.5/safestringlib/safeclib/wcpcpy_s.c0000644000000000000000000001543314210363175017462 0ustar 00000000000000/*------------------------------------------------------------------ * wcpcpy_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * wcpcpy_s * * SYNOPSIS * #include "safe_str_lib.h" * wchar_t * * wcpcpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, errno_t *err) * * DESCRIPTION * The wcpcpy_s function copies the wide character string pointed * to by src (including the terminating null character) into the * array pointed to by dest, and returns a pointer to the end of * the wide character string. All elements following the terminating * null character (if any) written by wcpcpy_s in the array of * dmax characters pointed to by dest are nulled when * wcpcpy_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the wide character string that will be copied * to dest * * err the error code upon error, or EOK if successful * * OUTPUT PARAMETERS * dest updated * err updated as follows: * EOK successful operation, the characters in src were * copied into dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not be greater than RSIZE_MAX_STR. * dmax shall not equal zero. * dmax shall be greater than strnlen_s(src, dmax). * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and destmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpy_s nulls dest. * * RETURN VALUE * a wchar_t pointer to the terminating null at the end of dest * * ALSO SEE * wcscpy_s(), wcscat_s(), wcsncat_s(), wcsncpy_s() * strcpy_s, strcat_s(), strncat_s(), strncpy_s() * */ wchar_t * wcpcpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, errno_t *err) { rsize_t orig_dmax; wchar_t *orig_dest; const wchar_t *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("wcpcpy_s: dest is null", NULL, ESNULLP); *err = RCNEGATE(ESNULLP); return NULL; } if (dmax == 0) { invoke_safe_str_constraint_handler("wcpcpy_s: dmax is 0", NULL, ESZEROL); *err = RCNEGATE(ESZEROL); return NULL; } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcpcpy_s: dmax exceeds max", NULL, ESLEMAX); *err = RCNEGATE(ESLEMAX); return NULL; } if (src == NULL) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to clear data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #else *dest = L'\0'; #endif invoke_safe_str_constraint_handler("wcpcpy_s: src is null", NULL, ESNULLP); *err = RCNEGATE(ESNULLP); return NULL; } if (dest == src) { /* move dest to the end of the string */ while (dmax && (*dest != L'\0')) { dmax--; dest++; } if ( *dest != L'\0' ) { invoke_safe_str_constraint_handler("wcpcpy_s: no null terminator in dest", NULL, ESLEMAX); *err = RCNEGATE(ESLEMAX); return NULL; } *err = RCNEGATE(EOK); return dest; } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcpcpy_s: overlapping objects", ESOVRLP); *err = RCNEGATE(ESOVRLP); return NULL; } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif *err = RCNEGATE(EOK); return dest; /* successful return */ } dmax--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcpcpy_s: overlapping objects", ESOVRLP); *err = RCNEGATE(ESOVRLP); return NULL; } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif *err = RCNEGATE(EOK); return dest; /* successful return */ } dmax--; dest++; src++; } } /* * the entire src must have been copied, if not reset dest * to null the string. */ handle_wc_error(orig_dest, orig_dmax, "wcpcpy_s: not enough space for src", ESNOSPC); *err = RCNEGATE(ESNOSPC); return NULL; } EXPORT_SYMBOL(wcpcpy_s); tboot-1.10.5/safestringlib/safeclib/wcscat_s.c0000644000000000000000000001604114210363175017435 0ustar 00000000000000/*------------------------------------------------------------------ * wcscat_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * wcscat_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * wcscat_s(wchar_t* dest, rsize_t dmax, const wchar_t* src) * * DESCRIPTION * The wcscat_s function appends a copy of the wide characer string pointed * to by src (including the terminating null character) to the * end of the string pointed to by dest. The initial wide character * from src overwrites the null character at the end of dest. * * All elements following the terminating null character (if * any) written by strcat_s in the array of dmax characters * pointed to by dest take unspeciï¬ed values when strcat_s * returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to wide character string that will be extended by src * if dmax allows. The string is null terminated. * If the resulting concatenated string is less * than dmax, the remaining slack space is nulled. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be concatenaed * to string dest * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer * dmax shall not equal zero * dmax shall not be greater than RSIZE_MAX_STR * dmax shall be greater than strnlen_s(src,m). * Copying shall not takeplace between objects that overlap * If there is a runtime-constraint violation, then if dest is * not a null pointer and dmax is greater than zero and not * greater than RSIZE_MAX_STR, then strcat_s nulls dest. * * RETURN VALUE * EOK successful operation, all the characters from src * were appended to dest and the result in dest is * null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max * ESUNTERM dest not terminated * * ALSO SEE * strcat_s, strncat_s(), strcpy_s(), strncpy_s() * */ errno_t wcscat_s(wchar_t* dest, rsize_t dmax, const wchar_t* src) { rsize_t orig_dmax; wchar_t *orig_dest; const wchar_t *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("wcscat_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("wcscat_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("wcscat_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcscat_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; /* Find the end of dest */ while (*dest != L'\0') { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } dest++; dmax--; if (dmax == 0) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } else { overlap_bumper = dest; /* Find the end of dest */ while (*dest != L'\0') { /* * NOTE: no need to check for overlap here since src comes first * in memory and we're not incrementing src here. */ dest++; dmax--; if (dmax == 0) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (src == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } /* * the entire src was not copied, so null the string */ handle_wc_error(orig_dest, orig_dmax, "wcscat_s: not enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(wcscat_s); tboot-1.10.5/safestringlib/safeclib/wcscpy_s.c0000644000000000000000000001452014210363175017461 0ustar 00000000000000/*------------------------------------------------------------------ * wcscpy_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * wcscpy_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * wcscpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src) * * DESCRIPTION * The wcscpy_s function copies the wide character string pointed * to by src (including the terminating null character) into the * array pointed to by dest. All elements following the terminating * null character (if any) written by strcpy_s in the array of * dmax characters pointed to by dest are nulled when * wcscpy_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the wide character string that will be copied * to dest * * OUTPUT PARAMETERS * dest updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not be greater than RSIZE_MAX_STR. * dmax shall not equal zero. * dmax shall be greater than strnlen_s(src, dmax). * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and destmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpy_s nulls dest. * * RETURN VALUE * EOK successful operation, the characters in src were * copied into dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * ALSO SEE * strcpy_s, strcat_s(), strncat_s(), strncpy_s() * wcscat_s(), * */ errno_t wcscpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src) { rsize_t orig_dmax; wchar_t *orig_dest; const wchar_t *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("wcscpy_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("wcscpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcscpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (src == NULL) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif invoke_safe_str_constraint_handler("wcscpy_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } /* Verify proper length according to dmax if src = dest */ if (dest == src) { /* Ensure that src is not longer than dmax */ while (*src != L'\0' && (dmax != 0)) { src++; dmax--; } if ( *src != L'\0' ) { invoke_safe_str_constraint_handler("wcscpy_s: src exceeds dmax", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } return RCNEGATE(EOK); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } /* * the entire src must have been copied, if not reset dest * to null the string. */ handle_wc_error(orig_dest, orig_dmax, "wcscpy_s: not " "enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(wcscpy_s); tboot-1.10.5/safestringlib/safeclib/wcsncat_s.c0000644000000000000000000002055014210363175017613 0ustar 00000000000000/*------------------------------------------------------------------ * wcsncat_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * wcsncat_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * wcsncat_s(wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t slen) * * DESCRIPTION * The wcsncat_s function appends a copy of (at most) the * first slen wide characters pointed to by src to the * end of the string pointed to by dest and terminates the * string with the null character. If less than slen wide * characters are in the string src, the function stops * copying after the null terminator is copied to dest. * The initial character from src overwrites the null * character at the end of dest. * * All elements following the terminating null character (if * any) written by strncat_s in the array of dmax characters * pointed to by dest take unspeciï¬ed values when strncat_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be extended by src * if dmax allows. The string is null terminated. * If the resulting concatenated string is less * than dmax, the remaining slack space is nulled. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be concatenaed * to string dest * * slen maximum characters to append * * OUTPUT PARAMETERS * dest updated string * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer * dmax shall not equal zero * dmax shall not be greater than RSIZE_STR_MAX * dmax shall be greater than strnlen_s(src,m). * Copying shall not takeplace between objects that overlap * If there is a runtime-constraint violation, then if dest is * not a null pointer and dmax is greater than zero and not * greater thanRSIZE_MAX, then strncat_s sets dest[0] to the * null character. * * RETURN VALUE * EOK successful operation, all the characters from src * were appended to dest and the result in dest is * null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESUNTERM dest not terminated * * */ errno_t wcsncat_s (wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t slen) { rsize_t orig_dmax; wchar_t *orig_dest; const wchar_t *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("wcsncat_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("wcsncat_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (slen*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcsncat_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (dmax == 0) { invoke_safe_str_constraint_handler("wcsncat_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcsncat_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; /* Find the end of dest */ while (*dest != L'\0') { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcsncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } dest++; dmax--; if (dmax == 0) { handle_wc_error(orig_dest, orig_dmax, "wcsncat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcsncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } /* * Copying truncated before the source null is encountered */ /* TODO: test if this copies at most slen characters including NULL */ if (slen == 0) { #ifdef SAFECLIB_STR_NULL_SLACK /* null remaining string */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #else *dest = L'\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } else { overlap_bumper = dest; /* Find the end of dest */ while (*dest != L'\0') { /* * NOTE: no need to check for overlap here since src comes first * in memory and we're not incrementing src here. */ dest++; dmax--; if (dmax == 0) { handle_wc_error(orig_dest, orig_dmax, "wcsncat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (src == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcsncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } /* * Copying truncated */ if (slen == 0) { #ifdef SAFECLIB_STR_NULL_SLACK /* null remaining string */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #else *dest = L'\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } /* * the entire src was not copied, so the string will be nulled. */ handle_wc_error(orig_dest, orig_dmax, "wcsncat_s: not enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(wcsncat_s); tboot-1.10.5/safestringlib/safeclib/wcsncpy_s.c0000644000000000000000000001734214210363175017644 0ustar 00000000000000/*------------------------------------------------------------------ * wcsncpy_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /* * NAME * wcsncpy_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * wcsncpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t slen) * * DESCRIPTION * The wcsncpy_s function copies not more than slen successive characters * (characters that follow a null character are not copied) from the * array pointed to by src to the array pointed to by dest. If no null * character was copied from src, then dest[slen] is set to a null character. * * All elements following the terminating null character (if any) * written by wcsncpy_s in the array of dmax characters pointed to * by dest take on the null value when wcsncpy_s returns. * * When SAFECLIB_STR_NULL_SLACK is defined to be true (#DEFINE), then * the dest array is filled with NULL characters following the end of * the last non-NULL character from src. While this is more secure, it * is also incurs a performance penalty, especially when the same dest * array is used multiple times to string manipulation routines in this * library. If this extra security is not required, ensure that the * library is compiled without #DEFINE SAFECLIB_STR_NULL_SLACK. * * Specicified in: * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * The resulting string is null terminated. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be copied * to string dest * * slen the maximum number of characters to copy from src * * OUTPUT PARAMETERS * dest updated with src string * * RUNTIME CONSTRAINTS * Neither dmax nor slen shall be equal to zero. * Neither dmax nor slen shall be equal zero. * Neither dmax nor slen shall be greater than RSIZE_MAX_STR. * If slen is either greater than or equal to dmax, then dmax * should be more than strnlen_s(src,dmax) * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and dmax greater than RSIZE_MAX_STR, * then strncpy_s nulls dest. * * RETURN VALUE * EOK successful operation, the characters in src were copied * to dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * ALSO SEE * strcat_s(), strncat_s(), strcpy_s() * wcscat_s(), wcsncat_s(), wcscpy_s() *- */ errno_t wcsncpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t slen) { rsize_t orig_dmax; wchar_t *orig_dest; const wchar_t *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("wcsncpy_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("wcsncpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcsncpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (src == NULL) { handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: src is null", ESNULLP); return RCNEGATE(ESNULLP); } if (slen == 0) { handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: slen is zero", ESZEROL); return RCNEGATE(ESZEROL); } if (slen*sizeof(wchar_t) > RSIZE_MAX_STR) { handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: slen exceeds max", ESLEMAX); return RCNEGATE(ESLEMAX); } if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } if (slen == 0) { /* * Copying truncated to slen chars. Note that the TR says to * copy slen chars plus the null char. We null the slack. */ #ifdef SAFECLIB_STR_NULL_SLACK while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } if (slen == 0) { /* * Copying truncated to slen chars. Note that the TR says to * copy slen chars plus the null char. We null the slack. */ #ifdef SAFECLIB_STR_NULL_SLACK while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } /* * the entire src was not copied, so zero the string */ handle_wc_error(orig_dest, orig_dmax, "wcsncpy_s: not enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); } EXPORT_SYMBOL(wcsncpy_s); tboot-1.10.5/safestringlib/safeclib/wcsnlen_s.c0000644000000000000000000000650614210363175017627 0ustar 00000000000000/*------------------------------------------------------------------ * wcsnlen_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_str_constraint.h" #include "safe_str_lib.h" /** * NAME * wcsnlen_s * * SYNOPSIS * #include "safe_str_lib.h" * rsize_t * wcsnlen_s(const wchar_t *dest, rsize_t dmax) * * DESCRIPTION * The wcsnlen_s function computes the length of the wide character string pointed * to by dest. * * SPECIFIED IN * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to wide character string * * dmax restricted maximum length. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer * dmax shall not be greater than RSIZE_MAX_STR * dmax shall not equal zero * * RETURN VALUE * The function returns the number of wide characters in the string * pointed to by dest, excluding the terminating null character. * If dest is NULL, then wcsnlen_s returns 0. * * Otherwise, the wcsnlen_s function returns the number of wide characters * that precede the terminating null character. If there is no null * character in the first dmax characters of dest then wcsnlen_s returns * dmax. At most the first dmax characters of dest are accessed * by wcsnlen_s. * * ALSO SEE * strnlen_s, strnterminate_s() * */ rsize_t wcsnlen_s (const wchar_t *dest, rsize_t dmax) { rsize_t count; if (dest == NULL) { return RCNEGATE(0); } if (dmax == 0) { invoke_safe_str_constraint_handler("wcsnlen_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(0); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcsnlen_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(0); } count = 0; while (*dest && dmax) { count++; dmax--; dest++; } return RCNEGATE(count); } EXPORT_SYMBOL(wcsnlen_s); tboot-1.10.5/safestringlib/safeclib/wmemcmp_s.c0000644000000000000000000001151714210363175017621 0ustar 00000000000000/*------------------------------------------------------------------ * wmemcmp_s.c - Compares memory * * September 2014, D. Wheeler * * Copyright (c) 2014 Intel Corp * All rights reserved. * * Based on memcmp32_s.c, October 2008, by Bo Berry * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "safe_mem_lib.h" /** * NAME * wmemcmp_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * wmemcmp_s(const wchar_t *dest, rsize_t dmax, * const wchar_t *src, rsize_t smax, int *diff) * * DESCRIPTION * Compares wide-character strings until they differ, and their difference is * returned in diff. If the wide character string is the same, diff=0. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to compare against * * dmax maximum length of dest, in uint32_t * * src pointer to the source memory to compare with dest * * smax maximum length of src, in uint32_t * * *diff pointer to the diff which is an integer greater * than, equal to or less than zero according to * whether the object pointed to by dest is * greater than, equal to or less than the object * pointed to by src. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memcmp_s(), memcmp16_s() * */ errno_t wmemcmp_s (const wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t smax, int *diff) { /* * must be able to return the diff */ if (diff == NULL) { invoke_safe_mem_constraint_handler("wmemcmp_s: diff is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } *diff = -1; /* default diff */ if (dest == NULL) { invoke_safe_mem_constraint_handler("wmemcmp_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (src == NULL) { invoke_safe_mem_constraint_handler("wmemcmp_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("wmemcmp_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM32) { invoke_safe_mem_constraint_handler("wmemcmp_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { invoke_safe_mem_constraint_handler("wmemcmp_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { invoke_safe_mem_constraint_handler("wmemcmp_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * no need to compare the same memory */ if (dest == src) { *diff = 0; return (RCNEGATE(EOK)); } /* * now compare src to dest */ *diff = 0; while (dmax != 0 && smax != 0) { if (*dest != *src) { *diff = *dest - *src; break; } dmax--; smax--; dest++; src++; } return (RCNEGATE(EOK)); } EXPORT_SYMBOL(wmemcmp_s); tboot-1.10.5/safestringlib/safeclib/wmemcpy_s.c0000644000000000000000000001150314210363175017630 0ustar 00000000000000/*------------------------------------------------------------------ * wmemcpy_s * * AUgust 2014, D. Wheeler * * Copyright (c) 2014 Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" #include /** * NAME * wmemcpy_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * wmemcpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t smax) * * DESCRIPTION * This function copies at most smax wide characters from src to dest, up to * dmax. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be replaced by src. * * dmax maximum length of the resulting dest * * src pointer to the memory that will be copied to dest * * smax maximum number bytes of src to copy * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * Copying shall not take place between regions that overlap. * If there is a runtime-constraint violation, the memcpy_s function * stores zeros in the ï¬rst dmax bytes of the region pointed to * by dest if dest is not a null pointer and smax is valid. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP source memory overlaps destination * * ALSO SEE * memcpy16_s(), memcpy32_s(), memcpy_s(), * wmemmove_s(), memmove_s(), memmove16_s(), memmove32_s(), * */ errno_t wmemcpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t smax) { wchar_t *dp; const wchar_t *sp; dp = dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("wmemcpy_s: dest is NULL", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_mem_constraint_handler("wmemcpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("wmemcpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (smax == 0) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemcpy_s: smax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (smax > dmax) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemcpy_s: smax exceeds dmax", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (sp == NULL) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemcpy_s: src is NULL", NULL, ESNULLP); return RCNEGATE(ESNULLP); } /* * overlap is undefined behavior, do not allow */ if( ((dp > sp) && (dp < (sp+smax))) || ((sp > dp) && (sp < (dp+dmax))) ) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemcpy_s: overlap undefined", NULL, ESOVRLP); return RCNEGATE(ESOVRLP); } /* * now perform the copy */ mem_prim_move(dp, sp, smax*sizeof(wchar_t)); return RCNEGATE(EOK); } EXPORT_SYMBOL(wmemcpy_s); tboot-1.10.5/safestringlib/safeclib/wmemmove_s.c0000644000000000000000000001156114210363175020007 0ustar 00000000000000/*------------------------------------------------------------------ * wmemmove_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" #include /** * NAME * wmemmove_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * wmemmove_s(wchar_t* dest, rsize_t dmax, * const wchar_t* src, size_t smax) * * DESCRIPTION * The wmemmove_s function copies smax wide characters from the region pointed * to by src into the region pointed to by dest. This copying takes place * as if the smax wide characters from the region pointed to by src are ï¬rst copied * into a temporary array of smax bytes that does not overlap the region * pointed to by dest or src, and then the smax bytes from the temporary * array are copied into the object region to by dest. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to the memory that will be replaced by src. * * dmax maximum number of resulting wide characters in dest * * src pointer to the memory that will be copied * to dest * * smax maximum number wide characters of src that can be copied * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM/sizeof(wchar_t). * smax shall not be greater than dmax. * If there is a runtime-constraint violation, the wmemmove_s function * stores zeros in the ï¬rst dmax characters of the region pointed to * by dest if dest is not a null pointer and dmax is not greater * than RSIZE_MAX_MEM/sizeof(wchar_t). * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memmove16_s(), memmove32_s(), memcpy_s(), memcpy16_s() memcpy32_s() * wmemcpy_s() * */ errno_t wmemmove_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, size_t smax) { wchar_t *dp; const wchar_t *sp; dp= dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("wmemmove_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("wmemmove_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("wmemmove_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemmove_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemmove_s: smax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (sp == NULL) { mem_prim_set(dp, dmax*sizeof(wchar_t), 0); invoke_safe_mem_constraint_handler("wmemmove_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * now perform the copy */ mem_prim_move(dp, sp, smax*sizeof(wchar_t)); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(wmemmove_s); tboot-1.10.5/safestringlib/safeclib/wmemset_s.c0000644000000000000000000000627414210363175017641 0ustar 00000000000000/*------------------------------------------------------------------ * wmemset_s * * August 2014, D Wheeler * * Copyright (c) 2014 Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "safeclib_private.h" #include "safe_mem_constraint.h" #include "mem_primitives_lib.h" #include "safe_mem_lib.h" /** * NAME * wmemset_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * wmemset_s(wchar_t *dest, wchar_t value, rsize_t len) * * DESCRIPTION * Sets len number of wide characters starting at dest to the specified value. * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be set to the value * * value byte value * * len number of wide characters to be set * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM/sizeof(wchar_t). * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memset_s, memset16_s(), memset32_s() * */ errno_t wmemset_s (wchar_t *dest, wchar_t value, rsize_t len) { if (dest == NULL) { invoke_safe_mem_constraint_handler("wmemset_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("wmemset_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len*sizeof(wchar_t) > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("wmemset_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } mem_prim_set32((void*)dest, len, value); return (RCNEGATE(EOK)); } EXPORT_SYMBOL(wmemset_s); tboot-1.10.5/safestringlib/unittests/Safe_String_UnitTestMain.c0000644000000000000000000001236514210363175022776 0ustar 00000000000000/* ============================================================================ Name : Safe_String_Extensions.c Author : David M. Wheeler Version : Copyright : (C) Intel Corp 2014 Description : Safe String Test Suite ============================================================================ */ #include #include #include #include extern int test_memcmp_s(); extern int test_memcmp16_s(); extern int test_memcmp32_s(); extern int test_memcpy_s(); extern int test_memcpy16_s(); extern int test_memcpy32_s(); extern int test_memmove_s(); extern int test_memmove16_s(); extern int test_memmove32_s(); extern int test_memset_s(); extern int test_memset16_s(); extern int test_memset32_s(); extern int test_memzero_s(); extern int test_memzero16_s(); extern int test_memzero32_s(); extern int test_strcasecmp_s(); extern int test_strcasestr_s(); extern int test_strcat_s(); extern int test_strcmp_s(); extern int test_strcmpfld_s(); extern int test_strcpy_s(); extern int test_strcpyfld_s(); extern int test_strcpyfldin_s(); extern int test_strcpyfldout_s(); extern int test_strcspn_s (); extern int test_strfirstchar_s(); extern int test_strfirstdiff_s(); extern int test_strfirstsame_s(); extern int test_strisalphanumeric_s(); extern int test_strisascii_s(); extern int test_strisdigit_s(); extern int test_strishex_s(); extern int test_strislowercase_s(); extern int test_strismixed_s(); extern int test_strispassword_s(); extern int test_strisuppercase_s(); extern int test_strlastchar_s(); extern int test_strlastdiff_s(); extern int test_strlastsame_s(); extern int test_strljustify_s(); extern int test_strncat_s (); extern int test_strncpy_s (); extern int test_strnlen_s (); extern int test_strnterminate_s(); extern int test_strpbrk_s (); extern int test_strprefix_s(); extern int test_strremovews_s(); extern int test_strspn_s (); extern int test_strstr_s (); extern int test_strtok_s(); extern int test_strtolowercase_s(); extern int test_strtouppercase_s(); extern int test_strzero_s(); extern int test_stpncpy_s(); extern int test_stpcpy_s(); extern int test_wcpcpy_s(); extern int test_wcscat_s(); extern int test_wcscpy_s(); extern int test_wcsncat_s(); extern int test_wcsncpy_s (void); extern int test_wcsnlen_s (void); extern int test_wmemcpy_s(void); extern int test_wmemmove_s(void); extern int test_wmemset_s(void); extern int test_wmemcmp_s(void); int main(void) { char dest[128]; char src[128]; rsize_t dmax = 128; rsize_t smax = 21; errno_t err; puts("!!!Basic Test Suite for Safe String Operations!!!"); puts(" ERRORS PRINT TO CONSOLE"); puts("----------------BEGIN TEST--------------------"); test_memcmp_s(); test_memcmp16_s(); test_memcmp32_s(); test_memcpy_s(); test_memcpy16_s(); test_memcpy32_s(); test_memmove_s(); test_memmove16_s(); test_memmove32_s(); test_memset_s(); test_memset16_s(); test_memset32_s(); test_memzero_s(); test_memzero16_s(); test_memzero32_s(); test_stpcpy_s(); /* New - Done */ test_stpncpy_s(); /* New - Done */ test_strcasecmp_s(); test_strcasestr_s(); test_strcat_s(); test_strcmp_s(); test_strcmpfld_s(); test_strcpy_s(); test_strcpyfld_s(); test_strcpyfldin_s(); test_strcpyfldout_s(); test_strcspn_s (); test_strfirstchar_s(); test_strfirstdiff_s(); test_strfirstsame_s(); test_strisalphanumeric_s(); test_strisascii_s(); test_strisdigit_s(); test_strishex_s(); test_strislowercase_s(); test_strismixed_s(); test_strispassword_s(); test_strisuppercase_s(); test_strlastchar_s(); test_strlastdiff_s(); test_strlastsame_s(); test_strljustify_s(); test_strncat_s (); test_strncpy_s (); test_strnlen_s (); test_strnterminate_s(); test_strpbrk_s (); test_strprefix_s(); test_strremovews_s(); test_strspn_s (); test_strstr_s (); test_strtok_s(); test_strtolowercase_s(); test_strtouppercase_s(); test_strzero_s(); test_wcpcpy_s(); /* New - Done */ test_wcscat_s(); /* New - Done */ test_wcscpy_s(); /* New - Done */ test_wcsncat_s(); /* New - Done */ test_wcsncpy_s(); /* New - Done */ test_wcsnlen_s(); /* New - Done */ test_wmemcpy_s(); /* New - Done */ test_wmemmove_s(); /* New - Done */ test_wmemset_s(); /* New - Done */ test_wmemcmp_s(); /* New - Done */ char str[] = "This is a char array"; char str2[] = "...And another one."; int indicator = -1; strcpy_s(dest, dmax, str); char *ret = stpcpy_s(&dest[20], 108, str2, &err); if (err != EOK) { puts("stpcpy_s returned failure"); } int val = 55; if ( (err = snprintf_s_si(src, 128, "Test sprintf_s_si() with simple format string [%s] and %d", dest, val)) < 0 ) { if ( SNPRFNEGATE(ESBADFMT) == err ) { puts("snprintf_s_si returned failure: Error Bad Format String."); } else if ( SNPRFNEGATE(ESFMTTYP) == err ) { puts("snprintf_s_si returned failure: Error Bad Argument Type for format string."); } else { printf("snprintf_s_si failed with unknown error: %d\n", err); } } else if ((strcmp_s(src, smax, "Test sprintf_s_si() with simple format string [This is a char array...And another one.] and 55", &indicator) != EOK ) || (indicator != 0 )) { puts("snprintf_s_si() failed - output was:"); puts(src); } puts("----------------END TEST--------------------"); return EXIT_SUCCESS; } tboot-1.10.5/safestringlib/unittests/test_memcmp16_s.c0000644000000000000000000001147414210363175021134 0ustar 00000000000000/*------------------------------------------------------------------ * test_memcmp16_s * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_mem_lib.h" #define LEN ( 128 ) int test_memcmp16_s() { errno_t rc; uint32_t len; int32_t ind; int32_t std_ind; uint32_t i; uint16_t mem1[LEN]; uint16_t mem2[LEN]; /*--------------------------------------------------*/ rc = memcmp16_s(NULL, LEN, mem2, LEN, &ind); if (rc != ESNULLP) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ rc = memcmp16_s(mem1, LEN, NULL, LEN, &ind); if (rc != ESNULLP) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ rc = memcmp16_s(mem1, LEN, mem2, LEN, NULL); if (rc != ESNULLP) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ rc = memcmp16_s(mem1, 0, mem2, LEN, &ind); if (rc != ESZEROL) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ rc = memcmp16_s(mem1, LEN, mem2, 0, &ind); if (rc != ESZEROL) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ rc = memcmp16_s(mem1, RSIZE_MAX_MEM+1, mem2, LEN, &ind); if (rc != ESLEMAX) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ rc = memcmp16_s(mem1, LEN, mem2, RSIZE_MAX_MEM+1, &ind); if (rc != ESLEMAX) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ for (i=0; i -1) { debug_printf("%s %u Ind=%d rc=%u \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ len = 3; memset(mem1, 55, len); memset(mem2, 55, len); rc = memcmp_s(mem1, len, mem2, len, &ind); if (rc != EOK) { debug_printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc); } if (ind != 0) { debug_printf("%s %u Ind=%d rc=%u \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_memcpy16_s.c0000644000000000000000000001441114210363175021142 0ustar 00000000000000/*------------------------------------------------------------------ * test_memcpy16_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_mem_lib.h" #define LEN ( 1024 ) int test_memcpy16_s() { errno_t rc; uint32_t len; uint32_t i; uint16_t mem1[LEN]; uint16_t mem2[LEN]; /*--------------------------------------------------*/ rc = memcpy16_s(NULL, LEN, mem2, LEN); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = memcpy16_s(mem1, 0, mem2, LEN); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = memcpy16_s(mem1, RSIZE_MAX_MEM16+1, mem2, LEN); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = memcpy16_s(mem1, LEN, NULL, LEN); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = memcpy16_s(mem1, 10, mem2, 0); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = memcpy16_s(mem1, LEN, mem2, RSIZE_MAX_MEM16+1); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ for (i=0; i * * Copyright (c) 2012, 2013 by Cisco Systems, Inc * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #ifndef __TEST_PRIVATE_H__ #define __TEST_PRIVATE_H__ #ifdef __KERNEL__ #include #include #include #include #define printf(...) printk(KERN_INFO __VA_ARGS__) #else #include #include #endif #ifdef DEBUG # ifdef __KERNEL__ # define debug_printf(...) printk(KERN_DEBUG __VA_ARGS__) # else # define debug_printf printf # endif #else #define debug_printf(...) #endif #endif /* __TEST_PRIVATE_H__ */ tboot-1.10.5/safestringlib/unittests/test_stpcpy_s.c0000644000000000000000000003521714210363175021032 0ustar 00000000000000/*------------------------------------------------------------------ * test_stpcpy_s * * September 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 3: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * TC 4: Test for third parameter, source char string, being sent in as NULL * * TEST WHEN SRC & DEST ARE THE SAME * TC 5: Test for src=dest, but string too long for dmax * TC 6: Test for src=dest, proper return * * TEST WHEN DEST BUFFER < SOURCE BUFFER * TC 7: Test for overlap of dest buffer into src buffer (src string too long) * TC12: Test for proper longer string copy over shorter string * TC13: Test for not enough space in destination (dest < src) * TC15: Test for just enough space in destination * * TEST NON-STANDARD FAILURE CONDITIONS FOR NULL DEST STRINGS * TC 9: Test copy null string over destination string (dest < src) * TC10: Test copy NULL string over existing string (dest > src) * TC11: Test copy string over NULL string (dest < src) * * TEST WHEN DEST BUFFER >= SOURCE BUFFER * TC 8: Test src buffer runs into beginning of dest buffer (src buffer is unterminated or been destroyed by copy) * TC14: Test for not enough space in destination (dest > src) * TC16: Test copy short string over long string * * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128 ) #define LEN ( 128 ) static char str1[LEN]; static char str2[LEN]; int test_stpcpy_s (void) { char *ret; errno_t rc; uint32_t i; int32_t ind; unsigned int testno = 0; printf("\nTesting stpcpy_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); ret = stpcpy_s(NULL, LEN, str2, &rc); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 2 Test for zero length destination */ printf("Test #%d:\n", ++testno); ret = stpcpy_s(str1, 0, str2, &rc); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 3 Test for too large destination size */ printf("Test #%d:\n", ++testno); ret = stpcpy_s(str1, (RSIZE_MAX_STR+1), str2, &rc); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 4 Test for NULL source check */ printf("Test #%d:\n", ++testno); strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = stpcpy_s(str1, 5, NULL, &rc); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != '\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[0] != '\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 5 Test for Src is same as dest, but source too long */ printf("Test #%d:\n", ++testno); strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = stpcpy_s(str1, 5, str1, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 6 Test copy the same string onto itself */ printf("Test #%d:\n", ++testno); strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = stpcpy_s(str1, LEN, str1, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 7 Test for string overlap, destination < src, and * dest overlaps onto the src string, so a copy would * change the src string */ printf("Test #%d:\n", ++testno); strcpy(&str1[0], "keep it simple"); ret = stpcpy_s(&str1[0], LEN, &str1[5], &rc); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i src, and * src overlaps onto the dest string, so a copy would * result in an infinite copy operation */ printf("Test #%d:\n", ++testno); strcpy(&str1[0], "keep it simple"); ret = stpcpy_s(&str1[5], LEN, &str1[0], &rc); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i src) */ printf("Test #%d:\n", ++testno); strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "keep it simple"); ret = stpcpy_s(str2, 2, str1, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str2 != '\0') { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 15: Test for just enough space in destination */ printf("Test #%d:\n", ++testno); strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "it"); ret = stpcpy_s(str1, 3, str2, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 16: Test copy short string over long string */ printf("Test #%d:\n", ++testno); strcpy(str2, "qq12345weqeqeqeq"); strcpy(str1, "it"); ret = stpcpy_s(str2, 10, str1, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str2+strnlen_s(str2, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcpy */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_stpncpy_s.c0000644000000000000000000004661514210363175021214 0ustar 00000000000000/*------------------------------------------------------------------ * test_stpncpy_s * * September 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 3: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * TC 4: Test for third parameter, source char string, being sent in as NULL * * TEST WHEN SRC & DEST ARE THE SAME * TC 5: Test for src=dest, but string too long for dmax * TC 6: Test for src=dest, proper return * * TEST WHEN DEST BUFFER < SOURCE BUFFER * TC 7: Test for overlap of dest buffer into src buffer (src string too long) * TC12: Test for proper substring copy of string over long string (limited by smax) * TC13: Test for accurate String copy over existing string, filling dest with dmax with NULLs * TC14: Test for accurate subString copy over existing string (limited by smax), filling dest wtih dmax nulls * TC15: Test for accurate subString copy (limited by smax) and adding null terminator, replacing existing string * TC16: Test copy but not enough space in destination * TC17: Test for not enough space in destination for null terminator * TC18: Test for just enough space in destination * TC19: Test copy short string over long string * * * TEST NON-STANDARD FAILURE CONDITIONS FOR NULL DEST STRINGS * TC 9: Test copy null string over destination string (dest < src) * TC10: Test copy NULL string over existing string (dest > src) * TC11: Test copy string over NULL string (dest < src) * * TEST WHEN DEST BUFFER >= SOURCE BUFFER * TC 8: Test src buffer runs into beginning of dest buffer (src buffer is unterminated or been destroyed by copy) * * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128 ) #define LEN ( 128 ) static char str1[LEN]; static char str2[LEN]; extern char *stpncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t smax, errno_t *err); int test_stpncpy_s (void) { char *ret; errno_t rc; uint32_t i; int32_t ind; rsize_t sz; unsigned int testno = 0; printf("\nTesting stpncpy_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); ret = stpncpy_s(NULL, LEN, str2, LEN, &rc); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 2 Test for zero length destination */ printf("Test #%d:\n", ++testno); ret = stpncpy_s(str1, 0, str2, LEN, &rc); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 3 Test for too large destination size */ printf("Test #%d:\n", ++testno); ret = stpncpy_s(str1, (RSIZE_MAX_STR+1), str2, LEN, &rc); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 4 Test for NULL source check */ printf("Test #%d:\n", ++testno); strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = stpncpy_s(str1, 5, NULL, LEN, &rc); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != '\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[0] != '\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 5 Test for Src is same as dest, but source too long */ printf("Test #%d:\n", ++testno); strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); sz = strnlen_s(str1, LEN); ret = stpncpy_s(str1, 5, str1, sz, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 6 Test copy the same string onto itself */ printf("Test #%d:\n", ++testno); strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); sz = strnlen_s(str1, LEN); ret = stpncpy_s(str1, LEN, str1, sz, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 7 Test for string overlap, destination < src, and * dest overlaps onto the src string, so a copy would * change the src string */ printf("Test #%d:\n", ++testno); strcpy(&str1[0], "keep it simple"); sz = strnlen_s(str1, LEN); ret = stpncpy_s(&str1[0], LEN, &str1[5], sz, &rc); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i src, and * src overlaps onto the dest string, so a copy would * result in an infinite copy operation */ printf("Test #%d:\n", ++testno); strcpy(&str1[0], "keep it simple"); sz = strnlen_s(str1, LEN); ret = stpncpy_s(&str1[5], LEN, &str1[0], sz, &rc); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i -%s- (smax=%d) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 12 Test for accurate subString copy over existing string */ printf("Test #%d:\n", ++testno); strcpy(str1, "xxxxxxxxxx"); strcpy(str2, "abcde"); ret = stpncpy_s(str1, LEN, str2, 3, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } else { /* be sure the results are the same as strcmp */ sz = strnlen_s(str1, LEN); ind = strncmp(str1, str2, sz); if (ind != 0 || sz != 3) { printf("%s %u -%s- <> -%s- (smax=%d) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } /* be sure that the slack is correct */ for (i=1; i<6; i++) { if (ret[i] != 'x') { printf("%s %u Incorrect Slack at returned ptr index %d Error rc=%u \n", __FUNCTION__, __LINE__, i, rc ); } } } /*--------------------------------------------------*/ /* 13 Test for accurate String copy with extra nulls over existing string */ printf("Test #%d:\n", ++testno); strcpy(str1, "xxxxxxxxxxxxxxxxxxxx"); strcpy(str2, "abcde"); ret = stpncpy_s(str1, LEN, str2, 10, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } else { /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } else { /* be sure that the nulls are correct */ for (i=0; i<5; i++) { if (ret[i] != '\0') { printf("%s %u Incorrect NULL fill at returned ptr index %d Error rc=%u \n", __FUNCTION__, __LINE__, i, rc ); } } /* be sure that the slack is correct */ for (; i<15; i++) { if (ret[i] != 'x') { printf("%s %u Incorrect Slack at returned ptr index %d Error rc=%u \n", __FUNCTION__, __LINE__, i, rc ); } } } } /*--------------------------------------------------*/ /* 14 Test for accurate String copy and added null over existing string */ printf("Test #%d:\n", ++testno); strcpy(str1, "xxxxxxxxxx"); strcpy(str2, "abcde"); ret = stpncpy_s(str1, LEN, str2, 5, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } else { /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } else { /* be sure that the slack is correct */ for (i=1; i<5; i++) { if (ret[i] != 'x') { printf("%s %u Incorrect Slack at returned ptr index %d Error rc=%u \n", __FUNCTION__, __LINE__, i, rc ); } } } } /*--------------------------------------------------*/ /* 15 Test for accurate String copy and added null over existing string */ printf("Test #%d:\n", ++testno); strcpy(str1, "xxxxxxxxxx"); strcpy(str2, "abcde"); ret = stpncpy_s(str1, LEN, str2, 6, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } else { /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } else { /* be sure that the slack is correct */ for (i=1; i<5; i++) { if (ret[i] != 'x') { printf("%s %u Incorrect Slack at returned ptr index %d Error rc=%u \n", __FUNCTION__, __LINE__, i, rc ); } } } } /*--------------------------------------------------*/ /* 16 Test for not enough space in destination */ printf("Test #%d:\n", ++testno); strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "keep it simple"); sz = strnlen_s(str2, LEN); ret = stpncpy_s(str1, 1, str2, sz, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str1 != '\0') { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 17 Test for not enough space in destination for null terminator */ printf("Test #%d:\n", ++testno); strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "keep it simple"); sz = strnlen_s(str2, LEN); ret = stpncpy_s(str1, 14, str2, sz, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str1 != '\0') { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 18: Test for just enough space in destination */ printf("Test #%d:\n", ++testno); strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "it"); sz = strnlen_s(str2, LEN); ret = stpncpy_s(str1, 3, str2, sz, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 19: Test copy short string over long string */ printf("Test #%d:\n", ++testno); strcpy(str1, "qq12345weqeqeqeq"); strcpy(str2, "it"); ret = stpncpy_s(str1, 10, str2, 2, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != '\0' || ret != str1+strnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcpy */ ind = strcmp(str1, str2); if (ind != 0) { printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strcasecmp_s.c0000644000000000000000000001423414210363175021650 0ustar 00000000000000/*------------------------------------------------------------------ * test_strcasecmp_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) static char str1[LEN]; static char str2[LEN]; int test_strcasecmp_s (void) { errno_t rc; int ind; int std_ind; /*--------------------------------------------------*/ rc = strcasecmp_s(NULL, LEN, str2, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strcasecmp_s(str1, LEN, NULL, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strcasecmp_s(str1, LEN, str2, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasecmp_s(str1, 0, str2, &ind); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strcasecmp_s(str1, RSIZE_MAX_STR+1, str2, &ind); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strcasecmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } std_ind = strcasecmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP IT SIMPLE"); strcpy (str2, "keep it simple"); rc = strcasecmp_s(str1, 1, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP IT SIMPLE"); strcpy (str2, "keep it simple"); rc = strcasecmp_s(str1, 2, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP IT SIMPLE"); strcpy (str2, "keep it simple"); rc = strcasecmp_s(str1, 4, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP IT SIMPLE"); strcpy (str2, "keep it simple"); rc = strcasecmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } std_ind = strcasecmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keeP it simple"); rc = strcasecmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); rc = strcasecmp_s(str1, LEN, str1, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP it simplified"); strcpy (str2, "keep it simple"); rc = strcasecmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != ('I' - 'E')) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP 1234567890"); strcpy (str2, "keep it simple"); rc = strcasecmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != ('1' - 'I')) { printf("%s %u Error ind=%d rc=%d %d \n", __FUNCTION__, __LINE__, ind, rc, ('1' - 'I')); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strcasestr_s.c0000644000000000000000000003110614210363175021676 0ustar 00000000000000/*------------------------------------------------------------------ * test_strcasestr_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) extern errno_t strcasestr_s (char *dest, rsize_t dmax, const char *src, rsize_t slen, char **substring); int test_strcasestr_s() { errno_t rc; char *sub; char *std_sub; rsize_t len1; rsize_t len2; char str1[LEN]; char str2[LEN]; /*--------------------------------------------------*/ rc = strcasestr_s(NULL, LEN, str2, LEN, &sub); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasestr_s(str1, LEN, NULL, LEN, &sub); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasestr_s(str1, LEN, str2, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasestr_s(str1, 0, str2, LEN, &sub); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasestr_s(str1, RSIZE_MAX_STR+1, str2, LEN, &sub); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasestr_s(str1, LEN, str2, 0, &sub); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcasestr_s(str1, LEN, str2, RSIZE_MAX_STR+1, &sub); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ *str1 = '\0'; *str2 = '\0'; rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != str1) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strcasestr(str1, str2); if ((int)sub != (int)std_sub) { // comparison to handle 32-bit library return and 64-bit library return printf("%s %u Error strcasestr_s() does not have same return as strcasestr() when str1 & str2 are zero length strings. rc=%u \n", __FUNCTION__, __LINE__, rc); printf("str1:[%s]\n", str1); printf("str2:[%s]\n", str2); printf("strcasestr_s returns:[%x]\n", sub); printf("strcasestr returns:[%x]\n\n", std_sub); } /*--------------------------------------------------*/ *str1 = '\0'; strcpy(str1, "key"); rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != str1) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strcasestr(str1, str2); if ((int)sub != (int)std_sub) { // comparison to handle 32-bit library return and 64-bit library return printf("%s %u Error strcasestr_s() does not have same return value as strcasestr() when str2 is zero length string. rc=%u \n", __FUNCTION__, __LINE__, rc); printf("str1:[%s]\n", str1); printf("str2:[%s]\n", str2); printf("strcasestr_s returns:[%x]\n", sub); printf("strcasestr returns:[%x]\n\n", std_sub); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); *str2 = '\0'; /* str2 being empty, must return str1 */ rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != str1) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strcasestr(str1, str2); if ((int)sub != (int)std_sub) { // comparison to handle 32-bit library return and 64-bit library return printf("%s %u Error strcasestr_s() does not have same return value as strcasestr() when str2 is zero length string. rc=%u \n", __FUNCTION__, __LINE__, rc); printf("str1:[%s]\n", str1); printf("str2:[%s]\n", str2); printf("strcasestr_s returns:[%p]\n", sub); printf("strcasestr returns:[%p]\n\n", std_sub); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "kee"); /* substring at beginning */ rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[0]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "eep it"); /* substring in the middle */ rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[1]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "ethe"); /* substring in the middle */ rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[15]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "er"); len1 = strlen(str1); len2 = strlen(str2); /* substring at the end */ rc = strcasestr_s(str1, len1, str2, len2, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[18]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strcasestr(str1, str2); if ((int)sub != (int)std_sub) { // comparison to handle 32-bit library return and 64-bit library return printf("%s %u Error strcasestr_s() does not have same return value as strcasestr() when str2 is substring of the end of str1. rc=%u \n", __FUNCTION__, __LINE__, rc); printf("str1:[%s]\n", str1); printf("str2:[%s]\n", str2); printf("strcasestr_s returns:[%p]\n", sub); printf("strcasestr returns:[%p]\n\n", std_sub); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "er"); len1 = strlen(str1); len2 = strlen(str2); /* substring at the end */ rc = strcasestr_s(str1, len1, str2, 2, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[18]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strcasestr(str1, str2); if ((int)sub != (int)std_sub) { // comparison to handle 32-bit library return and 64-bit library return printf("%s %u Error strcasestr_s() does not have same return value as strcasestr() when str2 is substring of middle of str1. rc=%u \n", __FUNCTION__, __LINE__, rc); printf("str1:[%s]\n", str1); printf("str2:[%s]\n", str2); printf("strcasestr_s returns:[%p]\n", sub); printf("strcasestr returns:[%p]\n\n", std_sub); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strcasestr_s(str1, 3, str2, LEN, &sub); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != NULL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strcasestr_s(str1, LEN, str2, 1, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[5]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strcasestr_s(str1, LEN, str2, 2, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[5]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strcasestr_s(str1, LEN, str2, 5, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[5]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "1234"); len1 = strlen(str1); rc = strcasestr_s(str1, len1, str2, LEN, &sub); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != NULL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "IT ALL"); rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[5]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "EEP"); /* validate */ rc = strcasestr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[1]) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strcasestr(str1, str2); if ((int)sub != (int)std_sub) { // comparison to handle 32-bit library return and 64-bit library return printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strcat_s.c0000644000000000000000000001724614210363175021012 0ustar 00000000000000/*------------------------------------------------------------------ * test_strcat_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) static char str1[LEN]; static char str2[LEN]; int test_strcat_s (void) { errno_t rc; int32_t ind; int32_t len1; int32_t len2; int32_t len3; /*--------------------------------------------------*/ rc = strcat_s(NULL, LEN, str2); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcat_s(str1, LEN, NULL); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcat_s(str1, 0, str2); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcat_s(str1, (RSIZE_MAX_STR+1), str2); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaa"); strcpy(str2, "keep it simple"); rc = strcat_s(str1, 1, str2); if (rc != ESUNTERM) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaa"); strcpy(str2, "keep it simple"); rc = strcat_s(str1, 2, str2); if (rc != ESUNTERM) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(&str1[0], "aaaaaaaaaa"); strcpy(&str2[0], "keep it simple"); len1 = strlen(str1); len2 = strlen(str2); rc = strcat_s(str1, 50, str2); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } len3 = strlen(str1); if (len3 != (len1+len2)) { debug_printf("%s %u lengths wrong: %u %u %u \n", __FUNCTION__, __LINE__, len1, len2, len3); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ str1[0] = '\0'; strcpy(str2, "keep it simple"); rc = strcat_s(str1, 1, str2); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ str1[0] = '\0'; strcpy(str2, "keep it simple"); rc = strcat_s(str1, 2, str2); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ str1[0] = '\0'; strcpy(str2, "keep it simple"); rc = strcat_s(str1, 20, str2); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, str2 ); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strcat_s(str1, LEN, str2); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ str1[0] = '\0'; strcpy(str2, "keep it simple"); rc = strcat_s(str1, LEN, str2); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, str2); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ strcpy(str1, "qqweqq"); strcpy(str2, "keep it simple"); rc = strcat_s(str1, LEN, str2); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "qqweqqkeep it simple"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ strcpy(str1, "1234"); strcpy(str2, "keep it simple"); rc = strcat_s(str1, 12, str2); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "1234"); strcpy(str2, "keep it simple"); rc = strcat_s(str1, 52, str2); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "1234keep it simple"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ strcpy(str1, "12345678901234567890"); rc = strcat_s(str1, 8, &str1[7]); if (rc != ESOVRLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(str1, "123456789"); rc = strcat_s(str1, 9, &str1[8]); if (rc != ESOVRLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(str2, "123"); strcpy(str1, "keep it simple"); rc = strcat_s(str2, 31, &str1[0]); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str2, "123keep it simple"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ strcpy(str2, "1234"); strcpy(str1, "56789"); rc = strcat_s(str2, 10, str1); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str2, "123456789"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strcmp_s.c0000644000000000000000000001425114210363175021013 0ustar 00000000000000/*------------------------------------------------------------------ * test_strcmp_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) static char str1[LEN]; static char str2[LEN]; int test_strcmp_s (void) { errno_t rc; int ind; int std_ind; /*--------------------------------------------------*/ rc = strcmp_s(NULL, LEN, str2, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strcmp_s(str1, LEN, NULL, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strcmp_s(str1, LEN, str2, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strcmp_s(str1, 0, str2, &ind); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strcmp_s(str1, RSIZE_MAX_STR+1, str2, &ind); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strcmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } std_ind = strcmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep it simple"); rc = strcmp_s(str1, 5, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ /* K - k == -32 */ strcpy (str1, "Keep it simple"); strcpy (str2, "keep it simple"); rc = strcmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != (-32)) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } std_ind = strcmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ /* p - P == 32 */ strcpy (str1, "keep it simple"); strcpy (str2, "keeP it simple"); rc = strcmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 32) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } std_ind = strcmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); rc = strcmp_s(str1, LEN, str1, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /* be sure the results are the same as strcmp */ std_ind = strcmp(str1, str1); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simplified"); strcpy (str2, "keep it simple"); rc = strcmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind <= 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /* be sure the results are the same as strcmp */ std_ind = strcmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep it simplified"); rc = strcmp_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind >= 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /* be sure the results are the same as strcmp */ std_ind = strcmp(str1, str2); if (ind != std_ind) { printf("%s %u ind=%d std_ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, std_ind, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strcmpfld_s.c0000644000000000000000000001550014210363175021477 0ustar 00000000000000/*------------------------------------------------------------------ * test_strcmpfld_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128 ) #define LEN ( 128 ) int test_strcmpfld_s() { errno_t rc; uint32_t i; rsize_t len; int ind; char str1[LEN]; char str2[LEN]; /*--------------------------------------------------*/ rc = strcmpfld_s(NULL, LEN, str2, &ind); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 5; rc = strcmpfld_s(str1, len, NULL, &ind); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 5; rc = strcmpfld_s(str1, len, str2, NULL); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strcmpfld_s(str1, 0, str2, &ind); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strcmpfld_s(str1, (RSIZE_MAX_STR+1), str2, &ind); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); strcpy(str2, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); len = 1; rc = strcmpfld_s(str1, len, str2, &ind); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } for (i=0; i,<"); len = strlen(str); rc = strisalphanumeric_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strisascii_s.c0000644000000000000000000000554314210363175021664 0ustar 00000000000000/*------------------------------------------------------------------ * test_strisascii_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strisascii_s() { bool rc; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strisascii_s(NULL, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strisascii_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strisascii_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* empty string */ rc = strisascii_s("", 2); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "ABCDEFGHIJK"); rc = strisascii_s(str, 2); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "N"); len = strlen(str); rc = strisascii_s(str, 1); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "N"); len = strlen(str); rc = strisascii_s(str, 2); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "NowISTHETimE"); len = strlen(str); rc = strisascii_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "qq21ego"); rc = strisascii_s(str, 33); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "1234"); str[2] = 132; /* special char */ len = strlen(str); /* special char embedded */ rc = strisascii_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strisdigit_s.c0000644000000000000000000000505114210363175021666 0ustar 00000000000000/*------------------------------------------------------------------ * test_strisdigit_s * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strisdigit_s() { bool rc; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strisdigit_s(NULL, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strisdigit_s("1234", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strisdigit_s("1234", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 9; rc = strisdigit_s("", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "123456789"); len = 4; rc = strisdigit_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "1"); len = strlen(str); rc = strisdigit_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "12"); len = strlen(str); rc = strisdigit_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "1abcd"); len = strlen(str); rc = strisdigit_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "abcd"); len = strlen(str); rc = strisdigit_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strishex_s.c0000644000000000000000000000603514210363175021355 0ustar 00000000000000/*------------------------------------------------------------------ * test_strishex_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strishex_s() { bool rc; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strishex_s(NULL, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ str[0] = '\0'; rc = strishex_s(str, 5); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strishex_s("1234", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strishex_s("1234", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 9; rc = strishex_s("", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "123456789"); len = 6; rc = strishex_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "1"); len = strlen(str); rc = strishex_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "12"); len = strlen(str); rc = strishex_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "1Af"); len = strlen(str); rc = strishex_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "FF"); len = strlen(str); rc = strishex_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "1abzd"); len = strlen(str); /* non hex char in string */ rc = strishex_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strislowercase_s.c0000644000000000000000000000455014210363175022555 0ustar 00000000000000/*------------------------------------------------------------------ * test_strislowercase_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strislowercase_s() { bool rc; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strislowercase_s(NULL, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strislowercase_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strislowercase_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ str[0] = '\0'; rc = strislowercase_s(str, 5); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "qqweqeqeqeq"); len = 3; rc = strislowercase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "qqweqeqeqeq"); len = strlen(str); rc = strislowercase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "qqWe go"); len = strlen(str); rc = strislowercase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "1234"); len = strlen(str); rc = strislowercase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strismixed_s.c0000644000000000000000000000514714210363175021702 0ustar 00000000000000/*------------------------------------------------------------------ * test_strismixed_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strismixed_s() { bool rc; rsize_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strismixedcase_s(NULL, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strismixedcase_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = RSIZE_MAX_STR+1; rc = strismixedcase_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 9; rc = strismixedcase_s("", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "AaBbCcDdEeFf"); len = 5; rc = strismixedcase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "N"); len = strlen(str); rc = strismixedcase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "NowISTHETimE"); len = strlen(str); rc = strismixedcase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "qq21ego"); len = strlen(str); rc = strismixedcase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "1234"); len = strlen(str); rc = strismixedcase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strispassword_s.c0000644000000000000000000000604214210363175022431 0ustar 00000000000000/*------------------------------------------------------------------ * test_strispassword_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN 64 int test_strispassword_s() { bool rc; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ rc = strispassword_s(NULL, LEN); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strispassword_s("", LEN); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strispassword_s("Test4You&", 0); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strispassword_s("Test4You&", 999); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strispassword_s("", 9); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "Test4You*123"); len = 8; rc = strispassword_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "Test4You*"); len = strlen(str); rc = strispassword_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "Test4You*Test4You*Test4You*"); len = strlen(str); rc = strispassword_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "Eest!22/"); len = strlen(str); rc = strispassword_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "pa$$W0rD"); len = strlen(str); rc = strispassword_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "Test"); len = strlen(str); rc = strispassword_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strisuppercase_s.c0000644000000000000000000000517414210363175022563 0ustar 00000000000000/*------------------------------------------------------------------ * test_strisuppercase_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strisuppercase_s() { bool rc; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strisuppercase_s(NULL, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strisuppercase_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strisuppercase_s("test", len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ str[0] = '\0'; rc = strisuppercase_s(str, 5); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "ABCDEFGHIGHIJ"); len = 7; rc = strisuppercase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "ABCDEFGHIGHIJ"); len = strlen(str); rc = strisuppercase_s(str, len); if (rc != true) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "qqWe go"); len = strlen(str); rc = strisuppercase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "1234"); len = strlen(str); rc = strisuppercase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "!@#$%^&*()"); len = strlen(str); rc = strisuppercase_s(str, len); if (rc != false) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strlastchar_s.c0000644000000000000000000001064614210363175022041 0ustar 00000000000000/*------------------------------------------------------------------ * test_strlastchar_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) int test_strlastchar_s() { errno_t rc; char *last; char str1[LEN]; /*--------------------------------------------------*/ rc = strlastchar_s(NULL, LEN, 'a', &last); if (rc != ESNULLP) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } if (last) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ rc = strlastchar_s(str1, LEN, 'a', NULL); if (rc != ESNULLP) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ rc = strlastchar_s(str1, 0, 'a', &last); if (rc != ESZEROL) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } if (last) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ rc = strlastchar_s(str1, RSIZE_MAX_STR+1, 'a', &last); if (rc != ESLEMAX) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } if (last) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; rc = strlastchar_s(str1, LEN, 'a', &last); if (rc != ESNOTFND) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } if (last) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ strcpy (str1, "Keep it simple"); rc = strlastchar_s(str1, 5, 'z', &last); if (rc != ESNOTFND) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } if (last) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ strcpy (str1, "Keep it simplezz"); rc = strlastchar_s(str1, LEN, 'z', &last); if (rc != EOK) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } if (last != &str1[15]) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ strcpy (str1, "Keep it simple"); rc = strlastchar_s(str1, LEN, 'K', &last); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (last != &str1[0]) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ strcpy (str1, "kEEp it simple"); rc = strlastchar_s(str1, LEN, 'E', &last); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (last != &str1[2]) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ strcpy (str1, "kEep it Simple"); rc = strlastchar_s(str1, LEN, 'S', &last); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (last != &str1[8]) { printf("%s %u Error str1=%p last=%p rc=%d \n", __FUNCTION__, __LINE__, str1, last, rc); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strlastdiff_s.c0000644000000000000000000001166014210363175022031 0ustar 00000000000000/*------------------------------------------------------------------ * test_strlastdiff_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) int test_strlastdiff_s() { errno_t rc; rsize_t ind; char str1[LEN]; char str2[LEN]; /*--------------------------------------------------*/ rc = strlastdiff_s(NULL, LEN, str2, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strlastdiff_s(str1, LEN, NULL, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strlastdiff_s(str1, LEN, str2, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strlastdiff_s(str1, 0, str2, &ind); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strlastdiff_s(str1, RSIZE_MAX_STR+1, str2, &ind); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strlastdiff_s(str1, LEN, str2, &ind); if (rc != ESNODIFF) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "Keep iT simple"); strcpy (str2, "keep it simple"); rc = strlastdiff_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 6) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "kEep it simple"); strcpy (str2, "keep it simple"); rc = strlastdiff_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 1) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it siMple"); strcpy (str2, "keEp it Simple"); rc = strlastdiff_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 10) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); rc = strlastdiff_s(str1, LEN, str1, &ind); if (rc != ESNODIFF) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep it simple"); rc = strlastdiff_s(str1, 1, str2, &ind); if (rc != ESNODIFF) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep it simplE"); rc = strlastdiff_s(str1, 25, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 13) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strlastsame_s.c0000644000000000000000000001445514210363175022053 0ustar 00000000000000/*------------------------------------------------------------------ * test_strlastsame_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) int test_strlastsame_s() { errno_t rc; rsize_t ind; char str1[LEN]; char str2[LEN]; /*--------------------------------------------------*/ rc = strlastsame_s(NULL, LEN, str2, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strlastsame_s(str1, LEN, NULL, &ind); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strlastsame_s(str1, LEN, str2, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strlastsame_s(str1, 0, str2, &ind); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ rc = strlastsame_s(str1, RSIZE_MAX_STR+1, str2, &ind); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strlastsame_s(str1, LEN, str2, &ind); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "Keep it simple"); strcpy (str2, "keep_IT_SIMPLISTIC"); rc = strlastsame_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 3) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "kEEP_IT_SIMPLE"); strcpy (str2, "keep it simplistic"); rc = strlastsame_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "kkEEP_IT_SIMPLE"); strcpy (str2, "kkeep it simplistic"); rc = strlastsame_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 1) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keeP_IT_SIMPLe"); rc = strlastsame_s(str1, LEN, str2, &ind); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (ind != 13) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); /* same string for src and dest */ rc = strlastsame_s(str1, LEN, str1, &ind); if (rc != EOK) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } if (ind != 13) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP it simple"); strcpy (str2, "keep it simple"); rc = strlastsame_s(str1, 1, str2, &ind); if (rc != ESNOTFND) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "KEEP it simple"); strcpy (str2, "Keep it simple"); rc = strlastsame_s(str1, 1, str2, &ind); if (rc != EOK) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "KEEP_IT_SIMPLE"); rc = strlastsame_s(str1, 5, str2, &ind); if (rc != ESNOTFND) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "KEEP_IT_SIMPLE"); rc = strlastsame_s(str1, LEN, str2, &ind); if (rc != ESNOTFND) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } if (ind != 0) { printf("%s %u Error ind=%d rc=%d \n", __FUNCTION__, __LINE__, ind, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strljustify_s.c0000644000000000000000000001347514210363175022114 0ustar 00000000000000/*------------------------------------------------------------------ * test_strljustify_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strljustify_s() { errno_t rc; int ind; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strljustify_s(NULL, len); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strljustify_s("test", len); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strljustify_s("test", len); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* empty string */ rc = strljustify_s(" ", 12); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "ABCDEFGHIJK"); len = 2; /* unterminated */ rc = strljustify_s(str, len); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != '\0') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " ABCDEFGHIJK"); len = 5; /* unterminated */ rc = strljustify_s(str, len); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != '\0') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "A"); len = 1; /* a one char string will be emptied - str[0]=='\0' */ rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != '\0') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "ABC"); len = 2; /* this will be unterminated */ rc = strljustify_s(str, len); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != '\0') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "ABC"); len = 5; /* this will be unterminated */ rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "ABC"); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " B "); len = strlen(str); rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "B "); if (ind != 0) { printf("%s %u Error -%s- ind=%d \n", __FUNCTION__, __LINE__, str, ind); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " B "); len = strlen(str); rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "B "); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " C "); len = strlen(str); rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "C "); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " NowISTHETimE "); len = strlen(str); rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "NowISTHETimE "); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " qq21ego "); len = strlen(str); rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " 1234 "); len = strlen(str); rc = strljustify_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strncat_s.c0000644000000000000000000001261114210363175021157 0ustar 00000000000000/*------------------------------------------------------------------ * test_strncat_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) static char str1[LEN]; static char str2[LEN]; int test_strncat_s (void) { errno_t rc; int32_t ind; /*--------------------------------------------------*/ rc = strncat_s(NULL, LEN, str2, LEN); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strncat_s(str1, LEN, NULL, LEN); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strncat_s(str1, 0, str2, LEN); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strncat_s(str1, (RSIZE_MAX_STR+1), str2, LEN); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strncat_s(str1, (RSIZE_MAX_STR), str2, (RSIZE_MAX_STR+1)); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaa"); strcpy(str2, "keep it simple"); rc = strncat_s(str1, 1, str2, LEN); if (rc != ESUNTERM) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaa"); strcpy(str2, "keep it simple"); rc = strncat_s(str1, 2, str2, LEN); if (rc != ESUNTERM) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(str1, "a"); strcpy(str2, "b"); rc = strncat_s(str1, 2, str2, 1); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ strcpy(str1, "a"); strcpy(str2, "b"); rc = strncat_s(str1, 3, str2, 1); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "ab"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaa"); strcpy(str2, "keep it simple"); rc = strncat_s(str1, 50, str2, LEN); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "aaaaaaaaaakeep it simple"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* TR example */ strcpy(str1, "good"); strcpy(str2, "bye"); rc = strncat_s(str1, 100, str2, 100); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "goodbye"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* TR example */ strcpy(str1, "hello"); rc = strncat_s(str1, 6, "", 1); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "hello"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* TR example */ strcpy(str1, "hello"); rc = strncat_s(str1, 6, "X", 2); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { debug_printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* TR example */ strcpy(str1, "abc"); rc = strncat_s(str1, 7, "defghijklmn", 3); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } ind = strcmp(str1, "abcdef"); if (ind != 0) { debug_printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strncpy_s.c0000644000000000000000000002125014210363175021202 0ustar 00000000000000/*------------------------------------------------------------------ * test_strncpy_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128 ) #define LEN ( 128 ) static char str1[LEN]; static char str2[LEN]; static char dest[LEN]; int test_strncpy_s (void) { errno_t rc; rsize_t nlen; int32_t ind; /*--------------------------------------------------*/ nlen = 5; rc = strncpy_s(NULL, LEN, str2, nlen); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); nlen = 5; rc = strncpy_s(str1, 5, NULL, nlen); if (rc != ESNULLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[0] != '\0') { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ nlen = 5; rc = strncpy_s(str1, 0, str2, nlen); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strncpy_s(str1, (RSIZE_MAX_STR+1), str2, nlen); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); str2[0] = '\0'; rc = strncpy_s(str1, 5, str2, 0); if (rc != ESZEROL) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[0] != '\0') { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ #if 1 strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); strcpy(str2, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); rc = strncpy_s(str1, 5, str2, (RSIZE_MAX_STR+1)); if (rc != ESLEMAX) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); str2[0] = '\0'; nlen = 5; rc = strncpy_s(&str1[0], LEN/2, &str2[0], nlen); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[0] != '\0') { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); nlen = 5; /* test overlap */ rc = strncpy_s(str1, LEN, str1, nlen); if (rc != ESOVRLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[0] != '\0') { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); nlen = 18; rc = strncpy_s(&str1[0], LEN, &str1[5], nlen); if (rc != ESOVRLP) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[0] != '\0') { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); str2[0] = '\0'; nlen = 10; rc = strncpy_s(str1, LEN, str2, nlen); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[0] != '\0') { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ str1[0] = '\0'; strcpy(str2, "keep it simple"); nlen = 20; rc = strncpy_s(str1, LEN, str2, nlen); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "keep it simple"); nlen = 32; rc = strncpy_s(str1, LEN, str2, nlen); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "keep it simple"); rc = strncpy_s(str1, 1, str2, nlen); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str1 != '\0') { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ strcpy(str1, "qqweqeqeqeq"); strcpy(str2, "keep it simple"); rc = strncpy_s(str1, 2, str2, nlen); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str1 != '\0') { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* TR example */ strcpy(dest, " "); strcpy(str1, "hello"); rc = strncpy_s(dest, 6, str1, 100); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(dest, str1); if (ind != 0) { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* TR example */ strcpy(dest, " "); strcpy(str2, "goodbye"); rc = strncpy_s(dest, 5, str2, 7); if (rc != ESNOSPC) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* TR example */ strcpy(dest, " "); strcpy(str2, "goodbye"); rc = strncpy_s(dest, 5, str2, 4); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(dest, "good"); if (ind != 0) { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ strcpy(dest, " "); strcpy(str2, "good"); /* strnlen("good") < 5 */ rc = strncpy_s(dest, 5, str2, 8); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(dest, "good"); if (ind != 0) { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ strcpy(str1, "qq12345weqeqeqeq"); strcpy(str2, "it"); nlen = 10; rc = strncpy_s(str1, 10, str2, nlen); if (rc != EOK) { debug_printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /* be sure the results are the same as strcmp */ ind = strcmp(str1, str2); if (ind != 0) { debug_printf("%s %u -%s- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strnlen_s.c0000644000000000000000000000566014210363175021174 0ustar 00000000000000/*------------------------------------------------------------------ * test_strnlen_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strnlen_s (void) { rsize_t len; rsize_t std_len; rsize_t max_len; /*--------------------------------------------------*/ max_len = 3; len = strnlen_s(NULL, max_len); if (len != 0) { printf("%s %u Len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ max_len = 0; len = strnlen_s("test", max_len); if (len != 0) { printf("%s %u Len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ max_len = RSIZE_MAX_STR+1; len = strnlen_s("test", max_len); if (len != 0) { printf("%s %u Len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ std_len = strlen(""); max_len = RSIZE_MAX_STR; len = strnlen_s ("", max_len); if (std_len != len) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ std_len = strlen("t"); max_len = RSIZE_MAX_STR; len = strnlen_s ("t", max_len); if (std_len != len) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ std_len = strlen("to"); max_len = RSIZE_MAX_STR; len = strnlen_s ("to", max_len); if (std_len != len) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ std_len = strlen("testing"); max_len = RSIZE_MAX_STR; len = strnlen_s ("testing", max_len); if (std_len != len) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ max_len = 1; len = strnlen_s ("testing", max_len); if (len != max_len) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ max_len = 2; len = strnlen_s ("testing", max_len); if (len != max_len) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ max_len = 3; len = strnlen_s ("testing", max_len); if (len != max_len) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strnterminate_s.c0000644000000000000000000001044714210363175022405 0ustar 00000000000000/*------------------------------------------------------------------ * test_strnterminate_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strnterminate_s() { rsize_t len; rsize_t std_len; rsize_t max_len; char dest[LEN]; /*--------------------------------------------------*/ strcpy(dest,""); max_len = 3; len = strnterminate_s(NULL, max_len); if (len != 0) { printf("%s %u Len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"test"); max_len = 0; len = strnterminate_s(dest, max_len); if (len != 0) { printf("%s %u Len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"test"); max_len = RSIZE_MAX_STR+1; len = strnterminate_s(dest, max_len); if (len != 0) { printf("%s %u Len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"ff"); std_len = strlen(dest); max_len = RSIZE_MAX_STR; len = strnterminate_s (dest, max_len); if (std_len != len) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ strcpy(dest,"ff"); len = strnterminate_s (dest, 1); if (len != 0 ) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ strcpy(dest,"f"); max_len = RSIZE_MAX_STR; len = strnterminate_s (dest, max_len); if (len != 1 ) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ strcpy(dest,"f"); max_len = RSIZE_MAX_STR; len = strnterminate_s (dest, max_len); if (len != 1 ) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ strcpy(dest,"ff"); max_len = RSIZE_MAX_STR; len = strnterminate_s (dest, max_len); if (len != 2) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ strcpy(dest,"test"); max_len = RSIZE_MAX_STR; len = strnterminate_s (dest, max_len); if (len != 4) { printf("%s %u std_len=%u len=%u \n", __FUNCTION__, __LINE__, std_len, len); } /*--------------------------------------------------*/ strcpy(dest,"testing"); max_len = 1; len = strnterminate_s (dest, max_len); if (len != 0) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"testing"); max_len = 2; len = strnterminate_s (dest, max_len); if (len != max_len-1) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"testing"); max_len = 3; len = strnterminate_s (dest, max_len); if (len != max_len-1) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"testing"); max_len = 33; len = strnterminate_s (dest, max_len); if (len != strlen(dest)) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } /*--------------------------------------------------*/ strcpy(dest,"012345678901234567890"); len = 21; while (len) { //printf(" strnterminate_s() len=%u \n", len); len = strnterminate_s (dest, len); if (len != strlen(dest)) { printf("%s %u len=%u \n", __FUNCTION__, __LINE__, len); } } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strpbrk_s.c0000644000000000000000000001706614210363175021201 0ustar 00000000000000/*------------------------------------------------------------------ * test_strpbrk_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) static char str1[LEN]; static char str2[LEN]; int test_strpbrk_s (void) { errno_t rc; char *first; char *std_first; /*--------------------------------------------------*/ rc = strpbrk_s(str1, LEN, str2, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strpbrk_s(NULL, LEN, str2, LEN, &first); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ rc = strpbrk_s(str1, LEN, NULL, LEN, &first); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ rc = strpbrk_s(str1, LEN, str2, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strpbrk_s(str1, 0, str2, LEN, &first); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ rc = strpbrk_s(str1, RSIZE_MAX_STR+1, str2, LEN, &first); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ rc = strpbrk_s(str1, RSIZE_MAX_STR, str2, RSIZE_MAX_STR+1, &first); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; /* not to be found */ rc = strpbrk_s(str1, LEN, str2, LEN, &first); if (rc != ESNOTFND) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } if (first) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "1234"); rc = strpbrk_s(str1, 2, str2, LEN, &first); if (rc != ESNOTFND) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "ke"); rc = strpbrk_s(str1, 2, str2, LEN, &first); if (rc != EOK) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simplez"); strcpy (str2, "z"); rc = strpbrk_s(str1, LEN, str2, LEN, &first); if (rc != EOK) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "123456"); rc = strpbrk_s(str1, LEN, str2, 2, &first); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first != 0) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, ""); rc = strpbrk_s(str1, LEN, str2, 1, &first); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (first != 0) { printf("%s %u Error first=%p rc=%d \n", __FUNCTION__, __LINE__, first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "k"); rc = strpbrk_s(str1, LEN, str2, 1, &first); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "ke"); rc = strpbrk_s(str1, LEN, str2, 2, &first); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "hip"); rc = strpbrk_s(str1, LEN, str2, LEN, &first); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simply"); strcpy (str2, "123y"); rc = strpbrk_s(str1, LEN, str2, LEN, &first); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_first = strpbrk(str1, str2); if (first != std_first) { printf("%s %u first=%p std_first=%p rc=%d \n", __FUNCTION__, __LINE__, first, std_first, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strprefix_s.c0000644000000000000000000000741214210363175021532 0ustar 00000000000000/*------------------------------------------------------------------ * test_strprefix_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) int test_strprefix_s() { errno_t rc; rsize_t len; char str1[LEN]; char str2[LEN]; /*--------------------------------------------------*/ rc = strprefix_s(NULL, LEN, str2); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strprefix_s(str1, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strprefix_s(str1, 0, str2); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strprefix_s(str1, RSIZE_MAX_STR+1, str2); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strprefix_s(str1, LEN, str2); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); strcpy(str2, "keep"); rc = strprefix_s(str1, 55, str2); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); strcpy(str2, "kerp"); rc = strprefix_s(str1, 55, str2); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "ke"); strcpy(str2, "kerp"); rc = strprefix_s(str1, 2, str2); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); strcpy(str2, "keep"); rc = strprefix_s(str1, 4, str2); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); strcpy(str2, "keeeep"); rc = strprefix_s(str1, 4, str2); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); rc = strprefix_s(str1, 4, ""); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); strcpy(str2, "keep it sipmle and very long"); len = strlen(str1); rc = strprefix_s(str1, len, str2); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it simple"); strcpy(str2, "keep it simple"); len = strlen(str1); rc = strprefix_s(str1, len, str2); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strremovews_s.c0000644000000000000000000001277414210363175022113 0ustar 00000000000000/*------------------------------------------------------------------ * test_strremovews_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strremovews_s() { errno_t rc; int ind; uint32_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strremovews_s(NULL, len); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strremovews_s("test", len); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strremovews_s("test", len); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "ABCDEFGHIJK"); len = 1; rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != '\0') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "ABCDEFGHIJK"); len = 2; rc = strremovews_s(str, len); if (rc != ESUNTERM) { printf("%s %u Error rc=%u --%s--\n", __FUNCTION__, __LINE__, rc, str ); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " ABCDEFGHIJK"); len = 3; rc = strremovews_s(str, len); if (rc != ESUNTERM) { printf("%s %u Error rc=%u --%s--\n", __FUNCTION__, __LINE__, rc, str ); } if (str[0] != '\0') { printf("%s %u Error rc=%u --%s--\n", __FUNCTION__, __LINE__, rc, str ); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " ABCDEFGHIJK"); len = 9; rc = strremovews_s(str, len); if (rc != ESUNTERM) { printf("%s %u Error rc=%u --%s--\n", __FUNCTION__, __LINE__, rc, str ); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "A"); len = 1; /* a one char string will be emptied - str[0]=='\0' */ rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != '\0') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, "ABC"); len = 8; rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != 'A') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " B"); len = strlen(str); rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str[0] != 'B') { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " C "); len = strlen(str); rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "C"); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy(str, " NowISTHETimE 1 2 "); len = strlen(str); rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "NowISTHETimE 1 2"); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " q q21ego"); len = strlen(str); rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "q q21ego"); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strzero_s(str, LEN); strcpy (str, " 1 2 3 4 "); len = strlen(str); rc = strremovews_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } ind = strcmp(str, "1 2 3 4"); if (ind != 0) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strspn_s.c0000644000000000000000000001702714210363175021040 0ustar 00000000000000/*------------------------------------------------------------------ * test_strspn_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) static char str1[LEN]; static char str2[LEN]; int test_strspn_s (void) { errno_t rc = 0; rsize_t count = 0; int32_t std_count = 0; /*--------------------------------------------------*/ rc = strspn_s(NULL, LEN, str2, LEN, &count); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ rc = strspn_s(str1, LEN, NULL, LEN, &count); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ rc = strspn_s(str1, LEN, str2, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strspn_s(str1, 0, str2, LEN, &count); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ rc = strspn_s(str1, LEN, str2, 0, &count); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ rc = strspn_s(str1, RSIZE_MAX_STR+1, str2, LEN, &count); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ rc = strspn_s(str1, RSIZE_MAX_STR, str2, RSIZE_MAX_STR+1, &count); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ str1[0] = '\0'; str2[0] = '\0'; rc = strspn_s(str1, LEN, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 0) { printf("%s %u Error count=%d rc=%d \n", __FUNCTION__, __LINE__, count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep"); rc = strspn_s(str1, 1, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 1) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep"); rc = strspn_s(str1, 2, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 2) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep"); rc = strspn_s(str1, 3, str2, 12, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (count != 3) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "k"); rc = strspn_s(str1, LEN, str2, 1, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_count = strspn(str1, str2); if (count != std_count) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "ke"); rc = strspn_s(str1, LEN, str2, 2, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_count = strspn(str1, str2); if (count != std_count) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep"); rc = strspn_s(str1, LEN, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_count = strspn(str1, str2); if (count != std_count) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "keep"); rc = strspn_s(str1, LEN, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_count = strspn(str1, str2); if (count != std_count) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "notincluded"); rc = strspn_s(str1, LEN, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_count = strspn(str1, str2); if (count != std_count) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ strcpy (str1, "keep it simple"); strcpy (str2, "1234567890"); rc = strspn_s(str1, LEN, str2, LEN, &count); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } std_count = strspn(str1, str2); if (count != std_count) { printf("%s %u count=%d std_count=%d rc=%d \n", __FUNCTION__, __LINE__, count, std_count, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strstr_s.c0000644000000000000000000001766614210363175021061 0ustar 00000000000000/*------------------------------------------------------------------ * test_strstr_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) #define SHORT_LEN ( 5 ) static char str1[LEN]; static char str2[LEN]; int test_strstr_s (void) { errno_t rc; char *sub; char *std_sub; rsize_t len1; rsize_t len2; /*--------------------------------------------------*/ rc = strstr_s(NULL, LEN, str2, LEN, &sub); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strstr_s(str1, LEN, NULL, LEN, &sub); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strstr_s(str1, LEN, str2, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strstr_s(str1, 0, str2, LEN, &sub); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strstr_s(str1, RSIZE_MAX_STR+1, str2, LEN, &sub); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strstr_s(str1, LEN, str2, 0, &sub); if (rc != ESZEROL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ rc = strstr_s(str1, LEN, str2, RSIZE_MAX_STR+1, &sub); if (rc != ESLEMAX) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ *str1 = '\0'; *str2 = '\0'; rc = strstr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != str1) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); *str2 = '\0'; rc = strstr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != str1) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "kee"); /* substring at beginning */ rc = strstr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[0]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "eep it"); /* substring in the middle - left */ rc = strstr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[1]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "ethe"); /* substring in the middle - right */ rc = strstr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[15]) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ // 012345678901234567890 strcpy(str1, "keep it all together"); strcpy(str2, "he"); len1 = strlen(str1); len2 = strlen(str2); rc = strstr_s(str1, len1, str2, len2, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[17]) { printf("%s %u Error rc=%d sub=%s \n", __FUNCTION__, __LINE__, rc, sub); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "er"); len1 = strlen(str1); len2 = strlen(str2); rc = strstr_s(str1, len1, str2, len2, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[18]) { printf("%s %u Error rc=%d sub=%s \n", __FUNCTION__, __LINE__, rc, sub); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strstr_s(str1, 3, str2, LEN, &sub); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strstr_s(str1, 333, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strstr_s(str1, LEN, str2, 5, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "1234"); len1 = strlen(str1); rc = strstr_s(str1, len1, str2, LEN, &sub); if (rc != ESNOTFND) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } if (sub != NULL) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "it all"); rc = strstr_s(str1, LEN, str2, 2, &sub); if (rc != EOK) { printf("%s %u Error rc=%d \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ strcpy(str1, "keep it all together"); strcpy(str2, "eep"); rc = strstr_s(str1, LEN, str2, LEN, &sub); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (sub != &str1[1]) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /* compare to legacy */ std_sub = strstr(str1, str2); if (sub != std_sub) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strtok_s.c0000644000000000000000000002204514210363175021031 0ustar 00000000000000/*------------------------------------------------------------------ * test_strtok_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strtok_s() { errno_t rc; char *p2str; char *p2tok; rsize_t len; char str1[LEN]; char str2[LEN]; /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); p2tok = strtok_s(str1, NULL, str2, &p2str); if (p2tok != NULL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); len = 0; p2tok = strtok_s(str1, &len, str2, &p2str); if (p2tok != NULL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); len = RSIZE_MAX_STR + 1; p2tok = strtok_s(str1, &len, str2, &p2str); if (p2tok != NULL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); len = 0; p2tok = strtok_s(str1, &len, NULL, &p2str); if (p2tok != NULL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); p2tok = strtok_s(str1, &len, str2, NULL); if (p2tok != NULL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); /* no token test */ strcpy(str1, "aaaaaaaa"); len = strlen(str1); strcpy(str2, "fedcba"); p2tok = strtok_s(str1, &len, str2, &p2str); if (p2tok != NULL) { printf("%s %u token -%s- remaining -%s- \n", __FUNCTION__, __LINE__, p2tok, p2str); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); strcpy(str1, "jklmnopqrst"); len = strlen(str1) - 2; /* cheat on len */ strcpy(str2, "fedcba"); p2tok = strtok_s(str1, &len, str2, &p2str); if (p2tok != NULL) { printf("%s %u token -%s- remaining -%s- \n", __FUNCTION__, __LINE__, p2tok, p2str); } if (p2tok != NULL) { printf("token -%s- -%s- \n", p2tok, p2str); } /*--------------------------------------------------*/ //printf("test: %u \n", __LINE__); strcpy(str1, "aaamnopqrst"); len = strlen(str1); strcpy(str2, "fedcba"); p2tok = strtok_s(str1, &len, str2, &p2str); if (p2tok == NULL) { printf("%s %u token -%s- remaining -%s- \n", __FUNCTION__, __LINE__, p2tok, p2str); } /*--------------------------------------------------*/ /** [1] **/ //printf("test: %u \n", __LINE__); strcpy(str1, "aaamnopqrstfedcba"); len = strlen(str1); strcpy(str2, "fedcba"); p2tok = strtok_s(str1, &len, str2, &p2str); if (p2tok == NULL) { printf("%s %u token -%s- remaining -%s- \n", __FUNCTION__, __LINE__, p2tok, p2str); } if (strcmp(p2tok, "mnopqrst")) { printf("%s %u token -%s- remaining -%s- \n", __FUNCTION__, __LINE__, p2tok, p2str); } //printf("token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); /*--------------------------------------------------*/ /** [2] **/ p2tok = strtok_s(p2str, &len, str2, &p2str); if (p2tok != NULL) { printf("%s %u token -%s- remaining -%s- \n", __FUNCTION__, __LINE__, p2tok, p2str); } //printf("token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); /*--------------------------------------------------*/ /*--------------------------------------------------*/ /** [1] **/ //printf("test: %u \n", __LINE__); strcpy(str1, "?a???b,,,#c"); len = strlen(str1); strcpy(str2, "?"); p2tok = strtok_s(str1, &len, str2, &p2str); if (strcmp(p2tok, "a") ) { printf("%s %u token -%s- -%s- len=%d \n", __FUNCTION__, __LINE__, p2tok, p2str, (int)len ); } //printf("token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); /*--------------------------------------------------*/ /** [2] **/ strcpy(str1, "?a???b,,,#c"); len = strlen(str1); strcpy(str2, ","); /* change the tokenizer string */ /** p2tok = strtok_s(p2str, &len, str2, &p2str); **/ p2tok = strtok_s(NULL, &len, str2, &p2str); if (strcmp(p2tok, "??b") ) { printf("%s %u token -%s- -%s- len=%d \n", __FUNCTION__, __LINE__, p2tok, p2str, (int)len ); } //printf("token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); /*--------------------------------------------------*/ /* strcpy(str1, ",,0,1,23,456,789,a,b,"); len = strlen(str1); strcpy(str2, ","); // change the tokenizer string printf("\n"); printf("String to tokenize str1 = \"%s\" len = %u\n", str1, len); printf("String of delimiters str2 = \"%s\" \n", str2); p2str = str1; p2tok = str1; while (p2tok && len) { printf(" p2tok = strtok_s(p2str, &len, str2, &p2str); \n"); p2tok = strtok_s(p2str, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); } */ /*--------------------------------------------------*/ /* strcpy(str1, ",.*;one,two;three,;four*.*.five-six***"); len = strlen(str1); strcpy(str2, ",.;*"); printf("\n"); printf("String to tokenize str1 = \"%s\" len = %u\n", str1, len); printf("String of delimiters str2 = \"%s\" \n", str2); printf(" p2tok = strtok_s(str1, &len, str2, &p2str); \n"); p2tok = strtok_s(str1, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); printf(" p2tok = strtok_s(NULL, &len, str2, &p2str); \n"); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); printf(" p2tok = strtok_s(NULL, &len, str2, &p2str); \n"); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); printf(" p2tok = strtok_s(NULL, &len, str2, &p2str); \n"); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); printf(" p2tok = strtok_s(NULL, &len, str2, &p2str); \n"); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); printf(" p2tok = strtok_s(NULL, &len, str2, &p2str); \n"); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); // len is zero at this point printf(" p2tok = strtok_s(NULL, &len, str2, &p2str); \n"); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); printf("\n"); */ /*--------------------------------------------------*/ /* strcpy(str1, ",.*;one,two;three,;four*.*.five-six***"); len = strlen(str1); strcpy(str2, ",.;*"); printf("\n"); printf("String to tokenize str1 = \"%s\" len = %u\n", str1, len); printf("String of delimiters str2 = \"%s\" \n", str2); p2str = str1; p2tok = str1; while (p2tok && len) { printf(" p2tok = strtok_s(p2str, &len, str2, &p2str); \n"); p2tok = strtok_s(p2str, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); } */ /*--------------------------------------------------*/ /* strcpy(str1, ",.*;one,two;three,;four*.*.five-six***"); len = strlen(str1) - 1; // back off the null strcpy(str2, ",.;*"); printf("\n"); printf("String to tokenize str1 = \"%s\" len = %u\n", str1, len); printf("String of delimiters str2 = \"%s\" \n", str2); p2str = str1; p2tok = str1; while (p2tok && len) { printf(" p2tok = strtok_s(p2str, &len, str2, &p2str); \n"); p2tok = strtok_s(p2str, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); } */ /*--------------------------------------------------*/ /* strcpy(str1, ",.*;one,two;three,;four*.*.five-six***"); len = strlen(str1) - 15; // back off a few! strcpy(str2, ",.;*"); printf("\n"); printf("String to tokenize str1 = \"%s\" len = %u\n", str1, len); printf("String of delimiters str2 = \"%s\" \n", str2); p2str = str1; p2tok = str1; while (p2tok && len) { printf(" p2tok = strtok_s(p2str, &len, str2, &p2str); \n"); // p2tok = strtok_s(p2str, &len, str2, &p2str); p2tok = strtok_s(NULL, &len, str2, &p2str); printf(" token -%s- -%s- len=%d \n", p2tok, p2str, (int)len ); } */ /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strtolowercase_s.c0000644000000000000000000000641614210363175022567 0ustar 00000000000000/*------------------------------------------------------------------ * test_strtolowercase_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strtolowercase_s() { errno_t rc; rsize_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; rc = strtolowercase_s(NULL, len); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; rc = strtolowercase_s("test", len); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 99999; rc = strtolowercase_s("test", len); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy(str, "N"); len = strlen(str); rc = strtolowercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (strcmp(str, "n") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy(str, "n"); len = strlen(str); rc = strtolowercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (strcmp(str, "n") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy(str, "NOWISTHETIM3"); rc = strtolowercase_s(str, 25); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (strcmp(str, "nowisthetim3") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy(str, "NOWISTHETIME"); len = strlen(str); rc = strtolowercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (strcmp(str, "nowisthetime") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy(str, "qqeRo"); len = strlen(str); rc = strtolowercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (strcmp(str, "qqero") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy(str, "1234"); len = strlen(str); rc = strtolowercase_s(str, 4); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strtouppercase_s.c0000644000000000000000000000713414210363175022570 0ustar 00000000000000/*------------------------------------------------------------------ * test_strtouppercase_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strtouppercase_s() { errno_t rc; rsize_t len; char str[LEN]; /*--------------------------------------------------*/ len = 5; //printf("debug - 01\n"); rc = strtouppercase_s(NULL, len); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ len = 0; //printf("debug - 02\n"); rc = strtouppercase_s("test", len); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* empty string */ len = 5; //printf("debug - 03\n"); rc = strtouppercase_s("", len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* FIXME: known bug: this test causes a bus error if the string max size is not restricted via RSIZE_MAX_STR */ len = 99999; //printf("debug - 04\n"); rc = strtouppercase_s("test", len); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ strcpy (str, "n"); len = strlen(str); //printf("debug - 05\n"); rc = strtouppercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } //printf("debug - 06\n"); if (strcmp(str, "N") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy (str, "N"); len = strlen(str); //printf("debug - 07\n"); rc = strtouppercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } //printf("debug - 08\n"); if (strcmp(str, "N") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy (str, "nowisthetime"); len = strlen(str); //printf("debug - 09\n"); rc = strtouppercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } //printf("debug - 10\n"); if (strcmp(str, "NOWISTHETIME") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy (str, "qqeRo"); len = strlen(str); //printf("debug - 11\n"); rc = strtouppercase_s(str, len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } //printf("debug - 12\n"); if (strcmp(str, "QQERO") ) { printf("%s %u Error -%s- \n", __FUNCTION__, __LINE__, str); } /*--------------------------------------------------*/ strcpy (str, "1234"); len = strlen(str); //printf("debug - 13\n"); rc = strtouppercase_s(str, 22); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_strzero_s.c0000644000000000000000000000615214210363175021214 0ustar 00000000000000/*------------------------------------------------------------------ * test_strzero_s * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) int test_strzero_s() { errno_t rc; rsize_t max_len; char str1[LEN]; uint32_t i; /*--------------------------------------------------*/ rc = strzero_s(NULL, 5); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strzero_s(str1, 0); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ rc = strzero_s(str1, RSIZE_MAX_STR+1); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ max_len = 1; rc = strzero_s(str1, max_len); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } for (i=0; i src) * TC11: Test copy string over NULL string (dest < src) * * TEST WHEN DEST BUFFER >= SOURCE BUFFER * TC 8: Test src buffer runs into beginning of dest buffer (src buffer is unterminated or been destroyed by copy) * TC14: Test for not enough space in destination (src < dest) * TC15: Test copy of string - just enough space in dest * TC17: Test copy with not enough room for final NULL in destination * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128 ) #define LEN ( 128 ) static wchar_t str1[LEN]; static wchar_t str2[LEN]; extern wchar_t *wcpcpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, errno_t *err); extern errno_t wcscpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src); extern rsize_t wcsnlen_s (const wchar_t *dest, rsize_t dmax); int test_wcpcpy_s (void) { wchar_t *ret; errno_t rc; uint32_t i; int32_t ind; rsize_t sz; unsigned int testno = 0; printf("\nTesting wcpcpy_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); ret = wcpcpy_s(NULL, LEN, str2, &rc); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 2 Test for zero length destination */ printf("Test #%d:\n", ++testno); ret = wcpcpy_s(str1, 0, str2, &rc); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 3 Test for too large destination size */ printf("Test #%d:\n", ++testno); ret = wcpcpy_s(str1, (RSIZE_MAX_STR+1), str2, &rc); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 4 Test for NULL source check */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = wcpcpy_s(str1, 5, NULL, &rc); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[0] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 5 Test for Src is same as dest, but source too long */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = wcpcpy_s(str1, 5, str1, &rc); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 6 Test copy the same string onto itself */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ret = wcpcpy_s(str1, LEN, str1, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != L'\0' || ret != str1+wcsnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 7 Test for string overlap, destination < src, and * dest overlaps onto the src string, so a copy would * change the src string */ printf("Test #%d:\n", ++testno); wcscpy_s(&str1[0], LEN, L"keep it simple"); sz = wcsnlen_s(str1, LEN); ret = wcpcpy_s(&str1[0], LEN, &str1[5], &rc); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i -%ls- (smax=%lu) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } if (ret == NULL || ret[0] != L'\0' || ret != str1+wcsnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 12 Test for accurate subString copy over existing string */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"xxxxxxxxxx"); wcscpy_s(str2, LEN, L"abcde"); ret = wcpcpy_s(str1, LEN, str2, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != L'\0' || ret != str1+wcsnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } sz = wcsnlen_s(str1, LEN); if (sz != 5) { printf("%s %u (sz=%lu <> 5) Error rc=%u \n", __FUNCTION__, __LINE__, sz, rc ); } rc = memcmp_s(str1, LEN, str2, (6)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- <> -%ls- (size=%lu) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } /*--------------------------------------------------*/ /* 13 Test for not enough space in destination (dest < src) */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"qqweqeqeqeq"); wcscpy_s(str2, LEN, L"keep it simple"); sz = wcsnlen_s(str2, LEN); ret = wcpcpy_s(str1, 14, str2, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str1 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 14 Test for not enough space in destination (src < dest) */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"qqweqeqeqeq"); wcscpy_s(str2, LEN, L"keep it simple"); sz = wcsnlen_s(str2, LEN); ret = wcpcpy_s(str2, 6, str1, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str2 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 15 Test for just enough space in destination */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"qqweqeqeqeq"); wcscpy_s(str1, LEN, L"it"); ret = wcpcpy_s(str2, 3, str1, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (3)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } if (ret == NULL || ret[0] != L'\0' || ret != str2+wcsnlen_s(str2, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 16 Test copy short string over long string */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"qq12345weqeqeqeq"); wcscpy_s(str2, LEN, L"it"); ret = wcpcpy_s(str1, 10, str2, &rc); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret == NULL || ret[0] != L'\0' || ret != str1+wcsnlen_s(str1, LEN) ) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (3)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 17 Test for not enough space in destination for final NULL */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"qqweqeqeqeq"); wcscpy_s(str1, LEN, L"it"); sz = wcsnlen_s(str2, LEN); ret = wcpcpy_s(str2, 2, str1, &rc); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (ret != NULL) { printf("Returned pointer incorrect: %s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str2 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_wcscat_s.c0000644000000000000000000003010114210363175020757 0ustar 00000000000000/*------------------------------------------------------------------ * test_wcscat_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) static wchar_t str1[LEN]; static wchar_t str2[LEN]; extern rsize_t wcsnlen_s (const wchar_t *dest, rsize_t dmax); extern errno_t wcscpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src); extern errno_t wcscat_s(wchar_t* dest, rsize_t dmax, const wchar_t* src); int test_wcscat_s (void) { errno_t rc; int32_t ind; int32_t len1; int32_t len2; int32_t len3; unsigned int testno = 0; printf("\nTesting wcscat_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); rc = wcscat_s(NULL, LEN, str2); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 2 Test for NULL source check */ printf("Test #%d:\n", ++testno); rc = wcscat_s(str1, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 3 Test zero maximum length of destination */ printf("Test #%d:\n", ++testno); rc = wcscat_s(str1, 0, str2); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 4 Test Exceed Maximum size of destination */ printf("Test #%d:\n", ++testno); rc = wcscat_s(str1, (RSIZE_MAX_STR+1), str2); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 5 Test overlapping destination string into the beginning of the src */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"12345678901234567890"); rc = wcscat_s(str1, 8, &str1[7]); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 6 Test too small size - destination appears unterminated */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"aaaaaaaaaa"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str1, 1, str2); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 7 Test length of destination appears unterminated */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"aaaaaaaaaa"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str1, 10, str2); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 8 Test overlap of destination buffer into source after copying begins */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"keep it simple"); wcscpy_s(&str1[20], LEN, L"aaaaaaaaaaaaaaaaaaaa"); rc = wcscat_s(str1, 30, &str1[20]); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 9 Test Verify proper size of concatenated strings */ printf("Test #%d:\n", ++testno); wcscpy_s(&str1[0], LEN, L"aaaaaaaaaa"); wcscpy_s(&str2[0], LEN, L"keep it simple"); len1 = wcsnlen_s(str1, LEN); len2 = wcsnlen_s(str2, LEN); rc = wcscat_s(str1, 50, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } len3 = wcsnlen_s(str1, LEN); if (len3 != (len1+len2)) { printf("%s %u lengths wrong: %u %u %u \n", __FUNCTION__, __LINE__, len1, len2, len3); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 10 Test NULL string is destination - too short */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str1, 1, str2); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 11 Test NULL string is destination - too short */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str1, 11, str2); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 12 Test NULL string is destination - proper result */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str1, 20, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str1, LEN, str2, wcsnlen_s(str2, LEN)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 13 Test concat two NULL strings */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; str2[0] = '\0'; rc = wcscat_s(str1, LEN, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 14 Test concat NULL string to existing string - proper result */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str2, LEN, str1); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"keep it simple", (15)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 15 Test concat two strings - proper result */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"qqweqq"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str1, LEN, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str1, LEN, L"qqweqqkeep it simple", (20)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 16 Test concat two strings - not enough space in dest */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"1234"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str2, 16, str1); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 17 Test concat two strings - just enough space in the destination */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"1234"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcscat_s(str2, 19, str1); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"keep it simple1234", (19)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 18 Test source overlaps into the dest string after copying begins */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"123456789123456789"); wcscpy_s(&str1[13], LEN, L"ABCDEFGHIJKLMNOP123456789"); rc = wcscat_s(&str1[13], LEN, str1); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[13] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 19 Test normal string concat */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"123"); wcscpy_s(str1, LEN, L"keep it simple"); rc = wcscat_s(str2, 31, &str1[0]); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"123keep it simple", (17)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 20 Test normal string concat - just enough room */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"1234"); wcscpy_s(str1, LEN, L"56789"); rc = wcscat_s(str2, 10, str1); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"123456789", (9)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 21 Test normal string concat - not enough room for NULL */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"1234"); wcscpy_s(str1, LEN, L"56789"); rc = wcscat_s(str2, 9, str1); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str2[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_wcscpy_s.c0000644000000000000000000003267714210363175021027 0ustar 00000000000000/*------------------------------------------------------------------ * test_wcscpy_s * * September 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 3: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * TC 4: Test for third parameter, source char string, being sent in as NULL * * TEST WHEN SRC & DEST ARE THE SAME * TC 5: Test for src=dest, but string too long for dmax * TC 6: Test for src=dest, proper return * * TEST WHEN DEST BUFFER < SOURCE BUFFER * TC 7: Test for overlap of dest buffer into src buffer (src string too long) * TC12: Test for proper copy of short string over long string * TC13: Test for not enough space in destination (dest < src) * TC16: Test copy short string over long string * * TEST NON-STANDARD FAILURE CONDITIONS FOR NULL DEST STRINGS * TC 9: Test copy null string over destination string * TC10: Test copy NULL string over existing string (dest > src) * TC11: Test copy string over NULL string (dest < src) * * TEST WHEN DEST BUFFER >= SOURCE BUFFER * TC 8: Test src buffer runs into beginning of dest buffer (src buffer is unterminated or been destroyed by copy) * TC14: Test for not enough space in destination (src < dest) * TC15: Test copy of string - just enough space in dest * TC17: Test copy with not enough room for final NULL in destination * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128*4 ) #define LEN ( 128*4 ) static wchar_t str1[LEN]; static wchar_t str2[LEN]; extern errno_t wcscpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src); int test_wcscpy_s (void) { wchar_t *ret; errno_t rc; uint32_t i; int32_t ind; rsize_t sz; rsize_t sz_orig; unsigned int testno = 0; printf("\nTesting wcscpy_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); rc = wcscpy_s(NULL, LEN, str2); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 2 Test for zero length destination */ printf("Test #%d:\n", ++testno); rc = wcscpy_s(str1, 0, str2); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 3 Test for too large destination size */ printf("Test #%d:\n", ++testno); rc = wcscpy_s(str1, (RSIZE_MAX_STR+1), str2); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 4 Test for NULL source check */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaa", 5); rc = wcscpy_s(str1, 5, NULL); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[0] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 5 Test for Src is same as dest, but source too long */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 42); rc = wcscpy_s(str1, 5, str1); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 6 Test copy the same string onto itself */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 42); rc = wcscpy_s(str1, LEN, str1); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 7 Test for string overlap, destination < src, and * dest overlaps onto the src string, so a copy would * change the src string */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"keep it simple--keep it simple--keep it simple", 47); rc = wcscpy_s(&str1[0], LEN, &str1[5]); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i -%ls-\n", __FUNCTION__, __LINE__, str2, str1); } /*--------------------------------------------------*/ /* 11 Test copying string over the NULL string */ printf("Test #%d:\n", ++testno); memset_s(str1, '\0', 50); wmemcpy_s(str2, LEN, L"keep it simple--keep it simple--keep it simple", 47); sz = wcsnlen_s(str2, LEN); rc = wcscpy_s(str1, LEN, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (sz)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- <> -%ls- (smax=%lu) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } /*--------------------------------------------------*/ /* 12 Test for accurate subString copy over existing string */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'x', 20); wmemcpy_s(str2, LEN, L"keep it simple", 15); sz_orig = wcsnlen_s(str2, LEN); rc = wcscpy_s(str1, LEN, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } sz = wcsnlen_s(str1, LEN); if (sz != sz_orig && sz == 14) { printf("%s %u (sz=%lu <> 5) Error rc=%u \n", __FUNCTION__, __LINE__, sz, rc ); } rc = memcmp_s(str1, LEN, str2, (sz)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- <> -%ls- (size=%lu) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } /*--------------------------------------------------*/ /* 13 Test for not enough space in destination (dest < src) */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'x', 20); wmemcpy_s(str2, LEN, L"keep it simple", 15); rc = wcscpy_s(str1, 14, str2); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str1 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 14 Test for not enough space in destination (src < dest) */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'x', 20); wmemcpy_s(str2, LEN, L"keep it simple", 15); rc = wcscpy_s(str2, 6, str1); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str2 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 15 Test for just enough space in destination */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"it", 3); wmemcpy_s(str2, LEN, L"qqweqeqeqeq", 12); rc = wcscpy_s(str2, 3, str1); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (3)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 16 Test copy short string over long string */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"qq12345weqeqeqeq", 17); wmemcpy_s(str2, LEN, L"it", 3); sz_orig = wcsnlen_s(str2, LEN); rc = wcscpy_s(str1, 10, str2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (3)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 17 Test for not enough space in destination for final NULL */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"it", 3); wmemcpy_s(str2, LEN, L"qqweqeqeqeq", 12); sz = wcsnlen_s(str2, LEN); rc = wcscpy_s(str2, 2, str1); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str2 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_wcsncat_s.c0000644000000000000000000003702614210363175021152 0ustar 00000000000000/*------------------------------------------------------------------ * test_wcsncat_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for third parameter, source char string, being sent in as NULL * TC 3: Test for last parameter, source length (slen), being larger than the maximum allowed size * TC 4: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 5: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * * TEST WHEN DEST BUFFER < SOURCE BUFFER * TC 6: Test for searching end of dest buffer runs into the src buffer (buffers overlap) * TC 7: Test for dest buffer unterminated in dmax characters * TC 8: Test for overlap of dest buffer into src buffer after copying from source begins * TC 9: Test for proper concatenation of only slen characters from source string * TC10: Test for proper concatenation of two strings * * TEST NON-STANDARD FAILURE CONDITIONS FOR NULL DEST STRINGS * TC 11: Test null string destination and size too short * TC 12: Test null string destination and dmax size is one character too short * TC 13: Test for proper concatenation into a NULL string of appropriate buffer size * TC 14: Test concatenation of two NULL strings * TC 15: Test concatenation of NULL string onto end of existing string * * TEST WHEN DEST BUFFER >= SOURCE BUFFER * TC16: Test concatenation of two strings - proper result * TC17: Test for dest buffer unterminated in dmax characters * TC18: Test for not enough space in dest buffer to fit src buffer characters * TC19: Test src buffer runs into beginning of dest buffer (src buffer is unterminated or been destroyed by copy) * TC20: Test concatenation with just enough space in the destination buffer * TC21: Test for proper concatenation of only slen characters from source string * TC22: Test concatenation with not enough room for final NULL in destination * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define LEN ( 128 ) static wchar_t str1[LEN]; static wchar_t str2[LEN]; extern rsize_t wcsnlen_s (const wchar_t *dest, rsize_t dmax); extern errno_t wcscpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src); extern errno_t wcsncat_s (wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t slen); int test_wcsncat_s (void) { errno_t rc; int32_t ind; int32_t len1; int32_t len2; int32_t len3; unsigned int testno = 0; printf("\nTesting wcsncat_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); rc = wcsncat_s(NULL, LEN, str2, LEN); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 2 Test for NULL source check */ printf("Test #%d:\n", ++testno); rc = wcsncat_s(str1, LEN, NULL, LEN); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 3 Test Exceed Maximum possible size of source */ printf("Test #%d:\n", ++testno); rc = wcsncat_s(str1, LEN, str2, (RSIZE_MAX_STR+1)); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 4 Test zero maximum length of destination */ printf("Test #%d:\n", ++testno); rc = wcsncat_s(str1, 0, str2, LEN); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /* 5 Test Exceed Maximum size of destination */ printf("Test #%d:\n", ++testno); rc = wcsncat_s(str1, (RSIZE_MAX_STR+1), str2, LEN); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 6 Test destination buffer overlaps into the src buffer */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"aaaaaaaaaa keep it simple"); rc = wcsncat_s(str1, LEN, &str1[11], LEN); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 7 Test length of destination appears unterminated */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"keep it simple"); rc = wcsncat_s(str1, 2, &str1[20], LEN); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 8 Test overlap of destination buffer into source after copying begins */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"keep it simple"); wcscpy_s(&str1[20], LEN, L"aaaaaaaaaaaaaaaaaaaa"); rc = wcsncat_s(str1, 30, &str1[20], LEN); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 9 Test proper concatenated of at most slen characters */ printf("Test #%d:\n", ++testno); wcscpy_s(&str1[0], LEN, L"aaaaaaaaaa"); wcscpy_s(&str2[0], LEN, L"keep it simple"); len1 = wcsnlen_s(str1, LEN); len2 = 10; rc = wcsncat_s(str1, 50, str2, len2); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } len3 = wcsnlen_s(str1, LEN); if (len3 != (len1+len2)) { printf("%s %u lengths wrong: %u %u %u \n", __FUNCTION__, __LINE__, len1, len2, len3); } rc = memcmp_s(str1, LEN, L"aaaaaaaaaakeep it si", (len3+1)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 10 Test Verify proper size of concatenated strings & value of concatenated string */ printf("Test #%d:\n", ++testno); wcscpy_s(&str1[0], LEN, L"aaaaaaaaaa"); wcscpy_s(&str2[0], LEN, L"keep it simple"); len1 = wcsnlen_s(str1, LEN); len2 = wcsnlen_s(str2, LEN); rc = wcsncat_s(str1, 50, str2, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } len3 = wcsnlen_s(str1, LEN); if (len3 != (len1+len2)) { printf("%s %u lengths wrong: %u %u %u \n", __FUNCTION__, __LINE__, len1, len2, len3); } rc = memcmp_s(str1, LEN, L"aaaaaaaaaakeep it simple", (len3+1)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 11 Test NULL string is destination - too short */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str1, 1, str2, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 12 Test NULL string is destination - too short */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str1, 14, str2, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 13 Test NULL string is destination - proper result */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str1, 20, str2, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str1, LEN, str2, wcsnlen_s(str2, LEN)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 14 Test concat two NULL strings */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; str2[0] = '\0'; rc = wcsncat_s(str1, LEN, str2, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 15 Test concat NULL string to existing string - proper result */ printf("Test #%d:\n", ++testno); str1[0] = '\0'; wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str2, LEN, str1, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"keep it simple", (15)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 16 Test concat two strings - proper result */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"qqweqq"); wcscpy_s(str1, LEN, L"keep it simple"); rc = wcsncat_s(str2, LEN, str1, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"qqweqqkeep it simple", (20)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 17 Test concat two strings - dest appears unterminated */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"1234"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str2, 12, str1, LEN); if (rc != ESUNTERM) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str2[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 18 Test concat two strings - not enough space in dest */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"1234"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str2, 16, str1, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str2[0] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 19 Test overlapping destination string into the beginning of the src */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"12345678901234567890"); rc = wcsncat_s(&str1[7], LEN, str1, LEN); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str1[7] != '\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ /* 20 Test concat two strings - just enough space in the destination */ printf("Test #%d:\n", ++testno); wcscpy_s(str1, LEN, L"1234"); wcscpy_s(str2, LEN, L"keep it simple"); rc = wcsncat_s(str2, 19, str1, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"keep it simple1234", (19)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 21 Test copy at most slen characters from src string */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"123456789"); wcscpy_s(str1, LEN, L"keep it simple"); rc = wcsncat_s(str2, LEN, str1, 7); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } rc = memcmp_s(str2, LEN, L"123456789keep it", (17)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- \n", __FUNCTION__, __LINE__, str1); } /*--------------------------------------------------*/ /* 22 Test normal string concat - no enough room for NULL */ printf("Test #%d:\n", ++testno); wcscpy_s(str2, LEN, L"1234"); wcscpy_s(str1, LEN, L"56789"); rc = wcsncat_s(str2, 9, str1, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc); } if (str2[0] != L'\0') { printf("%s %u Expected null \n", __FUNCTION__, __LINE__); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_wcsncpy_s.c0000644000000000000000000003677314210363175021206 0ustar 00000000000000/*------------------------------------------------------------------ * test_wcsncpy_s * * September 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 3: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * TC 4: Test for third parameter, source char string, being sent in as NULL * TC 5: Test for last parameter, source length (slen), being sent in as zero * TC 6: Test for last parameter, source length (slen), being larger than the maximum allowed size * * TEST WHEN SRC & DEST ARE THE SAME * TC 7: Test for src=dest, overlapping buffers not the same * * TEST WHEN DEST BUFFER < SOURCE BUFFER * TC 8: Test for overlap of dest buffer into src buffer * TC 9: Test copy only slen characters from src into dest (src string longer than provided length) * TC10: Test for copy dest < src, and copy ends after copy NULL char (slen > char string) * TC11: Test for copy dest < src, but dmax too small to hold src string * TC16: Test for accurate String copy over existing string (src > dest) * * TEST WHEN DEST BUFFER >= SOURCE BUFFER * TC12: Test overlapping buffers fails ( dest > src ) * TC13: Test copy only slen characters from src into dest (dest > src) * TC14: Test for copy src < dest, and copy ends after copy NULL char (slen > char string) * TC15: Test for copy src < dest, but dmax too small to hold src string * TC17: Test for just enough space in destination (src < dest) * TC18: Test for not enough space in destination for final NULL (dest > src) * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128*4 ) #define LEN ( 128*4 ) static wchar_t str1[LEN]; static wchar_t str2[LEN]; extern errno_t wcsncpy_s(wchar_t* dest, rsize_t dmax, const wchar_t* src, rsize_t slen); extern rsize_t wcsnlen_s(const wchar_t *dest, rsize_t dmax); extern errno_t wmemset_s (wchar_t *dest, wchar_t value, rsize_t len); int test_wcsncpy_s (void) { wchar_t *ret; errno_t rc; uint32_t i; int32_t ind; rsize_t sz; rsize_t sz_orig; unsigned int testno = 0; printf("\nTesting wcsncpy_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); rc = wcsncpy_s(NULL, LEN, str2, LEN); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 2 Test for zero length destination */ printf("Test #%d:\n", ++testno); rc = wcsncpy_s(str1, 0, str2, LEN); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 3 Test for too large destination size */ printf("Test #%d:\n", ++testno); rc = wcsncpy_s(str1, (RSIZE_MAX_STR+1), str2, LEN); if (rc != ESLEMAX) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 4 Test for NULL source check */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaa", 5); rc = wcsncpy_s(str1, 5, NULL, LEN); if (rc != ESNULLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[0] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 5 Test for zero length source */ printf("Test #%d:\n", ++testno); rc = wcsncpy_s(str1, LEN, str2, 0); if (rc != ESZEROL) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i -%ls-\n", __FUNCTION__, __LINE__, str1, str2); } /*--------------------------------------------------*/ /* 10 Test for copy src > dest, and copy ends after copy NULL char (slen > char string) */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'\0', 20); wmemcpy_s(str2, LEN, L"keep it simple--keep it simple--keep it simple", 47); sz = wcsnlen_s(str2, LEN); rc = wcsncpy_s(str1, LEN, str2, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[sz] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (sz+1)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- <> -%ls-\n", __FUNCTION__, __LINE__, str1, str2); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 11 Test for copy src > dest, but dmax too small to hold src string */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'\0', 20); wmemcpy_s(str2, LEN, L"keep it simple--keep it simple--keep it simple", 47); sz = wcsnlen_s(str2, LEN); rc = wcsncpy_s(str1, (sz-5), str2, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[0] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 12 Test overlapping buffers fails (dest > src ) */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 42); rc = wcsncpy_s(&str1[5], LEN, str1, 30); if (rc != ESOVRLP) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str1[5] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 13 Test copy only slen characters from src into dest */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"keep it simple--keep it simple--keep it simple", 47); wmemset_s(str2, L'\0', 20); rc = wcsncpy_s(str2, LEN, str1, 17); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str2[16] == L'\0' && str2[17] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (17)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- <> -%ls-\n", __FUNCTION__, __LINE__, str1, str2); } /*--------------------------------------------------*/ /* 14 Test for copy src < dest, and copy ends after copy NULL char (slen > char string) */ printf("Test #%d:\n", ++testno); wmemset_s(str2, L'\0', 20); wmemcpy_s(str1, LEN, L"keep it simple--keep it simple--keep it simple", 47); sz = wcsnlen_s(str1, LEN); rc = wcsncpy_s(str2, LEN, str1, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (str1[sz] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str2, LEN, str1, (sz+1)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u Error -%ls- <> -%ls-\n", __FUNCTION__, __LINE__, str2, str1); } /*--------------------------------------------------*/ /*--------------------------------------------------*/ /* 15: Test for copy src < dest, but dmax too small to hold src string */ printf("Test #%d:\n", ++testno); wmemset_s(str2, L'\0', 20); wmemcpy_s(str1, LEN, L"keep it simple--keep it simple--keep it simple", 47); sz = wcsnlen_s(str1, LEN); rc = wcsncpy_s(str2, (sz-5), str1, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #ifdef SAFE_LIB_STR_NULL_SLACK for (i=0; i<5; i++) { if (str1[i] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } } #else if (str2[0] != L'\0') { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } #endif /*--------------------------------------------------*/ /* 16: Test for accurate String copy over existing string */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'x', 20); wmemcpy_s(str2, LEN, L"keep it simple", 15); sz_orig = wcsnlen_s(str2, LEN); rc = wcsncpy_s(str1, LEN, str2, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } sz = wcsnlen_s(str1, LEN); if (sz != sz_orig && sz == 14) { printf("%s %u (sz=%lu <> 5) Error rc=%u \n", __FUNCTION__, __LINE__, sz, rc ); } rc = memcmp_s(str1, LEN, str2, (sz)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- <> -%ls- (size=%lu) Error rc=%u \n", __FUNCTION__, __LINE__, str1, str2, sz, rc ); } /*--------------------------------------------------*/ /* 17: Test for just enough space in destination */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"it", 3); wmemcpy_s(str2, LEN, L"qqweqeqeqeq", 12); rc = wcsncpy_s(str2, 3, str1, LEN); if (rc != EOK) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } rc = memcmp_s(str1, LEN, str2, (3)*sizeof(wchar_t), &ind ); if (ind != 0) { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ /* 18: Test for not enough space in destination for final NULL */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"it", 3); wmemcpy_s(str2, LEN, L"qqweqeqeqeq", 12); sz = wcsnlen_s(str2, LEN); rc = wcsncpy_s(str2, 2, str1, LEN); if (rc != ESNOSPC) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } if (*str2 != L'\0') { printf("%s %u -%ls- Error rc=%u \n", __FUNCTION__, __LINE__, str1, rc ); } /*--------------------------------------------------*/ return (0); } tboot-1.10.5/safestringlib/unittests/test_wcsnlen_s.c0000644000000000000000000001165414210363175021160 0ustar 00000000000000/*------------------------------------------------------------------ * test_wcsnlen_s * * September 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 3: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * TC 4: Test for third parameter, source char string, being sent in as NULL * * * * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_str_lib.h" #define MAX ( 128*4 ) #define LEN ( 128*4 ) static wchar_t str1[LEN]; extern rsize_t wcsnlen_s(const wchar_t *dest, rsize_t dmax); extern errno_t wmemset_s (wchar_t *dest, wchar_t value, rsize_t len); int test_wcsnlen_s (void) { errno_t rc; unsigned int testno = 0; printf("\nTesting wcsnlen_s:\n"); /*--------------------------------------------------*/ /* 1 Test for NULL destination check */ printf("Test #%d:\n", ++testno); rc = wcsnlen_s(NULL, LEN); if (rc != 0) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 2 Test for too large maximum size */ printf("Test #%d:\n", ++testno); rc = wcsnlen_s(str1, (RSIZE_MAX_STR+1)); if (rc != 0) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 3 Test for length is equal to maximum */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 42); rc = wcsnlen_s(str1, 41); if (rc != 40) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 4 Test for return length is equal to dmax */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 42); rc = wcsnlen_s(str1, 20); if (rc != 20) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 5 Test for zero length string */ printf("Test #%d:\n", ++testno); wmemset_s(str1, L'\0', 42); rc = wcsnlen_s(str1, LEN); if (rc != 0) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 6 Test for single character string */ printf("Test #%d:\n", ++testno); memset_s(str1, '\0', 50); str1[0] = L'A'; rc = wcsnlen_s(str1, LEN); if (rc != 1) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } /*--------------------------------------------------*/ /* 7 Test for two char string */ printf("Test #%d:\n", ++testno); wmemcpy_s(str1, LEN, L"12", 3); rc = wcsnlen_s(str1, LEN); if (rc != 2) { printf("%s %u Error rc=%u \n", __FUNCTION__, __LINE__, rc ); } return (0); } tboot-1.10.5/safestringlib/unittests/test_wmemcmp_s.c0000644000000000000000000002676614210363175021166 0ustar 00000000000000/*------------------------------------------------------------------ * test_wcsncat_s.c * * August 2014, D Wheeler * * Copyright (c) 2014 by Intel Corp * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. *------------------------------------------------------------------ *------------------------------------------------------------------ * TEST COVERAGE NOTES * * The following notes describe the purpose of the test cases in * order to ensure full coverage of all return paths in the code to * be tested, as well as test for security concerns in the target. * The test methodology is to perfrom branch-coverage testing to ensure * all exit paths from the code have been tested. Additional tests are added to * perform some corner case validation of certain more complex branches * to verify no side-effects or missing corners are introduced in the code. * * BASIC PARAMETER VALIDATION * TC 1: Test for first parameter, destination char string, being sent in as NULL * TC 2: Test for third parameter, source char string, being sent in as NULL * TC 3: Test for last parameter, indicator, being sent in as NULL * TC 4: Test for second parameter, dest maximum length (dmax), being sent in as zero * TC 5: Test for last parameter, source maximum (smax), being sent in as zero * TC 6: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size * TC 7: Test for last parameter, source length (smax), being larger than the maximum allowed size * * * TC 8: Test for single character equality comparison - proper result * TC 9: Test for two character equality comparison - proper result * TC10: Test for long string character equality comparison - proper result * TC11: Test long string many differences - s1 < s2 at index 10 * TC12: Test long string many differences - s1 < s2 at index 10 * TC13: Test long string - single char greater than difference at index 1 * TC14: Test long string - single char less than difference at index 1 * TC15: Test long string - single char greater than difference at end of string * TC16: Test long string - single char less than difference at end of string * *------------------------------------------------------------------ */ #include "test_private.h" #include "safe_mem_lib.h" #define LEN ( 128 ) extern errno_t wmemcmp_s (const wchar_t *dest, rsize_t dmax, const wchar_t *src, rsize_t smax, int *diff); int test_wmemcmp_s() { errno_t rc; uint32_t len; int32_t ind; uint32_t i; wchar_t mem1[LEN]; wchar_t mem2[LEN]; unsigned int testno = 0; printf("\nTesting wmemcmp_s:\n"); /*--------------------------------------------------*/ /* 1: Test for first parameter, destination char string, being sent in as NULL */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(NULL, LEN, mem2, LEN, &ind); if (rc != ESNULLP) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 2: Test for third parameter, source char string, being sent in as NULL */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(mem1, LEN, NULL, LEN, &ind); if (rc != ESNULLP) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 3: Test for last parameter, indicator, being sent in as NULL */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(mem1, LEN, mem2, LEN, NULL); if (rc != ESNULLP) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 4: Test for second parameter, dest maximum length (dmax), being sent in as zero */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(mem1, 0, mem2, LEN, &ind); if (rc != ESZEROL) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 5: Test for last parameter, source maximum (smax), being sent in as zero */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(mem1, LEN, mem2, 0, &ind); if (rc != ESZEROL) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 6: Test for second parameter, dest maximum length (dmax), being larger than the maximum allowed size */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(mem1, RSIZE_MAX_MEM+1, mem2, LEN, &ind); if (rc != ESLEMAX) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 7: Test for last parameter, source length (smax), being larger than the maximum allowed size */ printf("Test #%d:\n", ++testno); rc = wmemcmp_s(mem1, LEN, mem2, RSIZE_MAX_MEM+1, &ind); if (rc != ESLEMAX) { printf("%s %u Ind=%d Error rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 8: Test for single character equality comparison */ printf("Test #%d:\n", ++testno); for (i=0; i s2 at index 10 */ printf("Test #%d:\n", ++testno); for (i=0; i= 0) { printf("%s %u Ind=%d rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 13: Test long string - single char greater than difference at index 1 */ printf("Test #%d:\n", ++testno); for (i=0; i= 0) { printf("%s %u Ind=%d rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 14: Test long string - single char less than difference at index 1 */ printf("Test #%d:\n", ++testno); for (i=0; i= 0) { printf("%s %u Ind=%d rc=%u \n", __FUNCTION__, __LINE__, ind, rc ); } /*--------------------------------------------------*/ /* 16: Test long string - single char less than difference at end of string */ printf("Test #%d:\n", ++testno); for (i=0; i m2=%d \n", __LINE__, i, mem1[i], mem2[i]); } } if (mem1[len] != 33 && mem1[len+1] != 33) { printf("%d - %lu m1[len]=%d m1[len+1]=%d \n", __LINE__, len, mem1[len], mem1[len+1]); } } /*--------------------------------------------------*/ /* 13 Test copying when src buffer overlaps end of destination buffer */ printf("Test #%d:\n", ++testno); for (i=0; i<10; i++) { mem1[i] = 33; } for (i=10; i #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" extern tb_policy_t *g_policy; static bool hash_file(const char *filename, bool unzip, tb_hash_t *hash, uint16_t hash_alg) { FILE *f; static char buf[1024]; int read_cnt; if ( unzip ) f = (FILE *)gzopen(filename, "rb"); else f = fopen(filename, "rb"); if ( f == NULL ) { error_msg("File %s does not exist\n", filename); return false; } const EVP_MD *md; uint8_t* hash_out; EVP_MD_CTX *ctx = EVP_MD_CTX_create(); switch (hash_alg) { case TB_HALG_SHA1: md = EVP_sha1(); hash_out = hash->sha1; break; case TB_HALG_SHA256: md = EVP_sha256(); hash_out = hash->sha256; break; case TB_HALG_SHA384: md = EVP_sha384(); hash_out = hash->sha384; break; case TB_HALG_SHA512: md = EVP_sha512(); hash_out = hash->sha512; break; default: error_msg("unsupported hash alg (%d)\n", hash_alg); EVP_MD_CTX_destroy(ctx); if ( unzip ) { gzclose((gzFile)f); } else { fclose(f); } return false; } EVP_DigestInit(ctx, md); do { if ( unzip ) read_cnt = gzread((gzFile)f, buf, sizeof(buf)); else read_cnt = fread(buf, 1, sizeof(buf), f); if ( read_cnt == 0 ) break; EVP_DigestUpdate(ctx, buf, read_cnt); } while ( true ); EVP_DigestFinal(ctx, hash_out, NULL); if ( unzip ) gzclose((gzFile)f); else fclose(f); EVP_MD_CTX_destroy(ctx); return true; } bool do_show(const param_data_t *params) { /* read the policy file */ if ( !read_policy_file(params->policy_file, NULL) ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } /* this also displays it */ verify_policy(g_policy, calc_policy_size(g_policy), true); return true; } bool do_create(const param_data_t *params) { bool existing_policy = false; /* read the policy file, if it exists */ info_msg("reading existing policy file %s...\n", params->policy_file); if ( !read_policy_file(params->policy_file, &existing_policy) ) { /* this means there was an error reading an existing file */ if ( existing_policy ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } } /* policy_type must be specified for new policy */ if ( !existing_policy && params->policy_type == -1 ) { error_msg("Must specify --policy_type for new policy\n"); return false; } /* if file does not exist then create empty policy */ if ( !existing_policy ) new_policy(params->policy_type, params->policy_control, params->hash_alg); else { error_msg("warning: modifying existing policy file, hash algorithm " "will not be changed\n"); modify_policy(params->policy_type, params->policy_control); } info_msg("writing new policy file...\n"); if ( !write_policy_file(params->policy_file) ) return false; return true; } bool do_add(const param_data_t *params) { /* read the policy file, if it exists */ info_msg("reading existing policy file %s...\n", params->policy_file); if ( !read_policy_file(params->policy_file, NULL) ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } /* see if there is already an entry for this module */ tb_policy_entry_t *pol_entry = find_policy_entry(g_policy, params->mod_num); if ( pol_entry == NULL || pol_entry->mod_num != params->mod_num ) { /* since existing entry whose mod_num is TB_POL_MOD_NUM_ANY will */ /* match, exclude it unless that is what is being added */ pol_entry = add_pol_entry(params->mod_num, params->pcr, params->hash_type); if ( pol_entry == NULL ) { error_msg("cannot add another entry\n"); return false; } } else modify_pol_entry(pol_entry, params->pcr, params->hash_type); /* hash command line and files */ if ( params->hash_type == TB_HTYPE_IMAGE ) { tb_hash_t final_hash, hash; /* hash command line */ info_msg("hashing command line \"%s\"...\n", params->cmdline); hash_buffer((unsigned char *)params->cmdline, strnlen_s(params->cmdline, sizeof(params->cmdline)), &final_hash, g_policy->hash_alg); if ( verbose ) { info_msg("hash is..."); print_hash(&final_hash, g_policy->hash_alg); } /* hash file */ info_msg("hashing image file %s...\n", params->image_file); if ( !hash_file(params->image_file, true, &hash, g_policy->hash_alg) ) { return false; } if ( verbose ) { info_msg("hash is..."); print_hash(&hash, g_policy->hash_alg); } if ( !extend_hash(&final_hash, &hash, g_policy->hash_alg) ){ return false; } if ( verbose ) { info_msg("cumulative hash is..."); print_hash(&final_hash, g_policy->hash_alg); } if ( !add_hash(pol_entry, &final_hash) ) { error_msg("cannot add another hash\n"); return false; } } info_msg("writing new policy file...\n"); if ( !write_policy_file(params->policy_file) ) return false; return true; } bool do_del(const param_data_t *params) { /* read the policy file, if it exists */ info_msg("reading existing policy file %s...\n", params->policy_file); if ( !read_policy_file(params->policy_file, NULL) ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } /* see if there is an entry for this module */ tb_policy_entry_t *pol_entry = find_policy_entry(g_policy, params->mod_num); if ( pol_entry == NULL ) { error_msg("specified mod_num does not exist\n"); return false; } /* if pos was specified, find it */ if ( params->pos != -1 ) { if ( params->pos >= pol_entry->num_hashes ) { error_msg("specified pos does not exist\n"); return false; } /* if entry only has 1 hash, then delete the entire entry */ if ( pol_entry->num_hashes == 1 ) { if ( !del_entry(pol_entry) ) { error_msg("failed to delete entry\n"); return false; } } else { if ( !del_hash(pol_entry, params->pos) ) { error_msg("failed to delete hash\n"); return false; } } } else { if ( !del_entry(pol_entry) ) { error_msg("failed to delete entry\n"); return false; } } info_msg("writing new policy file...\n"); if ( !write_policy_file(params->policy_file) ) return false; return true; } bool do_unwrap(const param_data_t *params) { bool ret = false; /* read the elt file */ info_msg("reading existing elt file %s...\n", params->elt_file); size_t file_len; void *file = read_elt_file(params->elt_file, &file_len); if ( file == NULL ) { error_msg("Error reading elt file %s\n", params->elt_file); return false; } if ( sizeof(lcp_policy_element_t) > file_len ) { error_msg("data is too small\n"); goto exit; } lcp_policy_element_t *elt = (lcp_policy_element_t *)file; if ( file_len != elt->size ) { error_msg("data is too small\n"); goto exit; } if ( elt->type != LCP_POLELT_TYPE_CUSTOM ) { error_msg("Bad element type %u (i.e. non-custom)\n", elt->type); goto exit; } lcp_custom_element_t *custom = (lcp_custom_element_t *)&elt->data; tb_policy_t *pol = (tb_policy_t *)&custom->data; memcpy_s(g_policy, MAX_TB_POLICY_SIZE, pol, calc_policy_size(pol)); info_msg("writing/overwriting policy file...\n"); if ( !write_policy_file(params->policy_file) ) goto exit; ret = true; exit: free(file); file = NULL; return ret; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tb_polgen/hash.c0000644000000000000000000002070014210363175014114 0ustar 00000000000000/* * hash.c: support functions for tb_hash_t type * * Copyright (c) 2006-2008, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" /* * are_hashes_equal * * compare whether two hash values are equal. * */ bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { int diff; if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) { error_msg("Error: hash pointer is zero.\n"); return false; } switch (hash_alg) { case TB_HALG_SHA1: return (memcmp_s(hash1, SHA1_LENGTH, hash2, SHA1_LENGTH, &diff) == EOK && diff == 0); case TB_HALG_SHA256: return (memcmp_s(hash1, SHA256_LENGTH, hash2, SHA256_LENGTH, &diff) == EOK && diff == 0); case TB_HALG_SHA384: return (memcmp_s(hash1, SHA384_LENGTH, hash2, SHA384_LENGTH, &diff) == EOK && diff == 0); case TB_HALG_SHA512: return (memcmp_s(hash1, SHA512_LENGTH, hash2, SHA512_LENGTH, &diff) == EOK && diff == 0); default: error_msg("unsupported hash alg (%d)\n", hash_alg); return false; } } /* * hash_buffer * * hash the buffer according to the algorithm * */ bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { error_msg("Error: There is no space for output hash.\n"); return false; } const EVP_MD *md; uint8_t* hash_out; EVP_MD_CTX *ctx = EVP_MD_CTX_create(); switch (hash_alg) { case TB_HALG_SHA1: md = EVP_sha1(); hash_out = hash->sha1; break; case TB_HALG_SHA256: md = EVP_sha256(); hash_out = hash->sha256; break; case TB_HALG_SHA384: md = EVP_sha384(); hash_out = hash->sha384; break; case TB_HALG_SHA512: md = EVP_sha512(); hash_out = hash->sha512; break; case TB_HALG_SM3: md = EVP_sm3(); hash_out = hash->sm3; break; default: error_msg("unsupported hash alg (%d)\n", hash_alg); return false; } EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, size); EVP_DigestFinal(ctx, hash_out, NULL); EVP_MD_CTX_destroy(ctx); return true; } /* * extend_hash * * perform "extend" of two hashes (i.e. hash1 = SHA(hash1 || hash2) * */ bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { uint8_t buf[2*sizeof(tb_hash_t)]; if ( hash1 == NULL || hash2 == NULL ) { error_msg("Error: There is no space for output hash.\n"); return false; } const EVP_MD *md; EVP_MD_CTX *ctx = EVP_MD_CTX_create(); if ( hash_alg == TB_HALG_SHA1 ) { memcpy_s(buf, sizeof(buf), &(hash1->sha1), sizeof(hash1->sha1)); memcpy_s(buf + sizeof(hash1->sha1), sizeof(buf) - sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1)); md = EVP_sha1(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, 2*sizeof(hash1->sha1)); EVP_DigestFinal(ctx, hash1->sha1, NULL); EVP_MD_CTX_destroy(ctx); } else if ( hash_alg == TB_HALG_SHA256 ) { memcpy_s(buf, sizeof(buf), &(hash1->sha256), sizeof(hash1->sha256)); memcpy_s(buf + sizeof(hash1->sha256), sizeof(buf) - sizeof(hash1->sha256), &(hash2->sha256), sizeof(hash1->sha256)); md = EVP_sha256(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, 2*sizeof(hash1->sha256)); EVP_DigestFinal(ctx, hash1->sha256, NULL); EVP_MD_CTX_destroy(ctx); } else if ( hash_alg == TB_HALG_SHA384 ) { memcpy_s(buf, sizeof(buf), &(hash1->sha384), sizeof(hash1->sha384)); memcpy_s(buf + sizeof(hash1->sha384), sizeof(buf) - sizeof(hash1->sha384), &(hash2->sha384), sizeof(hash1->sha384)); md = EVP_sha384(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, 2*sizeof(hash1->sha384)); EVP_DigestFinal(ctx, hash1->sha384, NULL); EVP_MD_CTX_destroy(ctx); } else if ( hash_alg == TB_HALG_SHA512 ) { memcpy_s(buf, sizeof(buf), &(hash1->sha512), sizeof(hash1->sha512)); memcpy_s(buf + sizeof(hash1->sha512), sizeof(buf) - sizeof(hash1->sha512), &(hash2->sha512), sizeof(hash1->sha512)); md = EVP_sha512(); EVP_DigestInit(ctx, md); EVP_DigestUpdate(ctx, buf, 2*sizeof(hash1->sha512)); EVP_DigestFinal(ctx, hash1->sha512, NULL); EVP_MD_CTX_destroy(ctx); } else { error_msg("unsupported hash alg (%d)\n", hash_alg); return false; } return true; } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { error_msg("NULL"); return; } switch (hash_alg) { case TB_HALG_SHA1: for ( unsigned int i = 0; i < sizeof(hash->sha1); i++ ) { printf("%02x ", hash->sha1[i]); } printf("\n"); break; case TB_HALG_SHA256: for ( unsigned int i = 0; i < sizeof(hash->sha256); i++ ) { printf("%02x ", hash->sha256[i]); } printf("\n"); break; case TB_HALG_SHA384: for ( unsigned int i = 0; i < sizeof(hash->sha384); i++ ) { printf("%02x ", hash->sha384[i]); } printf("\n"); break; case TB_HALG_SHA512: for ( unsigned int i = 0; i < sizeof(hash->sha512); i++ ) { printf("%02x ", hash->sha512[i]); } printf("\n"); break; default: error_msg("unsupported hash alg (%d)\n", hash_alg); } } void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg) { if ( dest_hash == NULL || src_hash == NULL ) { error_msg("hashes are NULL\n"); return; } switch (hash_alg) { case TB_HALG_SHA1: memcpy_s(dest_hash, SHA1_LENGTH, src_hash, SHA1_LENGTH); break; case TB_HALG_SHA256: memcpy_s(dest_hash, SHA256_LENGTH, src_hash, SHA256_LENGTH); break; case TB_HALG_SHA384: memcpy_s(dest_hash, SHA384_LENGTH, src_hash, SHA384_LENGTH); break; case TB_HALG_SHA512: memcpy_s(dest_hash, SHA512_LENGTH, src_hash, SHA512_LENGTH); break; default: error_msg("unsupported hash alg (%d)\n", hash_alg); } } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tb_polgen/param.c0000644000000000000000000004152014210363175014274 0ustar 00000000000000/* * param.c: support functions for parsing command line parameters * * Copyright (c) 2006-2008, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" static const char *help[] = { "tb_polgen --create --type nonfatal|continue|halt\n", " [--alg sha1|sha256 (default)|sha384|sha512]\n", " [--ctrl ]\n", " [--verbose]\n", " \n", "tb_polgen --add --num |any\n", " --pcr |none\n", " --hash any|image\n", " [--cmdline \"command line\"]\n", " [--image ]\n", " [--verbose]\n", " \n", "tb_polgen --del --num |any\n", " [--pos ]\n", " [--verbose]\n", " \n", "tb_polgen --unwrap --elt \n", " [--verbose]\n", " \n", "tb_polgen --show [--verbose]\n", " \n", "tb_polgen --help\n", NULL }; /* * Define storage for user input parameter pointers */ bool verbose = false; static struct option long_options[] = { /* major sub-commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"add", no_argument, NULL, 'A'}, {"del", no_argument, NULL, 'D'}, {"unwrap", no_argument, NULL, 'U'}, {"show", no_argument, NULL, 'S'}, {"type", required_argument, NULL, 't'}, {"ctrl", required_argument, NULL, 'c'}, {"alg", required_argument, NULL, 'a'}, {"num", required_argument, NULL, 'n'}, {"pcr", required_argument, NULL, 'p'}, {"hash", required_argument, NULL, 'h'}, {"cmdline", required_argument, NULL, 'l'}, {"image", required_argument, NULL, 'i'}, {"pos", required_argument, NULL, 'o'}, {"elt", required_argument, NULL, 'e'}, {"verbose", no_argument, (int*)&verbose, true}, {0, 0, 0, 0} }; typedef struct { const char *name; int int_opt; } option_table_t; static option_table_t policy_type_opts[] = { {"nonfatal", int_opt : TB_POLTYPE_CONT_NON_FATAL}, {"continue", int_opt : TB_POLTYPE_CONT_VERIFY_FAIL}, {"halt", int_opt : TB_POLTYPE_HALT}, {NULL} }; static option_table_t hash_type_opts[] = { {"image", int_opt : TB_HTYPE_IMAGE}, {"any", int_opt : TB_HTYPE_ANY}, {NULL} }; static option_table_t mod_num_opts[] = { {"any", int_opt : TB_POL_MOD_NUM_ANY}, {""}, {NULL} }; static option_table_t pcr_opts[] = { {"none", int_opt : TB_POL_PCR_NONE}, {""}, {NULL} }; static option_table_t alg_opts[] = { {"sha1", int_opt : TB_HALG_SHA1}, {"sha256", int_opt : TB_HALG_SHA256}, {"sha384", int_opt : TB_HALG_SHA384}, {"sha512", int_opt : TB_HALG_SHA512}, {NULL} }; static bool strtonum(char *optarg, int *i) { if ( optarg == NULL || i == NULL ) return false; errno = 0; char* p; unsigned int value = (unsigned int)strtoul(optarg, &p, 0); /* error if either no value or extra chars after value or out of range */ if ( *optarg == '\0' || *p != '\0' || errno != 0) return false; *i = value; return true; } static bool parse_int_option(option_table_t *table, char *optarg, int *option) { if ( option == NULL ) { info_msg("NULL option\n"); return false; } info_msg("optarg = %s\n", optarg); while ( table->name != NULL ) { /* matches keyword so return its value */ if ( strcasecmp(table->name, optarg) == 0 ) { *option = table->int_opt; return true; } /* no keyword match but numeric arg is allowed, so try to convert */ else if ( *table->name == '\0' ) return strtonum(optarg, option); table++; } return false; } void print_params(param_data_t *params) { info_msg("params:\n"); info_msg("\t cmd = %d\n", params->cmd); info_msg("\t policy_type = %d\n", params->policy_type); info_msg("\t hash_alg = %d\n", params->hash_alg); info_msg("\t policy_control = %d\n", params->policy_control); info_msg("\t mod_num = %d\n", params->mod_num); info_msg("\t pcr = %d\n", params->pcr); info_msg("\t hash_type = %d\n", params->hash_type); info_msg("\t pos = %d\n", params->pos); info_msg("\t cmdline length = %lu\n", (unsigned long int)strnlen_s(params->cmdline, sizeof(params->cmdline))); info_msg("\t cmdline = %s\n", params->cmdline); info_msg("\t image_file = %s\n", params->image_file); info_msg("\t elt_file = %s\n", params->elt_file); info_msg("\t policy_file = %s\n", params->policy_file); } static bool validate_params(param_data_t *params) { const char *msg = NULL; switch( params->cmd ) { case POLGEN_CMD_NONE: msg = "Missing command argument\n"; goto error; case POLGEN_CMD_CREATE: /* these are required in all cases */ if ( strnlen_s(params->policy_file, sizeof(params->policy_file)) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( params->policy_type == -1 ) { msg = "Missing policy type\n"; goto error; } if ( params->hash_alg == -1 ) { msg = "Invalid --alg option\n"; goto error; } if ( (params->policy_control & ~TB_POLCTL_EXTEND_PCR17) != 0 ) { msg = "Invalid --ctrl value\n"; goto error; } return true; case POLGEN_CMD_ADD: /* these are required in all cases */ if ( strnlen_s(params->policy_file, sizeof(params->policy_file)) == 0 ) { msg = "Missing policy file\n"; goto error; } /* if hash_type is not ANY then need an image file */ if ( params->hash_type != TB_HTYPE_ANY && strnlen_s(params->image_file, sizeof(params->image_file)) == 0 ) { msg = "Missing --image option\n"; goto error; } /* if hash_type is ANY then no need for an image file */ if ( params->hash_type == TB_HTYPE_ANY && strnlen_s(params->image_file, sizeof(params->image_file)) != 0 ) { msg = "Extra --image option\n"; goto error; } if ( params->hash_type == -1 ) { msg = "Missing --hash option\n"; goto error; } if ( (params->pcr < 0 || params->pcr > TB_POL_MAX_PCR) && params->pcr != TB_POL_PCR_NONE ) { msg = "Invalid --pcr value\n"; goto error; } if ( (params->mod_num < 0 || params->mod_num > TB_POL_MAX_MOD_NUM) && params->mod_num != TB_POL_MOD_NUM_ANY ) { msg = "Invalid --num value\n"; goto error; } return true; case POLGEN_CMD_DEL: /* these are required in all cases */ if ( strnlen_s(params->policy_file, sizeof(params->policy_file)) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( (params->mod_num < 0 || params->mod_num > TB_POL_MAX_MOD_NUM) && params->mod_num != TB_POL_MOD_NUM_ANY ) { msg = "Invalid --num value\n"; goto error; } return true; case POLGEN_CMD_UNWRAP: if ( strnlen_s(params->policy_file, sizeof(params->policy_file)) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( strnlen_s(params->elt_file, sizeof(params->elt_file)) == 0 ) { msg = "Missing elt file\n"; goto error; } return true; case POLGEN_CMD_SHOW: if ( strnlen_s(params->policy_file, sizeof(params->policy_file)) == 0 ) { msg = "Missing policy file\n"; goto error; } return true; case POLGEN_CMD_HELP: return true; default: msg = "Unknown command\n"; goto error; } error: error_msg("%s", msg); if ( verbose ) print_params(params); return false; } #define HANDLE_MULTIPLE_CMDS(cmd) \ if ( (cmd) != POLGEN_CMD_NONE ) { \ error_msg("Only one command can be specified\n"); \ return false; \ } bool parse_input_params(int argc, char **argv, param_data_t *params) { int c; int option_index = 0; /* defaults */ params->cmd = POLGEN_CMD_NONE; params->mod_num = -1; params->pcr = -1; params->hash_alg = TB_HALG_SHA256; params->policy_type = -1; params->policy_control = TB_POLCTL_EXTEND_PCR17; params->hash_type = -1; params->policy_file[0] = '\0'; params->cmdline[0] = '\0'; params->image_file[0] = '\0'; params->elt_file[0] = '\0'; while ( true ) { c = getopt_long_only(argc, argv, "HCADUSt:a:c:n:p:h:l:i:o:e:", long_options, &option_index); if ( c == -1 ) /* no more args */ break; switch (c) { /* commands */ case 'H': /* --help */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_HELP; return true; case 'C': /* --create */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_CREATE; break; case 'A': /* --add */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_ADD; break; case 'D': /* --del */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_DEL; break; case 'U': /* --unwrap */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_UNWRAP; break; case 'S': /* --show */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_SHOW; break; /* options */ case 'n': /* --num */ if ( !parse_int_option(mod_num_opts, optarg, (int *)¶ms->mod_num) ) { error_msg("Unknown --num option\n"); return false; } break; case 'p': /* --pcr */ if ( !parse_int_option(pcr_opts, optarg, (int *)¶ms->pcr) ) { error_msg("Unknown --pcr option\n"); return false; } break; case 't': /* --type */ if ( !parse_int_option(policy_type_opts, optarg, (int *)¶ms->policy_type) ) { error_msg("Unknown --type option\n"); return false; } break; case 'a': /* --alg */ if ( !parse_int_option(alg_opts, optarg, (int *)¶ms->hash_alg) ) { error_msg("Unknown --alg option\n"); return false; } break; case 'c': /* --ctrl */ if ( !strtonum(optarg, ¶ms->policy_control) ) { error_msg("Unknown --ctrl option\n"); return false; } break; case 'h': /* --hash */ if ( !parse_int_option(hash_type_opts, optarg, (int *)¶ms->hash_type) ) { error_msg("Unknown --hash option\n"); return false; } break; case 'o': /* --pos */ if ( !strtonum(optarg, ¶ms->pos) ) { error_msg("Unknown --pos option\n"); return false; } break; case 'i': /* --image */ if ( optarg == NULL ) { error_msg("Missing filename for --image option\n"); return false; } strcpy_s(params->image_file, sizeof(params->image_file), optarg); break; case 'l': /* --cmdline */ if ( optarg == NULL ) { error_msg("Missing string for --cmdline option\n"); return false; } if (strnlen_s(optarg, sizeof(params->cmdline)) > sizeof(params->cmdline) - 1) { error_msg("Command line length of %lu exceeds %d " "character maximum\n", (unsigned long int)strnlen_s(optarg, sizeof(params->cmdline)), TBOOT_KERNEL_CMDLINE_SIZE-1); return false; } strcpy_s(params->cmdline, sizeof(params->cmdline), optarg); break; case 'e': /* --elt */ if ( optarg == NULL ) { error_msg("Missing filename for --elt option\n"); return false; } strcpy_s(params->elt_file, sizeof(params->elt_file), optarg); break; default: break; } } /* last argument is policy file */ if ( optind >= argc ){ error_msg("Missing filename for policy file\n"); return false; } strcpy_s(params->policy_file, sizeof(params->policy_file), argv[optind]); return validate_params(params); } void display_help_msg(void) { for ( int i = 0; help[i] != NULL; i++ ) printf("%s", help[i]); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tb_polgen/policy.c0000644000000000000000000001751214210363175014477 0ustar 00000000000000/* * policy.c: policy support functions * * Copyright (c) 2006-2008, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" /* buffer for policy read/written from/to policy file */ static uint8_t _policy_buf[MAX_TB_POLICY_SIZE]; tb_policy_t *g_policy = (tb_policy_t *)_policy_buf; void *read_elt_file(const char *elt_filename, size_t *length) { FILE *fp = fopen(elt_filename, "rb"); if ( fp == NULL ) { error_msg("fopen %s failed, errno %s\n", elt_filename, strerror(errno)); return NULL; } /* find size */ fseek(fp, 0, SEEK_END); long len = ftell(fp); if (len <= 0) { error_msg("failed to get file len\n"); fclose(fp); return NULL; } rewind(fp); void *data = malloc(len); if ( data == NULL ) { error_msg("failed to allocate %ld bytes memory\n", len); fclose(fp); return NULL; } if ( fread(data, len, 1, fp) != 1 ) { error_msg("reading file %s failed, errono %s\n", elt_filename, strerror(errno)); free(data); fclose(fp); return NULL; } fclose(fp); if ( length != NULL ) *length = len; return data; } bool read_policy_file(const char *policy_filename, bool *file_exists) { FILE *f = fopen(policy_filename, "r"); if ( f == NULL ) { if ( file_exists != NULL ) *file_exists = (errno != ENOENT); info_msg("fopen failed, errno %s\n", strerror(errno)); return false; } if ( file_exists != NULL ) *file_exists = true; /* clear for good measure */ memset_s(_policy_buf, sizeof(_policy_buf), 0); size_t read_cnt = fread(_policy_buf, 1, sizeof(_policy_buf), f); if ( ferror(f) ) { error_msg("fread failed, errno %s\n", strerror(errno)); fclose(f); return false; } if ( read_cnt == 0 ) { error_msg("Policy file %s is empty\n", policy_filename); fclose(f); return false; } fclose(f); if ( !verify_policy(g_policy, read_cnt, verbose) ) { error_msg("Policy file %s is corrupt\n", policy_filename); return false; } return true; } bool write_policy_file(const char *policy_filename) { verify_policy(g_policy, sizeof(_policy_buf), verbose); FILE *f = fopen(policy_filename, "w"); if ( f == NULL ) { info_msg("fopen failed, errno %s\n", strerror(errno)); return false; } size_t pol_size = calc_policy_size(g_policy); size_t write_cnt = fwrite(_policy_buf, 1, pol_size, f); if ( write_cnt != pol_size ) { info_msg("error writing policy, errno %s\n", strerror(errno)); fclose(f); return false; } fclose(f); return true; } void new_policy(int policy_type, int policy_control, int hash_alg) { /* current version is 2 */ g_policy->version = 2; g_policy->hash_alg = hash_alg; g_policy->num_entries = 0; modify_policy(policy_type, policy_control); } void modify_policy(int policy_type, int policy_control) { if ( policy_type != -1 ) g_policy->policy_type = policy_type; g_policy->policy_control = (uint32_t)policy_control; } tb_policy_entry_t *add_pol_entry(uint8_t mod_num, uint8_t pcr, uint8_t hash_type) { /* assumes check for existing mod_num already done */ info_msg("adding new policy entry for mod_num %u (pcr: %u, " "hash_type: %u)\n", mod_num, pcr, hash_type); /* TODO: if there is already a MOD_NUM_ANY entry then insert this */ /* new one before it */ /* always goes at end of policy, so no need to make space, */ /* just find end of policy data */ size_t size = calc_policy_size(g_policy); if ( size + sizeof(tb_policy_entry_t) > sizeof(_policy_buf) ) return NULL; tb_policy_entry_t *pol_entry = (tb_policy_entry_t *)(_policy_buf + size); pol_entry->mod_num = mod_num; pol_entry->pcr = pcr; pol_entry->hash_type = hash_type; pol_entry->num_hashes = 0; g_policy->num_entries++; return pol_entry; } void modify_pol_entry(tb_policy_entry_t *pol_entry, uint8_t pcr, uint8_t hash_type) { if ( pol_entry == NULL ) return; info_msg("modifying policy entry for mod_num %u\n", pol_entry->mod_num); pol_entry->pcr = pcr; pol_entry->hash_type = hash_type; } bool add_hash(tb_policy_entry_t *pol_entry, const tb_hash_t *hash) { if ( pol_entry == NULL ) return false; /* since pol_entry may not be last in policy, need to make space */ size_t pol_size = calc_policy_size(g_policy); size_t hash_size = get_hash_size(g_policy->hash_alg); if ( pol_size + hash_size > sizeof(_policy_buf) ) return false; unsigned char *entry_end = (unsigned char *)pol_entry + sizeof(*pol_entry) + (pol_entry->num_hashes * hash_size); unsigned char *pol_end = _policy_buf + pol_size; memmove_s(entry_end + hash_size, pol_end - entry_end, entry_end, pol_end - entry_end); copy_hash((tb_hash_t *)entry_end, hash, g_policy->hash_alg); pol_entry->num_hashes++; return true; } bool del_hash(tb_policy_entry_t *pol_entry, int i) { if ( pol_entry == NULL ) return false; if ( i < 0 || i >= pol_entry->num_hashes ) return false; void *start = get_policy_entry_hash(pol_entry, g_policy->hash_alg, i); size_t size = get_hash_size(g_policy->hash_alg); memmove_s(start, calc_policy_size(g_policy), start + size, calc_policy_size(g_policy) - size); pol_entry->num_hashes--; return true; } bool del_entry(tb_policy_entry_t *pol_entry) { if ( pol_entry == NULL ) return false; void *start = pol_entry; size_t size = calc_policy_entry_size(pol_entry, g_policy->hash_alg); memmove_s(start, calc_policy_size(g_policy), start + size, calc_policy_size(g_policy) - size); g_policy->num_entries--; return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tb_polgen/tb_polgen.c0000644000000000000000000000553114210363175015147 0ustar 00000000000000/* * tb_polgen.c: policy generation tool for tboot * * Copyright (c) 2006-2008, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" int main (int argc, char *argv[]) { param_data_t params; bool ret; if ( !parse_input_params(argc, argv, ¶ms) ) return 1; print_params(¶ms); switch ( params.cmd ) { case POLGEN_CMD_CREATE: ret = do_create(¶ms); break; case POLGEN_CMD_ADD: ret = do_add(¶ms); break; case POLGEN_CMD_DEL: ret = do_del(¶ms); break; case POLGEN_CMD_UNWRAP: ret = do_unwrap(¶ms); break; case POLGEN_CMD_SHOW: ret = do_show(¶ms); break; case POLGEN_CMD_HELP: display_help_msg(); ret = true; break; default: ret = false; break; } return (ret ? 0 : 1); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tb_polgen/tb_polgen.h0000644000000000000000000000757714210363175015170 0ustar 00000000000000/* * tb_polgen.h: types and definitions for tb_polgen * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TB_POLGEN_H__ #define __TB_POLGEN_H__ extern bool verbose; #define error_msg(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #define info_msg(fmt, ...) if (verbose) printf(fmt , ##__VA_ARGS__) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) typedef enum { POLGEN_CMD_NONE, POLGEN_CMD_HELP, POLGEN_CMD_CREATE, POLGEN_CMD_ADD, POLGEN_CMD_DEL, POLGEN_CMD_UNWRAP, POLGEN_CMD_SHOW, } polgen_cmd_t; typedef struct { polgen_cmd_t cmd; int policy_type; int policy_control; int mod_num; int pcr; int hash_type; int pos; int hash_alg; char cmdline[TBOOT_KERNEL_CMDLINE_SIZE]; char image_file[FILENAME_MAX]; char elt_file[FILENAME_MAX]; char policy_file[FILENAME_MAX]; } param_data_t; /* in param.c */ extern bool parse_input_params(int argc, char **argv, param_data_t *params); extern void display_help_msg(void); extern void print_params(param_data_t *params); /* in commands.c */ extern bool do_create(const param_data_t *params); extern bool do_add(const param_data_t *params); extern bool do_del(const param_data_t *params); extern bool do_unwrap(const param_data_t *params); extern bool do_show(const param_data_t *params); /* in policy.c */ extern void *read_elt_file(const char *elt_filename, size_t *length); extern bool read_policy_file(const char *policy_filename, bool *file_exists); extern bool write_policy_file(const char *policy_filename); extern void new_policy(int policy_type, int policy_control, int hash_alg); extern void modify_policy(int policy_type, int policy_control); extern tb_policy_entry_t *add_pol_entry(uint8_t mod_num, uint8_t pcr, uint8_t hash_type); extern void modify_pol_entry(tb_policy_entry_t *pol_entry, uint8_t pcr, uint8_t hash_type); extern bool add_hash(tb_policy_entry_t *pol_entry, const tb_hash_t *hash); extern bool del_hash(tb_policy_entry_t *pol_entry, int i); extern bool del_entry(tb_policy_entry_t *pol_entry); #endif /* __TB_POLGEN_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/20_linux_tboot0000644000000000000000000001737514210363175015013 0ustar 00000000000000#! /bin/sh set -e # grub-mkconfig helper script. # Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRUB is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . prefix=/usr exec_prefix=${prefix} bindir=${exec_prefix}/bin libdir=${exec_prefix}/lib sysconfdir=/etc if test -e /usr/share/grub/grub-mkconfig_lib; then . /usr/share/grub/grub-mkconfig_lib elif test -e ${libdir}/grub/grub-mkconfig_lib; then . ${libdir}/grub/grub-mkconfig_lib elif test -e /usr/share/grub2/grub-mkconfig_lib; then . /usr/share/grub2/grub-mkconfig_lib fi if test -e ${sysconfdir}/default/grub-tboot; then . ${sysconfdir}/default/grub-tboot fi # Set the following variables in /etc/default/grub-tboot to customize command lines # (empty values are treated as if the variables were unset). [ -z "${GRUB_CMDLINE_TBOOT}" ] && unset GRUB_CMDLINE_TBOOT [ -z "${GRUB_CMDLINE_LINUX_TBOOT}" ] && unset GRUB_CMDLINE_LINUX_TBOOT [ -z "${GRUB_TBOOT_POLICY_DATA}" ] && unset GRUB_TBOOT_POLICY_DATA # Command line for tboot itself : ${GRUB_CMDLINE_TBOOT='logging=serial,memory,vga'} # Linux kernel parameters to append for tboot : ${GRUB_CMDLINE_LINUX_TBOOT='intel_iommu=on'} # Base name of LCP policy data file for list policy : ${GRUB_TBOOT_POLICY_DATA=''} export TEXTDOMAIN=grub export TEXTDOMAINDIR=${prefix}/share/locale CLASS="--class gnu-linux --class gnu --class os --class tboot" if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but # the initrds that Linux uses don't like that. case ${GRUB_DEVICE} in /dev/loop/*|/dev/loop[0-9]) GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` ;; esac if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ || uses_abstraction "${GRUB_DEVICE}" lvm; then LINUX_ROOT_DEVICE=${GRUB_DEVICE} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi # Merge all sequences of spaces into a single space, like GRUB2 does during boot. # Simplistic, doesn't check for quoting, but should be good enough for the kernel command line. merge_spaces() { echo "$*" | sed -e 's/ \{1,\}/ /g' -e 's/^ //' -e 's/ $//' } linux_entry () { os="$1" version="$2" tboot_version="$3" recovery="$4" args="$5" tboot_args="$6" iommu_args="$7" if ${recovery} ; then title="$(gettext_quoted "%s, with tboot %s and Linux %s (recovery mode)")" else title="$(gettext_quoted "%s, with tboot %s and Linux %s")" fi if [ -d /sys/firmware/efi ] ; then mb_directive="multiboot2" mb_mod_directive="module2" mb_extra_kernel="noefi" else mb_directive="multiboot2" mb_mod_directive="module2" mb_extra_kernel="" fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${tboot_version}" "${version}" if ! ${recovery} ; then save_default_entry | sed -e "s/^/\t/" fi printf "\tinsmod multiboot2\n" if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" xmessage="$(gettext_printf "Loading tboot %s ..." ${tboot_version})" lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" tbargs=`merge_spaces ${tboot_args}` lxargs=`merge_spaces root=${linux_root_device_thisversion} ro ${args} ${iommu_args} ${mb_extra_kernel}` cat << EOF echo '$xmessage' ${mb_directive} ${rel_tboot_dirname}/${tboot_basename} ${tbargs} echo '$lmessage' ${mb_mod_directive} ${rel_dirname}/${basename} ${lxargs} EOF if test -n "${initrd}" ; then message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF echo '$message' ${mb_mod_directive} ${rel_dirname}/${initrd} EOF fi if test -n "${sinit_list}" ; then for i in ${sinit_list}; do message="$(gettext_printf "Loading sinit $i ...")" cat << EOF echo '$message' ${mb_mod_directive} ${rel_dirname}/${i} EOF done fi if test -n "${poldata_file}" ; then message="$(gettext_printf "Loading tboot policy data file ${poldata_file} ...")" cat << EOF echo '$message' ${mb_mod_directive} ${rel_dirname}/${poldata_file} EOF fi cat << EOF } EOF } linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do basename=$(basename $i) version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") if grub_file_is_not_garbage "$i" && grep -qx "CONFIG_INTEL_TXT=y" /boot/config-${version} 2> /dev/null ; then echo -n "$i " ; fi done` tboot_list=`for i in /boot/tboot*.gz; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` sinit_list=`for i in /boot/*sinit* /boot/*SINIT*; do basename=$(basename $i) if grub_file_is_not_garbage "$i" ; then echo -n "$basename " ; fi done` if [ -n "${GRUB_TBOOT_POLICY_DATA}" ]; then if grub_file_is_not_garbage "/boot/${GRUB_TBOOT_POLICY_DATA}"; then poldata_file=${GRUB_TBOOT_POLICY_DATA} else echo "ERROR in $0: GRUB_TBOOT_POLICY_DATA=${GRUB_TBOOT_POLICY_DATA} not found in /boot, check ${sysconfdir}/default/grub-tboot" >&2 fi fi prepare_boot_cache= while [ "x${tboot_list}" != "x" ] && [ "x$linux_list" != "x" ] ; do list="${linux_list}" current_tboot=`version_find_latest $tboot_list` tboot_basename=`basename ${current_tboot}` tboot_dirname=`dirname ${current_tboot}` rel_tboot_dirname=`make_system_path_relative_to_its_root $tboot_dirname` # tboot_version=`echo $tboot_basename | sed -e "s,.gz$,,g;s,^tboot-,,g"` tboot_version="1.10.5" echo "submenu \"tboot ${tboot_version}\" {" while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` echo "Found linux image: $linux" >&2 basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" initrd= for i in "initrd.img-${version}" "initrd-${version}.img" \ "initrd-${version}" "initramfs-${version}.img" \ "initrd.img-${alt_version}" "initrd-${alt_version}.img" \ "initrd-${alt_version}" "initramfs-${alt_version}.img" \ "initramfs-genkernel-${version}" \ "initramfs-genkernel-${alt_version}"; do if test -e "${dirname}/${i}" ; then initrd="$i" break fi done if test -n "${initrd}" ; then echo "Found initrd image: ${dirname}/${initrd}" >&2 else # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. linux_root_device_thisversion=${GRUB_DEVICE} fi linux_entry "${OS}" "${version}" "${tboot_version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_TBOOT}" \ "${GRUB_CMDLINE_LINUX_TBOOT}" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${tboot_version}" true \ "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_TBOOT}" \ "${GRUB_CMDLINE_LINUX_TBOOT}" fi list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` done echo "}" tboot_list=`echo $tboot_list | tr ' ' '\n' | grep -vx $current_tboot | tr '\n' ' '` done tboot-1.10.5/tboot/20_linux_xen_tboot0000644000000000000000000002350114210363175015651 0ustar 00000000000000#! /bin/sh set -e # grub-mkconfig helper script. # Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRUB is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . prefix=/usr exec_prefix=${prefix} bindir=${exec_prefix}/bin libdir=${exec_prefix}/lib sysconfdir=/etc if test -e /usr/share/grub/grub-mkconfig_lib; then . /usr/share/grub/grub-mkconfig_lib elif test -e ${libdir}/grub/grub-mkconfig_lib; then . ${libdir}/grub/grub-mkconfig_lib elif test -e /usr/share/grub2/grub-mkconfig_lib; then . /usr/share/grub2/grub-mkconfig_lib fi if test -e ${sysconfdir}/default/grub-tboot; then . ${sysconfdir}/default/grub-tboot fi # Set the following variables in /etc/default/grub-tboot to customize command lines # (empty values are treated as if the variables were unset). [ -z "${GRUB_CMDLINE_TBOOT}" ] && unset GRUB_CMDLINE_TBOOT [ -z "${GRUB_CMDLINE_XEN_TBOOT}" ] && unset GRUB_CMDLINE_XEN_TBOOT [ -z "${GRUB_CMDLINE_LINUX_XEN_TBOOT}" ] && unset GRUB_CMDLINE_LINUX_XEN_TBOOT [ -z "${GRUB_TBOOT_POLICY_DATA}" ] && unset GRUB_TBOOT_POLICY_DATA # Command line for tboot itself : ${GRUB_CMDLINE_TBOOT='logging=serial,memory,vga'} # Xen parameters to append for tboot : ${GRUB_CMDLINE_XEN_TBOOT=''} # Linux kernel parameters to append for tboot + Xen : ${GRUB_CMDLINE_LINUX_XEN_TBOOT=''} # Base name of LCP policy data file for list policy : ${GRUB_TBOOT_POLICY_DATA=''} export TEXTDOMAIN=grub export TEXTDOMAINDIR=${prefix}/share/locale CLASS="--class gnu-linux --class gnu --class os --class xen" if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but # the initrds that Linux uses don't like that. case ${GRUB_DEVICE} in /dev/loop/*|/dev/loop[0-9]) GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` ;; esac if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ || uses_abstraction "${GRUB_DEVICE}" lvm; then LINUX_ROOT_DEVICE=${GRUB_DEVICE} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi # Allow overriding GRUB_CMDLINE_LINUX and GRUB_CMDLINE_LINUX_DEFAULT. if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE}" ]; then GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX_XEN_REPLACE}" fi if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" ]; then GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" fi if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ] \ || [ "x`stat -f --printf=%T /`" = xbtrfs ]; then rootsubvol="`make_system_path_relative_to_its_root /`" rootsubvol="${rootsubvol#/}" if [ "x${rootsubvol}" != x ]; then GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" fi fi # Merge all sequences of spaces into a single space, like GRUB2 does during boot. # Simplistic, doesn't check for quoting, but should be good enough for the kernel command line. merge_spaces() { echo "$*" | sed -e 's/ \{1,\}/ /g' -e 's/^ //' -e 's/ $//' } linux_entry () { os="$1" version="$2" xen_version="$3" recovery="$4" args="$5" xen_args="$6" tboot_version="$7" tboot_args="$8" iommu_args="$9" if ${recovery} ; then title="$(gettext_quoted "%s, with Xen %s, Tboot %s and Linux %s (recovery mode)")" else title="$(gettext_quoted "%s, with Xen %s, Tboot %s and Linux %s")" fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${xen_version}" "${tboot_version}" "${version}" if ! ${recovery} ; then save_default_entry | sed -e "s/^/\t/" fi printf "\tinsmod multiboot2\n" if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})" tmessage="$(gettext_printf "Loading Tboot %s ..." ${tboot_version})" lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" tbargs=`merge_spaces ${tboot_args}` xnargs=`merge_spaces ${xen_args} ${iommu_args}` lxargs=`merge_spaces root=${linux_root_device_thisversion} ro ${args}` cat << EOF echo '$tmessage' multiboot2 ${rel_tboot_dirname}/${tboot_basename} ${tbargs} echo '$xmessage' module2 ${rel_xen_dirname}/${xen_basename} ${xnargs} echo '$lmessage' module2 ${rel_dirname}/${basename} ${lxargs} EOF if test -n "${initrd}" ; then message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF echo '$message' module2 ${rel_dirname}/${initrd} EOF fi if test -n "${sinit_list}" ; then for i in ${sinit_list}; do message="$(gettext_printf "Loading sinit $i ...")" cat << EOF echo '$message' module2 ${rel_dirname}/${i} EOF done fi if test -n "${poldata_file}" ; then message="$(gettext_printf "Loading tboot policy data file ${poldata_file} ...")" cat << EOF echo '$message' module2 ${rel_dirname}/${poldata_file} EOF fi cat << EOF } EOF } linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* /boot/kernel-*; do if grub_file_is_not_garbage "$i"; then basename=$(basename $i) version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") dirname=$(dirname $i) config= for j in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do if test -e "${j}" ; then config="${j}" break fi done if (grep -qx "CONFIG_XEN_DOM0=y" "${config}" 2> /dev/null || grep -qx "CONFIG_XEN_PRIVILEGED_GUEST=y" "${config}" 2> /dev/null); then echo -n "$i " ; fi fi done` if [ "x${linux_list}" = "x" ] ; then exit 0 fi xen_list=`for i in /boot/xen*; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` tboot_list=`for i in /boot/tboot*.gz; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` sinit_list=`for i in /boot/*sinit* /boot/*SINIT*; do basename=$(basename $i) if grub_file_is_not_garbage "$i" ; then echo -n "$basename " ; fi done` if [ -n "${GRUB_TBOOT_POLICY_DATA}" ]; then if grub_file_is_not_garbage "/boot/${GRUB_TBOOT_POLICY_DATA}"; then poldata_file=${GRUB_TBOOT_POLICY_DATA} else echo "ERROR in $0: GRUB_TBOOT_POLICY_DATA=${GRUB_TBOOT_POLICY_DATA} not found in /boot, check ${sysconfdir}/default/grub-tboot" >&2 fi fi prepare_boot_cache= while [ "x${xen_list}" != "x" ] ; do current_xen=`version_find_latest $xen_list` xen_basename=`basename ${current_xen}` xen_dirname=`dirname ${current_xen}` rel_xen_dirname=`make_system_path_relative_to_its_root $xen_dirname` xen_version=`echo $xen_basename | sed -e "s,.gz$,,g;s,^xen-,,g"` tlist="${tboot_list}" while [ "x${tlist}" != "x" ] && [ "x$linux_list" != "x" ] ; do current_tboot=`version_find_latest $tlist` tboot_basename=`basename ${current_tboot}` tboot_dirname=`dirname ${current_tboot}` rel_tboot_dirname=`make_system_path_relative_to_its_root $tboot_dirname` tboot_version="1.10.5" list="${linux_list}" echo "submenu \"Xen ${xen_version}\" \"Tboot ${tboot_version}\"{" while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` echo "Found linux image: $linux" >&2 basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" initrd= for i in "initrd.img-${version}" "initrd-${version}.img" \ "initrd-${version}" "initrd.img-${alt_version}" \ "initrd-${alt_version}.img" "initrd-${alt_version}" \ "initramfs-genkernel-${version}" \ "initramfs-genkernel-${alt_version}" ; do if test -e "${dirname}/${i}" ; then initrd="$i" break fi done if test -n "${initrd}" ; then echo "Found initrd image: ${dirname}/${initrd}" >&2 else # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. linux_root_device_thisversion=${GRUB_DEVICE} fi linux_entry "${OS}" "${version}" "${xen_version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_XEN_TBOOT}" \ "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT} ${GRUB_CMDLINE_XEN_TBOOT}" \ "${tboot_version}" "${GRUB_CMDLINE_TBOOT}" "iommu=force" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${xen_version}" true \ "single ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_XEN_TBOOT}" \ "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_TBOOT}" \ "${tboot_version}" "${GRUB_CMDLINE_TBOOT}" "iommu=force" fi list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` done echo "}" tlist=`echo $tlist | tr ' ' '\n' | grep -vx $current_tboot | tr '\n' ' '` done xen_list=`echo $xen_list | tr ' ' '\n' | grep -vx $current_xen | tr '\n' ' '` done tboot-1.10.5/tboot/Config.mk0000644000000000000000000000315714210363175013750 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tboot-specific build settings # RELEASEVER := "1.10.5" RELEASETIME := "2022-03-04 12:00 +0100" ROOTDIR ?= $(CURDIR)/.. # tboot needs too many customized compiler settings to use system CFLAGS, # so if environment wants to set any compiler flags, it must use TBOOT_CFLAGS CFLAGS := $(TBOOT_CFLAGS) include $(ROOTDIR)/Config.mk # if target arch is 64b, then convert -m64 to -m32 (tboot is always 32b) CFLAGS := $(shell echo $(CFLAGS) | sed -e s/-m64/-m32/) CFLAGS += -march=i686 CFLAGS += -nostdinc CFLAGS += -fno-builtin -fno-common -fno-strict-aliasing CFLAGS += -fomit-frame-pointer CFLAGS += -pipe CFLAGS += -iwithprefix include CFLAGS += -I$(CURDIR)/include -I$(ROOTDIR)/include # ensure no floating-point variables CFLAGS += -msoft-float # Disable PIE/SSP if GCC supports them. They can break us. CFLAGS += $(call cc-option,$(CC),-nopie,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) CFLAGS += $(call cc-option,$(CC),-fno-stack-check,) # changeset variable for banner CFLAGS += -DTBOOT_CHANGESET=\""$(shell (hg parents --template "{latesttag} {date|isodate} {rev}:{node|short}" || echo "$(RELEASETIME) $(RELEASEVER)") 2>/dev/null)"\" # flags for OpenSSL CFLAGS += -DPOLY1305_ASM -DOPENSSL_IA32_SSE2 AFLAGS += -D__ASSEMBLY__ # Most CFLAGS are safe for assembly files: # -std=gnu{89,99} gets confused by #-prefixed end-of-line comments AFLAGS += $(patsubst -std=gnu%,,$(CFLAGS)) # LDFLAGS are only passed directly to $(LD) LDFLAGS = -melf_i386 tboot-1.10.5/tboot/Makefile0000644000000000000000000000712114210363175013645 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tboot makefile # include $(CURDIR)/Config.mk TARGET := $(CURDIR)/tboot # boot.o must be first obj-y := common/boot.o obj-y += common/acpi.o common/cmdline.o common/com.o common/e820.o common/vtd.o obj-y += common/elf.o common/hash.o common/index.o common/integrity.o obj-y += common/linux.o common/loader.o common/memcmp.o common/memcpy.o obj-y += common/misc.o common/mutex.o common/paging.o common/pci_cfgreg.o obj-y += common/policy.o common/printk.o common/sha1.o obj-y += common/strcmp.o common/strlen.o common/strncmp.o common/strncpy.o obj-y += common/strtoul.o common/tb_error.o common/tboot.o common/tpm.o obj-y += common/vga.o common/vsprintf.o common/lz.o common/memlog.o obj-y += txt/acmod.o txt/errors.o txt/heap.o txt/mtrrs.o txt/txt.o obj-y += txt/verify.o txt/vmcs.o obj-y += common/tpm_12.o common/tpm_20.o obj-y += common/sha256.o common/sha512.o common/sha384.o common/efi_memmap.o obj-y += common/poly1305/poly1305.o common/poly1305/poly1305-x86.o obj-y += common/poly1305/x86cpuid.o OBJS := $(obj-y) TARGET_LDS := $(CURDIR)/common/tboot.lds $(TARGET).strip : $(TARGET) strip $< -o $@ $(TARGET).gz : $(TARGET).strip gzip -n -f -9 < $< > $@ $(TARGET) : $(OBJS) $(TARGET_LDS) $(LD) $(LDFLAGS) -T $(TARGET_LDS) -N $(OBJS) -o $@ $(NM) -n $@ >$(TARGET)-syms $(TARGET_LDS) : $(TARGET_LDS).x $(HDRS) $(CPP) -x c -P -E -Ui386 $(AFLAGS) -o $@ $< $(TARGET_LDS).x : FORCE # # universal rules # dist : install build : $(TARGET).gz install : $(DISTDIR)/boot/$(TARGET).gz $(DISTDIR)/boot/$(TARGET).gz : $(TARGET).gz [ -d $(DISTDIR)/boot ] || $(INSTALL_DIR) $(DISTDIR)/boot $(INSTALL_DATA) $(TARGET).gz $(DISTDIR)/boot/$(notdir $(TARGET)).gz $(INSTALL_DATA) $(TARGET)-syms $(DISTDIR)/boot/$(notdir $(TARGET))-syms [ -d $(DISTDIR)/etc/grub.d ] || $(INSTALL_DIR) $(DISTDIR)/etc/grub.d $(INSTALL) -m755 -t $(DISTDIR)/etc/grub.d 20* clean : rm -f $(TARGET)* $(TARGET_LDS) *~ include/*~ include/txt/*~ *.o common/*~ txt/*~ common/*.o txt/*.o common/poly1305/*.o rm -f tags TAGS cscope.files cscope.in.out cscope.out cscope.po.out distclean : clean # # TAGS / tags # define all_sources ( find . -name '*.[chS]' -print ) endef define set_exuberant_flags exuberant_flags=`$1 --version 2>/dev/null | grep -iq exuberant && \ echo "-I __initdata,__exitdata,__acquires,__releases \ -I EXPORT_SYMBOL \ --extra=+f --c-kinds=+px"` endef .PHONY: TAGS TAGS : rm -f TAGS; \ $(call set_exuberant_flags,etags); \ $(all_sources) | xargs etags $$exuberant_flags -a .PHONY: tags tags : rm -f tags; \ $(call set_exuberant_flags,ctags); \ $(all_sources) | xargs ctags $$exuberant_flags -a # # cscope # .PHONY: cscope cscope : $(all_sources) > cscope.files cscope -k -b -q # # MAP # .PHONY: MAP MAP : $(NM) -n $(TARGET)-syms | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' > System.map # # implicit rules # HDRS := $(wildcard $(CURDIR)/include/*.h) HDRS += $(wildcard $(CURDIR)/include/txt/*.h) BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Config.mk $(CURDIR)/Makefile # fix case where gcc doesn't use builtin memcmp() when built w/o optimizations ifeq ($(debug),y) CFLAGS += -O2 endif %.o : %.c $(HDRS) $(BUILD_DEPS) $(CC) $(CFLAGS) -c $< -o $@ %.o : %.S $(HDRS) $(BUILD_DEPS) $(CC) $(AFLAGS) -c $< -o $@ %.i : %.c $(HDRS) $(BUILD_DEPS) $(CPP) $(CFLAGS) $< -o $@ # -std=gnu{89,99} gets confused by # as an end-of-line comment marker %.s : %.S $(HDRS) $(BUILD_DEPS) $(CPP) $(AFLAGS) $< -o $@ %.S : %.pl $(HDRS) $(BUILD_DEPS) /usr/bin/perl $< "elf" $(AFLAGS) $@ tboot-1.10.5/tboot/common/acpi.c0000644000000000000000000003137414210363175014564 0ustar 00000000000000/* * acpi.c: ACPI utility fns * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ACPI_DEBUG #define acpi_printk printk #else #define acpi_printk(...) /* */ #endif static struct acpi_rsdp *rsdp; static void dump_gas(const char *reg_name, const tboot_acpi_generic_address_t *reg) { const char *space_id[] = { "memory", "I/O", "PCI config space", "EC", "SMBus" }; printk(TBOOT_DETA"%s GAS @ %p:\n", reg_name, reg); if ( reg == NULL ) return; if ( reg->space_id >= ARRAY_SIZE(space_id) ) printk(TBOOT_DETA"\t space_id: unsupported (%u)\n", reg->space_id); else printk(TBOOT_DETA"\t space_id: %s\n", space_id[reg->space_id]); printk(TBOOT_DETA"\t bit_width: %u\n", reg->bit_width); printk(TBOOT_DETA"\t bit_offset: %u\n", reg->bit_offset); printk(TBOOT_DETA"\t access_width: %u\n", reg->access_width); printk(TBOOT_DETA"\t address: %Lx\n", reg->address); } static inline struct acpi_rsdt *get_rsdt(void) { return (struct acpi_rsdt *)rsdp->rsdp1.rsdt; } static inline struct acpi_xsdt *get_xsdt(void) { if ( rsdp->rsdp_xsdt >= 0x100000000ULL ) { printk(TBOOT_ERR"XSDT above 4GB\n"); return NULL; } return (struct acpi_xsdt *)(uintptr_t)rsdp->rsdp_xsdt; } static bool verify_acpi_checksum(uint8_t *start, uint8_t len) { uint8_t sum = 0; while ( len ) { sum += *start++; len--; } return (sum == 0); } static bool find_rsdp_in_range(void *start, void *end) { #define RSDP_BOUNDARY 16 /* rsdp ranges on 16-byte boundaries */ #define RSDP_CHKSUM_LEN 20 /* rsdp check sum length, defined in ACPI 1.0 */ for ( ; start < end; start += RSDP_BOUNDARY ) { rsdp = (struct acpi_rsdp *)start; if ( tb_memcmp(rsdp->rsdp1.signature, RSDP_SIG, sizeof(rsdp->rsdp1.signature)) == 0 ) { if ( verify_acpi_checksum((uint8_t *)rsdp, RSDP_CHKSUM_LEN) ) { printk(TBOOT_DETA"RSDP (v%u, %.6s) @ %p\n", rsdp->rsdp1.revision, rsdp->rsdp1.oemid, rsdp); return true; } else { printk(TBOOT_ERR"checksum failed.\n"); return false; } } } return false; } extern loader_ctx *g_ldr_ctx; static bool find_rsdp(void) { uint32_t length; uint8_t *ldr_rsdp = NULL; if ( rsdp != NULL ) return true; /* for grins, let's try asking the loader_ctx if it has a copy */ ldr_rsdp = get_loader_rsdp(g_ldr_ctx, &length); if (ldr_rsdp != NULL){ rsdp = (struct acpi_rsdp *) ldr_rsdp; return true; } /* 0x00 - 0x400 */ if ( find_rsdp_in_range(RSDP_SCOPE1_LOW, RSDP_SCOPE1_HIGH) ) return true; /* 0xE0000 - 0x100000 */ if ( find_rsdp_in_range(RSDP_SCOPE2_LOW, RSDP_SCOPE2_HIGH) ) return true; printk(TBOOT_ERR"can't find RSDP\n"); rsdp = NULL; return false; } struct acpi_rsdp *get_rsdp(loader_ctx *lctx) { if (rsdp != NULL) return rsdp; if (true == find_rsdp()) return rsdp; /* so far we're striking out. Must have been an EFI lauch */ if (false == is_loader_launch_efi(lctx)){ /* uncle */ return NULL; } /* EFI launch, and the loader didn't grace us with an ACPI tag. * We can try to find this the hard way, right? */ return NULL; } /* this function can find dmar table whether or not it was hidden */ static struct acpi_table_header *find_table(const char *table_name) { if ( !find_rsdp() ) { printk(TBOOT_ERR"no rsdp to use\n"); return NULL; } struct acpi_table_header *table = NULL; struct acpi_xsdt *xsdt = get_xsdt(); /* it is ok even on 1.0 tables */ /* because value will be ignored */ if ( rsdp->rsdp1.revision >= 2 && xsdt != NULL ) { /* ACPI 2.0+ */ for ( uint64_t *curr_table = xsdt->table_offsets; curr_table < (uint64_t *)((void *)xsdt + xsdt->hdr.length); curr_table++ ) { table = (struct acpi_table_header *)(uintptr_t)*curr_table; if ( tb_memcmp(table->signature, table_name, sizeof(table->signature)) == 0 ) return table; } } else { /* ACPI 1.0 */ struct acpi_rsdt *rsdt = get_rsdt(); if ( rsdt == NULL ) { printk(TBOOT_ERR"rsdt is invalid.\n"); return NULL; } for ( uint32_t *curr_table = rsdt->table_offsets; curr_table < (uint32_t *)((void *)rsdt + rsdt->hdr.length); curr_table++ ) { table = (struct acpi_table_header *)(uintptr_t)*curr_table; if ( tb_memcmp(table->signature, table_name, sizeof(table->signature)) == 0 ) return table; } } printk(TBOOT_ERR"can't find %s table.\n", table_name); return NULL; } static struct acpi_madt *get_apic_table(void) { return (struct acpi_madt *)find_table(MADT_SIG); } uint32_t get_madt_apic_base(void) { struct acpi_madt *madt = get_apic_table(); if ( madt == NULL ) { printk(TBOOT_ERR"no MADT table found\n"); return 0; } return (uint32_t)madt->local_apic_address; } struct acpi_table_ioapic *get_acpi_ioapic_table(void) { struct acpi_madt *madt = get_apic_table(); if ( madt == NULL ) { printk(TBOOT_ERR"no MADT table found\n"); return NULL; } /* APIC tables begin after MADT */ union acpi_madt_entry *entry = (union acpi_madt_entry *)(madt + 1); while ( (void *)entry < ((void *)madt + madt->hdr.length) ) { uint8_t length = entry->madt_lapic.length; if ( entry->madt_lapic.apic_type == ACPI_MADT_IOAPIC ) { if ( length != sizeof(entry->madt_ioapic) ) { printk(TBOOT_ERR"APIC length error.\n"); return NULL; } return (struct acpi_table_ioapic *)entry; } entry = (void *)entry + length; } printk(TBOOT_ERR"no IOAPIC type.\n"); return NULL; } struct acpi_mcfg *get_acpi_mcfg_table(void) { return (struct acpi_mcfg *)find_table(MCFG_SIG); } struct acpi_dmar *get_vtd_dmar_table(void) { return (struct acpi_dmar *)find_table(DMAR_SIG); } static bool write_to_reg(const tboot_acpi_generic_address_t *reg, uint32_t val) { if ( reg->address >= 100000000ULL ) { printk(TBOOT_ERR"GAS address >4GB (0x%Lx)\n", reg->address); return false; } uint32_t address = (uint32_t)reg->address; if ( reg->space_id == GAS_SYSTEM_IOSPACE ) { switch ( reg->bit_width ) { case 8: outb(address, (uint8_t)val); return true; case 16: outw(address, (uint16_t)val); return true; case 32: outl(address, val); return true; default: printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width); return false; } } else if ( reg->space_id == GAS_SYSTEM_MEMORY ) { switch ( reg->bit_width ) { case 8: writeb(address, (uint8_t)val); return true; case 16: writew(address, (uint16_t)val); return true; case 32: writel(address, val); return true; default: printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width); return false; } } printk(TBOOT_ERR"unsupported GAS addr space ID: %u\n", reg->space_id); return false; } static bool read_from_reg(const tboot_acpi_generic_address_t *reg, uint32_t *val) { if ( reg->address >= 100000000ULL ) { printk(TBOOT_ERR"GAS address >4GB (0x%Lx)\n", reg->address); return false; } uint32_t address = (uint32_t)reg->address; if ( reg->space_id == GAS_SYSTEM_IOSPACE ) { switch ( reg->bit_width ) { case 8: *val = inb(address); return true; case 16: *val = inw(address); return true; case 32: *val = inl(address); return true; default: printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width); return false; } } else if ( reg->space_id == GAS_SYSTEM_MEMORY ) { switch ( reg->bit_width ) { case 8: *val = readb(address); return true; case 16: *val = readw(address); return true; case 32: *val = readl(address); return true; default: printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width); return false; } } printk(TBOOT_ERR"unsupported GAS addr space ID: %u\n", reg->space_id); return false; } static void wait_to_sleep(const tboot_acpi_sleep_info_t *acpi_sinfo) { #define WAKE_STATUS 0x8000 /* the 15th bit */ while ( true ) { uint32_t pm1a_value = 0, pm1b_value = 0; if ( acpi_sinfo->pm1a_evt_blk.address ) { if ( read_from_reg(&acpi_sinfo->pm1a_evt_blk, &pm1a_value) && ( pm1a_value & WAKE_STATUS ) ) return; } if ( acpi_sinfo->pm1b_evt_blk.address ) { if ( read_from_reg(&acpi_sinfo->pm1b_evt_blk, &pm1b_value) && ( pm1b_value & WAKE_STATUS ) ) return; } } } bool machine_sleep(const tboot_acpi_sleep_info_t *acpi_sinfo) { dump_gas("PM1A", &acpi_sinfo->pm1a_cnt_blk); dump_gas("PM1B", &acpi_sinfo->pm1b_cnt_blk); wbinvd(); if ( acpi_sinfo->pm1a_cnt_blk.address ) { if ( !write_to_reg(&acpi_sinfo->pm1a_cnt_blk, acpi_sinfo->pm1a_cnt_val) ) return false;; } if ( acpi_sinfo->pm1b_cnt_blk.address ) { if ( !write_to_reg(&acpi_sinfo->pm1b_cnt_blk, acpi_sinfo->pm1b_cnt_val) ) return false; } /* just to wait, the machine may shutdown before here */ wait_to_sleep(acpi_sinfo); return true; } void set_s3_resume_vector(const tboot_acpi_sleep_info_t *acpi_sinfo, uint64_t resume_vector) { if ( acpi_sinfo->vector_width <= 32 ) *(uint32_t *)(unsigned long)(acpi_sinfo->wakeup_vector) = (uint32_t)resume_vector; else if ( acpi_sinfo->vector_width <= 64 ) *(uint64_t *)(unsigned long)(acpi_sinfo->wakeup_vector) = resume_vector; else printk(TBOOT_WARN"vector_width error.\n"); acpi_printk(TBOOT_DETA"wakeup_vector_address = %llx\n", acpi_sinfo->wakeup_vector); acpi_printk(TBOOT_DETA"wakeup_vector_value = %llxx\n", resume_vector); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/boot.S0000644000000000000000000003142014210363175014563 0ustar 00000000000000/* * boot.S: assembly bootstrapping code for tboot module * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #define BSP_STACK_SIZE 0x2000 #define AP_STACK_SIZE 0x0800 #define cs_sel 1<<3 #define ds_sel 2<<3 #define cs16_sel 4<<3 #define ds16_sel 5<<3 /* opcode prefixes for 16bit data and addressing */ #define DATA16 .byte 0x66 #define ADDR16 .byte 0x67 /* TXT config regs addrs/offsets */ #define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 #define TXTCR_STS 0x0000 #define TXTCR_ERRORCODE 0x0030 #define TXTCR_CMD_RESET 0x0038 #define TXTCR_CMD_UNLOCK_MEM_CONFIG 0x0218 #define TXTCR_HEAP_BASE 0x0300 /* OsSinitData field offsets */ #define MLE_PGTBL_OFF 8 /* errorcode for post-launch memory layout verfication failure */ #define LAYOUT_ERR 0xc0008001 /* Helpers macros from XEN source code */ .macro mb2ht_args arg:req, args:vararg .long \arg .ifnb \args mb2ht_args \args .endif .endm .macro mb2ht_init type:req, req:req, args:vararg .balign MULTIBOOT2_TAG_ALIGN, 0xc2 /* Avoid padding with long nops. */ .Lmb2ht_init_start\@: .short \type .short \req .long .Lmb2ht_init_end\@ - .Lmb2ht_init_start\@ .ifnb \args mb2ht_args \args .endif .Lmb2ht_init_end\@: .endm .section ".tboot_multiboot_header","w" .align 4 /* multiboot header */ multiboot_header: #define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_HEADER_MODS_ALIGNED | \ MULTIBOOT_HEADER_WANT_MEMORY) /* magic number for multiboot header */ .long MULTIBOOT_HEADER_MAGIC /* flags for bootloader */ .long MULTIBOOT_HEADER_FLAGS /* checksum: negated sum of above */ .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* multiboot2 header */ .align 8 multiboot2_header: .long MB2_HEADER_MAGIC .long MB2_ARCH_X86 .long multiboot2_header_end - multiboot2_header /* checksum */ .long -(MB2_HEADER_MAGIC + MB2_ARCH_X86 + (multiboot2_header_end - multiboot2_header)) /* Framebuffer tag */ mb2ht_init MB2_HDR_TAG_FRAMEBUFFER, MB2_HDR_TAG_OPTIONAL, \ FB_MAX_HRES, /* width */ \ FB_MAX_VRES, /* height */ \ FB_BPP /* depth */ /* Multiboot2 header end tag. */ mb2ht_init MB2_HDR_TAG_END, MB2_HDR_TAG_REQUIRED multiboot2_header_end: .size multiboot2_header, . - multiboot2_header .type multiboot2_header, @object .text ENTRY(start) ENTRY(_start) jmp __start /* entry point post-launch, to verify memory layout */ /* (must all be w/in one page; since _start is page-aligned, it will be; */ /* which is why we can't call much other code (e.g. printk, TPM fns, etc.) */ ENTRY(_post_launch_entry) /* verify phys addr we were entered at is the one we expected * ebx contains the phys addr of the entry point * ecx contains the phy addr of the MLE page table */ cmp $_post_launch_entry, %ebx jne layout_err /* verify last entry in MLE page table is the one we expected * this is sufficient because: 1) all addrs must be phys increasing * and 2) tboot is phys contig--therefore if any page were moved to * a different phys addr then the last page would have to be different * from tboot's last page */ /* get addr of MLE page table from OsSinitData */ /* start of TXT heap (== BiosDataSize) */ mov (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_HEAP_BASE), %eax add (%eax), %eax /* skip BiosData */ add (%eax), %eax /* skip OsMleData */ mov (MLE_PGTBL_OFF+8)(%eax), %eax /* addr of MLE page table */ /* get to page table itself (there is only one for tboot) */ mov (%eax), %eax /* pgdir ptr -> pgdir */ /* TODO when SINIT ready */ /* mov (%ecx), %eax */ and $PAGE_MASK, %eax mov (%eax), %eax /* pgdir -> pgtbl */ and $PAGE_MASK, %eax /* find last page (pte) */ mov $_mle_end, %ecx sub $_mle_start, %ecx /* size of MLE */ shr $PAGE_SHIFT-3, %ecx sub $8, %ecx /* size/4k*8 is offset+1 of last pte */ add %ecx, %eax mov (%eax), %eax /* pte of last page */ and $PAGE_MASK, %eax /* calc expected addr of last page */ mov $(_mle_end - 1), %ebx /* addr of last byte of MLE... */ and $PAGE_MASK, %ebx /* ...rounded to page start */ /* are they equal? */ cmp %ebx, %eax je __start /* yes, so continue with normal launch */ layout_err: /* layout check failed so TXT RESET */ /* set a special error code */ movl $LAYOUT_ERR, (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_ERRORCODE) /* unlock memory config (and serialize) */ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_CMD_UNLOCK_MEM_CONFIG) movl (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_STS), %eax /* TXT RESET */ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_CMD_RESET) mov $6, %eax mov $0xcf9, %edx out %al, (%dx) /* for debug chipsets where TXT RESET may not work */ ud2 ENTRY(__start) /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:gdt_descr mov $(ds_sel),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%fs mov %ecx,%gs mov %ecx,%ss ljmp $(cs_sel),$(1f) 1: leal bsp_stack,%esp /* Reset EFLAGS (subsumes CLI and CLD). */ pushl $0 popf /* preserve EAX to be a param to begin_launch--it should * contain either MULTIBOOT_MAGIC or MULTIBOOT2_MAGIC--we'll need * to figure out which */ mov %eax,%edx /* Initialize BSS (no nasty surprises!) */ mov $__bss_start,%edi mov $_end,%ecx sub %edi,%ecx xor %eax,%eax rep stosb /* Load IDT */ lidt idt_descr /* enable MCE */ mov %cr4,%eax or $CR4_MCE,%eax mov %eax,%cr4 /* pass multiboot info struct, magic and call measured launch code */ push %edx push %ebx call begin_launch ud2 ENTRY(__enable_nmi) pushf push %cs push $(1f) iret 1: ret /* * vmexit handler */ ENTRY(vmx_asm_vmexit_handler) call vmx_vmexit_handler /* fall through to loop if callee returns (shouldn't happen) */ ENTRY(_mini_guest) 1: pause cmp $0, (aps_exit_guest) je 1b /* VMCALL out of guest */ .byte 0x0f,0x01,0xc1 jmp 1b #include "shutdown.S" /* * entry point for GETSEC[WAKEUP] */ ENTRY(_txt_wakeup) # prepare this thread for C code /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:gdt_descr mov $0x10, %ecx mov %ecx, %ds mov %ecx, %es mov %ecx, %fs mov %ecx, %gs mov %ecx, %ss ljmp $(cs_sel), $(1f) /* Load IDT */ 1: lidt idt_descr /* enable MCE */ mov %cr4,%eax or $CR4_MCE,%eax mov %eax,%cr4 # get initial 32-bit local APIC ID for this processor mov $0x0b, %eax xor %edx, %edx cpuid # set stack as id-based offset from AP stack base # spin hlt if we exceed, since C code can't handle shared stack cmp $NR_CPUS, %edx jl 3f # TBD: increment global counter so BSP can tell we exceeded NR_CPUS 2: cli hlt jmp 2b 3: mov $AP_STACK_SIZE, %eax mul %edx mov $ap_stacks, %ecx sub %eax, %ecx mov %ecx, %esp call txt_cpu_wakeup /* * entry point for switch to real mode and jump * entry point in %ebx */ ENTRY(_prot_to_real) /* disable interrupts */ cli mov 0x4(%esp), %ebx /* deal with parameter, real mode program entry point */ mov %ebx, %eax and $0xffff0, %eax shr $4, %eax mov %ax, _real_mode_entry_point + 4 and $0xfff0000f, %ebx mov %ebx, _real_mode_entry_point /* load proper segments for real mode */ mov $(ds16_sel), %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss lidt real_idt_desc xor %eax, %eax ljmp $(cs16_sel), $(1f) .code16 1: mov %eax, %cr0 mov $0x0, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss .code32 DATA16 ADDR16 ljmp *_real_mode_entry_point /* * interrupt handler */ int_handler: call handle_exception ud2 /* * descriptors and descriptor tables */ .align 8 /* GDT */ gdt_descr: .word gdt_table_end - gdt_table - 1 .long gdt_table .align PAGE_SIZE, 0 ENTRY(gdt_table) /* unused */ .quad 0x0000000000000000 cs_descr: /* cs */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9b00 /* read + exec + accessed */ .word 0x00cf /* granularity = 4096 */ ds_descr: /* ds */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9300 /* read + write + accessed */ .word 0x00cf /* granularity = 4096 */ tss_descr: /* tss */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x8900 /* system segment, 32b available TSS */ .word 0x008f /* granularity = 4096 */ cs16_desc: /* cs16 */ .word 0xffff /* limit = 4GB */ .word 0x0000 /* base = 0 */ .word 0x9b00 /* read + exec + accessed */ .word 0x008f /* granularity = 4096, D = 0 */ ds16_desc: /* ds16 */ .word 0xffff /* limit = 4GB */ .word 0x0000 /* base = 0 */ .word 0x9300 /* read + exec + accessed */ .word 0x008f /* granularity = 4096, D = 0 */ /* end (unused) */ .quad 0x0000000000000000 ENTRY(gdt_table_end) /* IDT */ idt_descr: .word idt_table_end - idt_table - 1 .long idt_table .align 8 idt_table: .rept 18 .word int_handler - _start .word cs_sel .word 0x8e00 /* present, DPL=0, 32b, interrupt */ .word (int_handler - _start + TBOOT_START) >> 16 .endr /* for machine-check exception */ .word int_handler - _start .word cs_sel .word 0x8f00 /* present, DPL=0, 32b, trap */ .word (int_handler - _start + TBOOT_START) >> 16 .rept 237 .word int_handler - _start .word cs_sel .word 0x8e00 /* present, DPL=0, 32b, interrupt */ .word (int_handler - _start + TBOOT_START) >> 16 .endr idt_table_end: /* Real Mode IDT */ real_idt_desc: .word 0x03ff .long 0 #include "wakeup.S" /* * stacks */ .section ".bss.stack_aligned","w" bsp_stack_end: .fill BSP_STACK_SIZE, 1, 0 bsp_stack: ap_stacks_end: .fill AP_STACK_SIZE * NR_CPUS, 1, 0 ap_stacks: /* * page table and VMCS data for AP bringup */ .align PAGE_SIZE, 0 .section ".bss.page_aligned","w" ENTRY(idle_pg_table) .fill 1*PAGE_SIZE,1,0 .align PAGE_SIZE, 0 ENTRY(host_vmcs) .fill 1*PAGE_SIZE,1,0 .align PAGE_SIZE, 0 /* the input info when os/vmm kerneltrap into tboot */ ENTRY(ap_vmcs) .fill NR_CPUS * PAGE_SIZE, 1, 0 /* * misc. bss data */ .section ".bss" _real_mode_entry_point: .long 0 .word 0 .section ".data" ENTRY(s3_flag) .long 0 /* * shared data page with kernel (i.e. Xen) * (put at end so that not split e820 region for tboot) */ .section ".tboot_shared","w" .align PAGE_SIZE, 0 ENTRY(_tboot_shared) .fill PAGE_SIZE,1,0 .align PAGE_SIZE, 0 ENTRY(_end) tboot-1.10.5/tboot/common/cmdline.c0000644000000000000000000004476214210363175015270 0ustar 00000000000000/* * cmdline.c: command line parsing fns * * Copyright (c) 2006-2012, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef IS_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* * copy of original command line * part of tboot measurement (hence in .text section) */ __text char g_cmdline[CMDLINE_SIZE] = { 0 }; /* Used for kernel command line parameter setup */ typedef struct { const char *name; /* set to NULL for last item in list */ const char *def_val; } cmdline_option_t; #define MAX_VALUE_LEN 64 /* * the option names and default values must be separate from the actual * params entered * this allows the names and default values to be part of the MLE measurement * param_values[] need to be in .bss section so that will get cleared on launch */ /* global option array for command line */ static const cmdline_option_t g_tboot_cmdline_options[] = { { "loglvl", "all" }, /* all|err,warn,info|none */ { "logging", "serial,vga" }, /* vga,serial,memory|none */ { "serial", "115200,8n1,0x3f8" }, /* serial=[/][,[,[,[,[,]]]]] */ { "vga_delay", "0" }, /* # secs */ { "ap_wake_mwait", "false" }, /* true|false */ { "pcr_map", "legacy" }, /* legacy|da */ { "min_ram", "0" }, /* size in bytes | 0 for no min */ { "call_racm", "false" }, /* true|false|check */ { "measure_nv", "false" }, /* true|false */ { "extpol", "sha256" }, /*agile|embedded|sha1|sha256|sm3|... */ { "ignore_prev_err", "true"}, /* true|false */ { "force_tpm2_legacy_log", "false"}, /* true|false */ { "save_vtd", "false"}, /* true|false */ { "dump_memmap", "false"}, /* true|false */ { NULL, NULL } }; static char g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN]; static const cmdline_option_t g_linux_cmdline_options[] = { { "vga", "" }, { "mem", "" }, { NULL, NULL } }; static char g_linux_param_values[ARRAY_SIZE(g_linux_cmdline_options)][MAX_VALUE_LEN]; typedef struct { const char *log_name; uint8_t log_val; } tb_loglvl_map_t; /* map */ static const tb_loglvl_map_t g_loglvl_map[] = { { "none", TBOOT_LOG_LEVEL_NONE }, { "err", TBOOT_LOG_LEVEL_ERR }, { "warn", TBOOT_LOG_LEVEL_WARN }, { "info", TBOOT_LOG_LEVEL_INFO }, { "detail",TBOOT_LOG_LEVEL_DETA }, { "all", TBOOT_LOG_LEVEL_ALL }, }; static const char* get_option_val(const cmdline_option_t *options, char vals[][MAX_VALUE_LEN], const char *opt_name) { for ( int i = 0; options[i].name != NULL; i++ ) { if ( tb_strcmp(options[i].name, opt_name) == 0 ) return vals[i]; } printk(TBOOT_ERR"requested unknown option: %s\n", opt_name); return NULL; } static void cmdline_parse(const char *cmdline, const cmdline_option_t *options, char vals[][MAX_VALUE_LEN]) { const char *p = cmdline; int i; /* copy default values to vals[] */ for ( i = 0; options[i].name != NULL; i++ ) { tb_strncpy(vals[i], options[i].def_val, MAX_VALUE_LEN-1); vals[i][MAX_VALUE_LEN-1] = '\0'; } if ( p == NULL ) return; /* parse options */ while ( true ) { /* skip whitespace */ while ( isspace(*p) ) p++; if ( *p == '\0' ) break; /* find end of current option */ const char *opt_start = p; const char *opt_end = tb_strchr(opt_start, ' '); if ( opt_end == NULL ) opt_end = opt_start + tb_strlen(opt_start); p = opt_end; /* find value part; if no value found, use default and continue */ const char *val_start = tb_strchr(opt_start, '='); if ( val_start == NULL || val_start > opt_end ) continue; val_start++; unsigned int opt_name_size = val_start - opt_start - 1; unsigned int copy_size = opt_end - val_start; if ( copy_size > MAX_VALUE_LEN - 1 ) copy_size = MAX_VALUE_LEN - 1; if ( opt_name_size == 0 || copy_size == 0 ) continue; /* value found, so copy it */ for ( i = 0; options[i].name != NULL; i++ ) { if ( tb_strncmp(options[i].name, opt_start, opt_name_size ) == 0 ) { tb_strncpy(vals[i], val_start, copy_size); vals[i][copy_size] = '\0'; /* add '\0' to the end of string */ break; } } } } void tboot_parse_cmdline(void) { cmdline_parse(g_cmdline, g_tboot_cmdline_options, g_tboot_param_values); } void linux_parse_cmdline(const char *cmdline) { cmdline_parse(cmdline, g_linux_cmdline_options, g_linux_param_values); } uint8_t get_loglvl_prefix(char **pbuf, int *len) { uint8_t log_level = TBOOT_LOG_LEVEL_ALL; if ( *len > 2 && **pbuf == '<' && *(*pbuf+2) == '>' && isdigit(*(*pbuf+1)) ) { unsigned int i = *(*pbuf+1) - '0'; if ( i < ARRAY_SIZE(g_loglvl_map) ) log_level = g_loglvl_map[i].log_val; *pbuf += 3; *len = *len - 3; } return log_level; } void get_tboot_loglvl(void) { const char *loglvl = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "loglvl"); if ( loglvl == NULL ) return; /* determine whether the target is set explicitly */ while ( isspace(*loglvl) ) loglvl++; g_log_level = TBOOT_LOG_LEVEL_NONE; while ( *loglvl != '\0' ) { unsigned int i; for ( i = 0; i < ARRAY_SIZE(g_loglvl_map); i++ ) { if ( tb_strncmp(loglvl, g_loglvl_map[i].log_name, tb_strlen(g_loglvl_map[i].log_name)) == 0 ) { loglvl += tb_strlen(g_loglvl_map[i].log_name); if ( g_loglvl_map[i].log_val == TBOOT_LOG_LEVEL_NONE ) { g_log_level = TBOOT_LOG_LEVEL_NONE; return; } else { g_log_level |= g_loglvl_map[i].log_val; break; } } } if ( i == ARRAY_SIZE(g_loglvl_map) ) break; /* unrecognized, end loop */ /* skip ',' */ if ( *loglvl == ',' ) loglvl++; else break; /* unrecognized, end loop */ } } void get_tboot_log_targets(void) { const char *targets = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "logging"); /* nothing set, leave defaults */ if ( targets == NULL || *targets == '\0' ) return; /* determine if no targets set explicitly */ if ( tb_strcmp(targets, "none") == 0 ) { g_log_targets = TBOOT_LOG_TARGET_NONE; /* print nothing */ return; } /* else init to nothing and parse the possible targets */ g_log_targets = TBOOT_LOG_TARGET_NONE; while ( *targets != '\0' ) { if ( tb_strncmp(targets, "memory", 6) == 0 ) { g_log_targets |= TBOOT_LOG_TARGET_MEMORY; targets += 6; } else if ( tb_strncmp(targets, "serial", 6) == 0 ) { g_log_targets |= TBOOT_LOG_TARGET_SERIAL; targets += 6; } else if ( tb_strncmp(targets, "vga", 3) == 0 ) { g_log_targets |= TBOOT_LOG_TARGET_VGA; targets += 3; } else break; /* unrecognized, end loop */ if ( *targets == ',' ) targets++; else break; /* unrecognized, end loop */ } } static bool parse_pci_bdf(const char **bdf, uint32_t *bus, uint32_t *slot, uint32_t *func) { *bus = tb_strtoul(*bdf, (char **)bdf, 16); if ( **bdf != ':' ) return false; (*bdf)++; *slot = tb_strtoul(*bdf, (char **)bdf, 16); if ( **bdf != '.' ) return false; (*bdf)++; *func = tb_strtoul(*bdf, (char **)bdf, 16); return true; } bool g_psbdf_enabled = false; static bool parse_com_psbdf(const char **bdf) { g_psbdf_enabled = parse_pci_bdf(bdf, &g_com_port.comc_psbdf.bus, &g_com_port.comc_psbdf.slot, &g_com_port.comc_psbdf.func); return g_psbdf_enabled; } bool g_pbbdf_enabled = false; static bool parse_com_pbbdf(const char **bdf) { g_pbbdf_enabled = parse_pci_bdf(bdf, &g_com_port.comc_pbbdf.bus, &g_com_port.comc_pbbdf.slot, &g_com_port.comc_pbbdf.func); return g_pbbdf_enabled; } static bool parse_com_fmt(const char **fmt) { /* fmt: <5|6|7|8><0|1> */ /* default 8n1 */ uint8_t data_bits = 8; uint8_t parity = 'n'; uint8_t stop_bits = 1; /* must specify all values */ if ( tb_strlen(*fmt) < 3 ) return false; /* data bits */ if ( **fmt >= '5' && **fmt <= '8' ) data_bits = **fmt - '0'; else return false; (*fmt)++; /* parity */ if ( **fmt == 'n' || **fmt == 'o' || **fmt == 'e' || **fmt == 'm' || **fmt == 's' ) parity = **fmt; else return false; (*fmt)++; /* stop bits */ if ( **fmt == '0' || **fmt == '1' ) stop_bits = **fmt - '0'; else return false; (*fmt)++; g_com_port.comc_fmt = GET_LCR_VALUE(data_bits, stop_bits, parity); return true; } static bool parse_serial_param(const char *com) { /* parse baud */ g_com_port.comc_curspeed = tb_strtoul(com, (char **)&com, 10); if ( (g_com_port.comc_curspeed < 1200) || (g_com_port.comc_curspeed > 115200) ) return false; /* parse clock hz */ if ( *com == '/' ) { ++com; g_com_port.comc_clockhz = tb_strtoul(com, (char **)&com, 0) << 4; if ( g_com_port.comc_clockhz == 0 ) return false; } /* parse data_bits/parity/stop_bits */ if ( *com != ',' ) goto exit; ++com; while ( isspace(*com) ) com++; if ( !parse_com_fmt(&com) ) return false; /* parse IO base */ if ( *com != ',' ) goto exit; ++com; g_com_port.comc_port = tb_strtoul(com, (char **)&com, 0); if ( g_com_port.comc_port == 0 ) return false; /* parse irq */ if ( *com != ',' ) goto exit; ++com; g_com_port.comc_irq = tb_strtoul(com, (char **)&com, 10); if ( g_com_port.comc_irq == 0 ) return false; /* parse PCI serial controller bdf */ if ( *com != ',' ) goto exit; ++com; if ( !parse_com_psbdf(&com) ) return false; /* parse PCI bridge bdf */ if ( *com != ',' ) goto exit; ++com; if ( !parse_com_pbbdf(&com) ) return false; exit: return true; } bool get_tboot_serial(void) { const char *serial = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "serial"); if ( serial == NULL || *serial == '\0' ) return false; return parse_serial_param(serial); } void get_tboot_vga_delay(void) { const char *vga_delay = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "vga_delay"); if ( vga_delay == NULL ) return; g_vga_delay = tb_strtoul(vga_delay, NULL, 0); } bool get_tboot_prefer_da(void) { const char *value = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "pcr_map"); if ( value != NULL && tb_strcmp(value, "da") == 0 ) return true; return false; } extern uint32_t g_min_ram; void get_tboot_min_ram(void) { const char *min_ram = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "min_ram"); if ( min_ram == NULL ) return; g_min_ram = tb_strtoul(min_ram, NULL, 0); } bool get_tboot_mwait(void) { const char *mwait = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "ap_wake_mwait"); if ( mwait == NULL || tb_strcmp(mwait, "false") == 0 ) return false; return true; } bool get_tboot_call_racm(void) { const char *call_racm = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "call_racm"); if ( call_racm == NULL || tb_strcmp(call_racm, "true") != 0 ) return false; return true; } bool get_tboot_call_racm_check(void) { const char *call_racm = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "call_racm"); if ( call_racm == NULL || tb_strcmp(call_racm, "check") != 0 ) return false; return true; } bool get_tboot_measure_nv(void) { const char *measure_nv = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "measure_nv"); if ( measure_nv == NULL || tb_strcmp(measure_nv, "true") != 0 ) return false; return true; } void get_tboot_extpol(void) { const char *extpol = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "extpol"); struct tpm_if *tpm = get_tpm(); if ( extpol == NULL ) { tpm->extpol = TB_EXTPOL_FIXED; tpm->cur_alg = TB_HALG_SHA256; return; } if ( tb_strcmp(extpol, "agile") == 0 ) { tpm->extpol = TB_EXTPOL_AGILE; tpm->cur_alg = TB_HALG_SHA256; } else if ( tb_strcmp(extpol, "embedded") == 0 ) { tpm->extpol = TB_EXTPOL_EMBEDDED; tpm->cur_alg = TB_HALG_SHA256; } else if ( tb_strcmp(extpol, "sha256") == 0 ) { tpm->extpol = TB_EXTPOL_FIXED; tpm->cur_alg = TB_HALG_SHA256; } else if ( tb_strcmp(extpol, "sha1") == 0 ) { printk(TBOOT_WARN"Warning: SHA1 is selected in extpol, this is an unsafe option\n"); tpm->extpol = TB_EXTPOL_FIXED; tpm->cur_alg = TB_HALG_SHA1; } else if ( tb_strcmp(extpol, "sm3") == 0 ) { tpm->extpol = TB_EXTPOL_FIXED; tpm->cur_alg = TB_HALG_SM3; } else if ( tb_strcmp(extpol, "sha384") == 0 ) { tpm->extpol = TB_EXTPOL_FIXED; tpm->cur_alg = TB_HALG_SHA384; } else if ( tb_strcmp(extpol, "sha512") == 0 ) { tpm->extpol = TB_EXTPOL_FIXED; tpm->cur_alg = TB_HALG_SHA512; } } bool get_tboot_force_tpm2_legacy_log(void) { const char *force_legacy_log = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "force_tpm2_legacy_log"); if ( force_legacy_log != NULL && tb_strcmp(force_legacy_log, "true") == 0 ) return true; return false; } bool get_tboot_ignore_prev_err(void) { const char *ignore_prev_err = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "ignore_prev_err"); if ( ignore_prev_err == NULL || tb_strcmp(ignore_prev_err, "true") == 0 ) return true; return false; } bool get_tboot_save_vtd(void) { const char *save_vtd = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "save_vtd"); if ( save_vtd != NULL && tb_strcmp(save_vtd, "true") == 0 ) return true; return false; } bool get_tboot_dump_memmap(void) { const char *dump_memmap = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "dump_memmap"); if ( dump_memmap != NULL && tb_strcmp(dump_memmap, "true") == 0 ) return true; return false; } /* * linux kernel command line parsing */ bool get_linux_vga(int *vid_mode) { const char *vga = get_option_val(g_linux_cmdline_options, g_linux_param_values, "vga"); if ( vga == NULL || vid_mode == NULL ) return false; if ( tb_strcmp(vga, "normal") == 0 ) *vid_mode = 0xFFFF; else if ( tb_strcmp(vga, "ext") == 0 ) *vid_mode = 0xFFFE; else if ( tb_strcmp(vga, "ask") == 0 ) *vid_mode = 0xFFFD; else *vid_mode = tb_strtoul(vga, NULL, 0); return true; } bool get_linux_mem(uint64_t *max_mem) { char *last = NULL; const char *mem = get_option_val(g_linux_cmdline_options, g_linux_param_values, "mem"); if ( mem == NULL || max_mem == NULL ) return false; *max_mem = tb_strtoul(mem, &last, 0); if ( *max_mem == 0 ) return false; if ( last == NULL ) return true; switch ( *last ) { case 'G': case 'g': *max_mem = *max_mem << 30; return true; case 'M': case 'm': *max_mem = *max_mem << 20; return true; case 'K': case 'k': *max_mem = *max_mem << 10; return true; default: return false; } return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/com.c0000644000000000000000000001005014210363175014412 0ustar 00000000000000/*- * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /* * Portions copyright (c) 2010, Intel Corporation */ /* * sys/boot/i386/libi386/comconsole.c */ #include #include #include #include #include #include #include #define COMC_TXWAIT 0x40000 /* transmit timeout */ #define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ #define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ #define OUTB(add, val) outb(g_com_port.comc_port + (add), (val)) #define INB(add) inb(g_com_port.comc_port + (add)) serial_port_t g_com_port = {115200, 0, 0x3, COM1_ADDR}; /* com1,115200,8n1 */ extern bool g_psbdf_enabled; extern bool g_pbbdf_enabled; extern struct mutex pcicfg_mtx; static void comc_putchar(int c) { int wait; for ( wait = COMC_TXWAIT; wait > 0; wait-- ) if ( INB(com_lsr) & LSR_TXRDY ) { OUTB(com_data, (u_char)c); break; } } static void comc_setup(int speed) { OUTB(com_cfcr, CFCR_DLAB | g_com_port.comc_fmt); OUTB(com_dlbl, COMC_BPS(speed) & 0xff); OUTB(com_dlbh, COMC_BPS(speed) >> 8); OUTB(com_cfcr, g_com_port.comc_fmt); OUTB(com_mcr, MCR_RTS | MCR_DTR); for ( int wait = COMC_TXWAIT; wait > 0; wait-- ) { INB(com_data); if ( !(INB(com_lsr) & LSR_RXRDY) ) break; } } static void comc_pci_setup(void) { if ( g_psbdf_enabled ) { if ( g_pbbdf_enabled ) { pcireg_cfgwrite(g_com_port.comc_pbbdf.bus, g_com_port.comc_pbbdf.slot, g_com_port.comc_pbbdf.func, PCIR_IOBASEL_1, (g_com_port.comc_port & 0xF000) | ((g_com_port.comc_port & 0xF000) >> 8), 2); } pcireg_cfgwrite(g_com_port.comc_psbdf.bus, g_com_port.comc_psbdf.slot, g_com_port.comc_psbdf.func, PCIR_BARS, g_com_port.comc_port | 0x1, 4); pcireg_cfgwrite(g_com_port.comc_psbdf.bus, g_com_port.comc_psbdf.slot, g_com_port.comc_psbdf.func, PCIR_COMMAND, 0x1, 2); mtx_init(&pcicfg_mtx); } } void comc_init(void) { comc_pci_setup(); comc_setup(g_com_port.comc_curspeed); } void comc_puts(const char *s, unsigned int cnt) { while ( *s && cnt-- ) { if ( *s == '\n' ) comc_putchar('\r'); comc_putchar(*s++); } } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/e820.c0000644000000000000000000006024514210363175014325 0ustar 00000000000000/* * e820.c: support functions for manipulating the e820 table * * Copyright (c) 2006-2012, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* minimum size of RAM (type 1) region that cannot be marked as reserved even if it comes after a reserved region; 0 for no minimum (i.e. current behavior) */ uint32_t g_min_ram = 0; /* * copy of bootloader/BIOS e820 table with adjusted entries * this version will replace original in mbi */ #define MAX_E820_ENTRIES (TBOOT_E820_COPY_SIZE / sizeof(memory_map_t)) static unsigned int g_nr_map; static memory_map_t *g_copy_e820_map = (memory_map_t *)TBOOT_E820_COPY_ADDR; static inline void split64b(uint64_t val, uint32_t *val_lo, uint32_t *val_hi) { *val_lo = (uint32_t)(val & 0xffffffff); *val_hi = (uint32_t)(val >> 32); } static inline uint64_t combine64b(uint32_t val_lo, uint32_t val_hi) { return ((uint64_t)val_hi << 32) | (uint64_t)val_lo; } static inline uint64_t e820_base_64(memory_map_t *entry) { return combine64b(entry->base_addr_low, entry->base_addr_high); } static inline uint64_t e820_length_64(memory_map_t *entry) { return combine64b(entry->length_low, entry->length_high); } /* * print_e820_map * * Prints copied e820 map w/o any header (i.e. just entries, indented by a tab) * */ static void print_map(memory_map_t *e820, int nr_map) { for ( int i = 0; i < nr_map; i++ ) { memory_map_t *entry = &e820[i]; uint64_t base_addr, length; base_addr = e820_base_64(entry); length = e820_length_64(entry); printk(TBOOT_DETA"\t%016Lx - %016Lx (%d)\n", (unsigned long long)base_addr, (unsigned long long)(base_addr + length), entry->type); } } static bool insert_after_region(memory_map_t *e820map, unsigned int *nr_map, unsigned int pos, uint64_t addr, uint64_t size, uint32_t type) { /* no more room */ if ( *nr_map + 1 > MAX_E820_ENTRIES ) return false; /* shift (copy) everything up one entry */ for ( unsigned int i = *nr_map - 1; i > pos; i--) e820map[i+1] = e820map[i]; /* now add our entry */ split64b(addr, &(e820map[pos+1].base_addr_low), &(e820map[pos+1].base_addr_high)); split64b(size, &(e820map[pos+1].length_low), &(e820map[pos+1].length_high)); e820map[pos+1].type = type; e820map[pos+1].size = sizeof(memory_map_t) - sizeof(uint32_t); (*nr_map)++; return true; } static void remove_region(memory_map_t *e820map, unsigned int *nr_map, unsigned int pos) { /* shift (copy) everything down one entry */ for ( unsigned int i = pos; i < *nr_map - 1; i++) e820map[i] = e820map[i+1]; (*nr_map)--; } static bool protect_region(memory_map_t *e820map, unsigned int *nr_map, uint64_t new_addr, uint64_t new_size, uint32_t new_type) { uint64_t addr, tmp_addr, size, tmp_size; uint32_t type; unsigned int i; if ( new_size == 0 ) return true; /* check for wrap */ if ( new_addr + new_size < new_addr ) return false; /* find where our region belongs in the table and insert it */ for ( i = 0; i < *nr_map; i++ ) { addr = e820_base_64(&e820map[i]); size = e820_length_64(&e820map[i]); type = e820map[i].type; /* is our region at the beginning of the current map region? */ if ( new_addr == addr ) { if ( !insert_after_region(e820map, nr_map, i-1, new_addr, new_size, new_type) ) return false; break; } /* are we w/in the current map region? */ else if ( new_addr > addr && new_addr < (addr + size) ) { if ( !insert_after_region(e820map, nr_map, i, new_addr, new_size, new_type) ) return false; /* fixup current region */ tmp_addr = e820_base_64(&e820map[i]); split64b(new_addr - tmp_addr, &(e820map[i].length_low), &(e820map[i].length_high)); i++; /* adjust to always be that of our region */ /* insert a copy of current region (before adj) after us so */ /* that rest of code can be common with previous case */ if ( !insert_after_region(e820map, nr_map, i, addr, size, type) ) return false; break; } /* is our region in a gap in the map? */ else if ( addr > new_addr ) { if ( !insert_after_region(e820map, nr_map, i-1, new_addr, new_size, new_type) ) return false; break; } } /* if we reached the end of the map without finding an overlapping */ /* region, insert us at the end (note that this test won't trigger */ /* for the second case above because the insert() will have incremented */ /* nr_map and so i++ will still be less) */ if ( i == *nr_map ) { if ( !insert_after_region(e820map, nr_map, i-1, new_addr, new_size, new_type) ) return false; return true; } i++; /* move to entry after our inserted one (we're not at end yet) */ tmp_addr = e820_base_64(&e820map[i]); tmp_size = e820_length_64(&e820map[i]); /* did we split the (formerly) previous region? */ if ( (new_addr >= tmp_addr) && ((new_addr + new_size) < (tmp_addr + tmp_size)) ) { /* then adjust the current region (adj size first) */ split64b((tmp_addr + tmp_size) - (new_addr + new_size), &(e820map[i].length_low), &(e820map[i].length_high)); split64b(new_addr + new_size, &(e820map[i].base_addr_low), &(e820map[i].base_addr_high)); return true; } /* if our region completely covers any existing regions, delete them */ while ( (i < *nr_map) && ((new_addr + new_size) >= (tmp_addr + tmp_size)) ) { remove_region(e820map, nr_map, i); tmp_addr = e820_base_64(&e820map[i]); tmp_size = e820_length_64(&e820map[i]); } /* finally, if our region partially overlaps an existing region, */ /* then truncate the existing region */ if ( i < *nr_map ) { tmp_addr = e820_base_64(&e820map[i]); tmp_size = e820_length_64(&e820map[i]); if ( (new_addr + new_size) > tmp_addr ) { split64b((tmp_addr + tmp_size) - (new_addr + new_size), &(e820map[i].length_low), &(e820map[i].length_high)); split64b(new_addr + new_size, &(e820map[i].base_addr_low), &(e820map[i].base_addr_high)); } } return true; } /* * is_overlapped * * Detect whether two ranges are overlapped. * * return: true = overlapped */ static bool is_overlapped(uint64_t base, uint64_t end, uint64_t e820_base, uint64_t e820_end) { uint64_t length = end - base, e820_length = e820_end - e820_base; uint64_t min, max; min = (base < e820_base)?base:e820_base; max = (end > e820_end)?end:e820_end; /* overlapping */ if ( (max - min) < (length + e820_length) ) return true; if ( (max - min) == (length + e820_length) && ( ((length == 0) && (base > e820_base) && (base < e820_end)) || ((e820_length == 0) && (e820_base > base) && (e820_base < end)) ) ) return true; return false; } /* helper funcs for loader.c */ memory_map_t *get_e820_copy() { return g_copy_e820_map; } unsigned int get_nr_map() { return g_nr_map; } /* * copy_e820_map * * Copies the raw e820 map from bootloader to new table with room for expansion * * return: false = error (no table or table too big for new space) */ bool copy_e820_map(loader_ctx *lctx) { get_tboot_min_ram(); g_nr_map = 0; if (have_loader_memmap(lctx)){ uint32_t memmap_length = get_loader_memmap_length(lctx); memory_map_t *memmap = get_loader_memmap(lctx); printk(TBOOT_DETA"original e820 map:\n"); print_map(memmap, memmap_length/sizeof(memory_map_t)); uint32_t entry_offset = 0; while ( entry_offset < memmap_length && g_nr_map < MAX_E820_ENTRIES ) { memory_map_t *entry = (memory_map_t *) (((uint32_t) memmap) + entry_offset); /* we want to support unordered and/or overlapping entries */ /* so use protect_region() to insert into existing map, since */ /* it handles these cases */ if ( !protect_region(g_copy_e820_map, &g_nr_map, e820_base_64(entry), e820_length_64(entry), entry->type) ) return false; if (lctx->type == 1) entry_offset += entry->size + sizeof(entry->size); if (lctx->type == 2) /* the MB2 memory map entries don't have a size-- * they have a "zero" with a value of zero. Additionally, * because they *end* with a size and the MB1 guys *start* * with a size, we get into trouble if we try to use them, */ entry_offset += sizeof(memory_map_t); } if ( g_nr_map == MAX_E820_ENTRIES ) { printk(TBOOT_ERR"Too many e820 entries\n"); return false; } } else if ( have_loader_memlimits(lctx) ) { printk(TBOOT_DETA"no e820 map, mem_lower=%x, mem_upper=%x\n", get_loader_mem_lower(lctx), get_loader_mem_upper(lctx)); /* lower limit is 0x00000000 - *0x400 (i.e. in kb) */ g_copy_e820_map[0].base_addr_low = 0; g_copy_e820_map[0].base_addr_high = 0; g_copy_e820_map[0].length_low = (get_loader_mem_lower(lctx)) << 10; g_copy_e820_map[0].length_high = 0; g_copy_e820_map[0].type = E820_RAM; g_copy_e820_map[0].size = sizeof(memory_map_t) - sizeof(uint32_t); /* upper limit is 0x00100000 - *0x400 */ g_copy_e820_map[1].base_addr_low = 0x100000; g_copy_e820_map[1].base_addr_high = 0; split64b((uint64_t)(get_loader_mem_upper(lctx)) << 10, &(g_copy_e820_map[1].length_low), &(g_copy_e820_map[1].length_high)); g_copy_e820_map[1].type = E820_RAM; g_copy_e820_map[1].size = sizeof(memory_map_t) - sizeof(uint32_t); g_nr_map = 2; } else { printk(TBOOT_ERR"no e820 map nor memory limits provided\n"); return false; } return true; } bool e820_protect_region(uint64_t addr, uint64_t size, uint32_t type) { return protect_region(g_copy_e820_map, &g_nr_map, addr, size, type); } /* * e820_check_region * * Given a range, check which kind of range it covers * * return: E820_GAP, it covers gap in e820 map; * E820_MIXED, it covers at least two different kinds of ranges; * E820_XXX, it covers E820_XXX range only; * it will not return 0. */ uint32_t e820_check_region(uint64_t base, uint64_t length) { memory_map_t* e820_entry; uint64_t end = base + length, e820_base, e820_end, e820_length; uint32_t type; uint32_t ret = 0; bool gap = true; /* suppose there is always a virtual gap at first */ e820_base = 0; e820_length = 0; for ( unsigned int i = 0; i < g_nr_map; i = gap ? i : i+1, gap = !gap ) { e820_entry = &g_copy_e820_map[i]; if ( gap ) { /* deal with the gap in e820 map */ e820_base = e820_base + e820_length; e820_length = e820_base_64(e820_entry) - e820_base; type = E820_GAP; } else { /* deal with the normal item in e820 map */ e820_base = e820_base_64(e820_entry); e820_length = e820_length_64(e820_entry); type = e820_entry->type; } if ( e820_length == 0 ) continue; /* if the range is zero, then skip */ e820_end = e820_base + e820_length; if ( !is_overlapped(base, end, e820_base, e820_end) ) continue; /* if no overlapping, then skip */ /* if the value of ret is not assigned before, then set ret to type directly */ if ( ret == 0 ) { ret = type; continue; } /* if the value of ret is assigned before but ret is equal to type, then no need to do anything */ if ( ret == type ) continue; /* if the value of ret is assigned before but it is GAP, then no need to do anything since any type merged with GAP is GAP */ if ( ret == E820_GAP ) continue; /* if the value of ret is assigned before but it is not GAP and type is GAP now this time, then set ret to GAP since any type merged with GAP is GAP. */ if ( type == E820_GAP ) { ret = E820_GAP; continue; } /* if the value of ret is assigned before but both ret and type are not GAP and their values are not equal, then set ret to MIXED since any two non-GAP values are merged into MIXED if they are not equal. */ ret = E820_MIXED; } /* deal with the last gap */ if ( is_overlapped(base, end, e820_base + e820_length, (uint64_t)-1) ) ret = E820_GAP; /* print the result */ printk(TBOOT_DETA" (range from %016Lx to %016Lx is in ", base, base + length); switch (ret) { case E820_RAM: printk(TBOOT_INFO"E820_RAM)\n"); break; case E820_RESERVED: printk(TBOOT_INFO"E820_RESERVED)\n"); break; case E820_ACPI: printk(TBOOT_INFO"E820_ACPI)\n"); break; case E820_NVS: printk(TBOOT_INFO"E820_NVS)\n"); break; case E820_UNUSABLE: printk(TBOOT_INFO"E820_UNUSABLE)\n"); break; case E820_GAP: printk(TBOOT_INFO"E820_GAP)\n"); break; case E820_MIXED: printk(TBOOT_INFO"E820_MIXED)\n"); break; default: printk(TBOOT_INFO"UNKNOWN)\n"); } return ret; } /* * e820_reserve_ram * * Given the range, any ram range in e820 is in it, change type to reserved. * * return: false = error */ bool e820_reserve_ram(uint64_t base, uint64_t length) { memory_map_t* e820_entry; uint64_t e820_base, e820_length, e820_end; uint64_t end; if ( length == 0 ) return true; end = base + length; /* find where our region should cover the ram in e820 */ for ( unsigned int i = 0; i < g_nr_map; i++ ) { e820_entry = &g_copy_e820_map[i]; e820_base = e820_base_64(e820_entry); e820_length = e820_length_64(e820_entry); e820_end = e820_base + e820_length; /* if not ram, no need to deal with */ if ( e820_entry->type != E820_RAM ) continue; /* if the range is before the current ram range, skip the ram range */ if ( end <= e820_base ) continue; /* if the range is after the current ram range, skip the ram range */ if ( base >= e820_end ) continue; /* case 1: the current ram range is within the range: base, e820_base, e820_end, end */ if ( (base <= e820_base) && (e820_end <= end) ) e820_entry->type = E820_RESERVED; /* case 2: overlapping: base, e820_base, end, e820_end */ else if ( (e820_base >= base) && (end > e820_base) && (e820_end > end) ) { /* split the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i-1, e820_base, (end - e820_base), E820_RESERVED) ) return false; /* fixup the current ram map */ i++; split64b(end, &(g_copy_e820_map[i].base_addr_low), &(g_copy_e820_map[i].base_addr_high)); split64b(e820_end - end, &(g_copy_e820_map[i].length_low), &(g_copy_e820_map[i].length_high)); /* no need to check more */ break; } /* case 3: overlapping: e820_base, base, e820_end, end */ else if ( (base > e820_base) && (e820_end > base) && (end >= e820_end) ) { /* fixup the current ram map */ split64b((base - e820_base), &(g_copy_e820_map[i].length_low), &(g_copy_e820_map[i].length_high)); /* split the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i, base, (e820_end - base), E820_RESERVED) ) return false; i++; } /* case 4: the range is within the current ram range: e820_base, base, end, e820_end */ else if ( (base > e820_base) && (e820_end > end) ) { /* fixup the current ram map */ split64b((base - e820_base), &(g_copy_e820_map[i].length_low), &(g_copy_e820_map[i].length_high)); /* split the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i, base, length, E820_RESERVED) ) return false; i++; /* fixup the rest of the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i, end, (e820_end - end), e820_entry->type) ) return false; i++; /* no need to check more */ break; } else { printk(TBOOT_ERR"we should never get here\n"); return false; } } return true; } void print_e820_map(void) { print_map(g_copy_e820_map, g_nr_map); } bool get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram, uint64_t *min_hi_ram, uint64_t *max_hi_ram) { if ( min_lo_ram == NULL || max_lo_ram == NULL || min_hi_ram == NULL || max_hi_ram == NULL ) return false; *min_lo_ram = *min_hi_ram = ~0ULL; *max_lo_ram = *max_hi_ram = 0; bool found_reserved_region = false; uint64_t last_min_ram_base = 0, last_min_ram_size = 0; /* * if g_min_ram > 0, we will never mark a region > g_min_ram in size * as reserved even if it is after a reserved region (effectively * we ignore reserved regions below the last type 1 region * > g_min_ram in size) * so in order to reserve RAM regions above this last region, we need * to find it first so that we can tell when we have passed it */ if ( g_min_ram > 0 ) { e820_get_highest_sized_ram(g_min_ram, 0x100000000ULL, &last_min_ram_base, &last_min_ram_size); printk(TBOOT_DETA"highest min_ram (0x%x) region found: base=0x%Lx, size=0x%Lx\n", g_min_ram, last_min_ram_base, last_min_ram_size); } for ( unsigned int i = 0; i < g_nr_map; i++ ) { memory_map_t *entry = &g_copy_e820_map[i]; uint64_t base = e820_base_64(entry); uint64_t limit = base + e820_length_64(entry); if ( entry->type == E820_RAM ) { /* if range straddles 4GB boundary, that is an error */ if ( base < 0x100000000ULL && limit > 0x100000000ULL ) { printk(TBOOT_ERR"e820 memory range straddles 4GB boundary\n"); return false; } /* * some BIOSes put legacy USB buffers in reserved regions <4GB, * which if DMA protected cause SMM to hang, so make sure that * we don't overlap any of these even if that wastes RAM * ...unless min_ram was specified */ if ( !found_reserved_region || base <= last_min_ram_base ) { if ( base < 0x100000000ULL && base < *min_lo_ram ) *min_lo_ram = base; if ( limit <= 0x100000000ULL && limit > *max_lo_ram ) *max_lo_ram = limit; } else { /* need to reserve low RAM above reserved regions */ if ( base < 0x100000000ULL ) { printk(TBOOT_DETA"discarding RAM above reserved regions: 0x%Lx - 0x%Lx\n", base, limit); if ( !e820_reserve_ram(base, limit - base) ) return false; if (!efi_memmap_reserve(base, limit - base)) { return false; } } } if ( base >= 0x100000000ULL && base < *min_hi_ram ) *min_hi_ram = base; if ( limit > 0x100000000ULL && limit > *max_hi_ram ) *max_hi_ram = limit; } else { /* parts of low memory may be reserved for cseg, ISA hole, etc. but these seem OK to DMA protect, so ignore reserved regions <0x100000 */ if ( *min_lo_ram != ~0ULL && limit > 0x100000ULL ) found_reserved_region = true; } } /* no low RAM found */ if ( *min_lo_ram >= *max_lo_ram ) { printk(TBOOT_ERR"no low ram in e820 map\n"); return false; } /* no high RAM found */ if ( *min_hi_ram >= *max_hi_ram ) *min_hi_ram = *max_hi_ram = 0; return true; } /* find highest (< ) RAM region of at least bytes */ bool e820_get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size) { uint64_t last_fit_base = 0, last_fit_size = 0; if ( ram_base == NULL || ram_size == NULL ) return false; for ( unsigned int i = 0; i < g_nr_map; i++ ) { memory_map_t *entry = &g_copy_e820_map[i]; if ( entry->type == E820_RAM ) { uint64_t base = e820_base_64(entry); uint64_t length = e820_length_64(entry); /* over 4GB so use the last region that fit */ if ( base + length > limit ) break; if ( size <= length ) { last_fit_base = base; last_fit_size = length; } } } if (last_fit_size == 0) { return false; } else { *ram_base = last_fit_base; *ram_size = last_fit_size; return true; } } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/efi_memmap.c0000644000000000000000000003022714210363175015743 0ustar 00000000000000/* * efi_memmap.c: EFI memory map parsing functions * * Copyright (c) 2006-2020, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include static bool efi_mmap_available = false; static efi_memmap_t* efi_mmap = (efi_memmap_t*)TBOOT_EFI_MEMMAP_COPY_ADDR; static bool insert_after_region(uint32_t pos, uint64_t addr, uint64_t size, uint32_t type, uint64_t attr); static bool region_is_free(uint32_t region_type); /** * @brief Copy memory map from mbi to defined memory space to allow insertion * of new entries * * @param lctx loader context with mbi */ bool efi_memmap_copy(loader_ctx *lctx) { uint32_t descr_addr, descr_ver, descr_size, mmap_size; descr_addr = find_efi_memmap(lctx, &descr_size, &descr_ver, &mmap_size); if (descr_addr == 0 || descr_ver != EFI_MEMORY_DESCRIPTOR_VERSION) { printk(TBOOT_WARN"Failed to get EFI memory map\n"); return false; } if (mmap_size < TBOOT_EFI_MEMMAP_COPY_SIZE - offsetof(efi_memmap_t, descr)) { efi_mmap->size = mmap_size; efi_mmap->descr_size = descr_size; tb_memcpy(efi_mmap->descr, (void*)descr_addr, mmap_size); efi_mmap_available = true; return true; } else { printk(TBOOT_WARN"Too many entries in EFI memory map\n"); return false; } } /** * @brief Get address of memory map descriptors * * @param descr_size return size of each descriptor * @param descr_vers return descriptor version * @param mmap_size return sum of all descriptors size */ uint32_t efi_memmap_get_addr(uint32_t *descr_size, uint32_t *descr_vers, uint32_t *mmap_size) { if (!efi_mmap_available) { return 0; } if (descr_size != NULL) { *descr_size = efi_mmap->descr_size; } if (descr_vers != NULL) { *descr_vers = EFI_MEMORY_DESCRIPTOR_VERSION; } if (mmap_size != NULL) { *mmap_size = efi_mmap->size; } return (uint32_t)efi_mmap->descr; } /** * @brief Walk through memory map descriptors * * @param prev pointer to previous descriptor, when NULL start interating from * first one */ efi_mem_descr_t* efi_memmap_walk(efi_mem_descr_t* prev) { if (!efi_mmap_available) { printk(TBOOT_WARN"EFI memory map not available\n"); return NULL; } if (prev == NULL) { return (efi_mem_descr_t*)efi_mmap->descr; } else if ((uint32_t)prev < (uint32_t)efi_mmap->descr) { /* * Should never happens, just to prevent overflow in below * substraction */ return NULL; } else { uint32_t next = (uint32_t)prev + efi_mmap->descr_size; if (next - (uint32_t)efi_mmap->descr < efi_mmap->size) { return (efi_mem_descr_t*)next; } else { return NULL; } } } /** * @brief Mark given memory region as reserved * * Region will be changed to EFI_RESERVED_TYPE, if given region already has type * that indicates that it is not free, type will not be changed. Non-free means * other than loader, boot, runtime and conventional memory types. * * Region has to be aligned to page size, function will round non-aligned * values. Base address is rounded down, length - up. * * If the specified region lies within a gap, a new region will be added * * @param base starting address * @param length length of region to reserve */ bool efi_memmap_reserve(uint64_t base, uint64_t length) { if (length == 0 || !efi_mmap_available) { return true; } /* Round to page size */ uint64_t mask = ~((1ULL << EFI_PAGE_SHIFT) - 1ULL); base &= mask; if (length & ~mask) { length &= mask; length += (1ULL << EFI_PAGE_SHIFT); } uint64_t end = base + length; efi_mem_descr_t* desc = NULL; uint32_t i = 0; bool in_range = false; while ((desc = efi_memmap_walk(desc)) != NULL) { uint64_t desc_base = desc->physical_start; uint64_t desc_length = desc->num_pages << EFI_PAGE_SHIFT; uint64_t desc_end = desc_base + desc_length; /* if already unusable, no need to deal with */ if (desc->type < EFI_LOADER_CODE || desc->type > EFI_CONVENTIONAL_MEMORY) { goto cont; } /* if the range is before the current ram range, skip the ram range */ if (end <= desc_base) { goto cont; } /* if the range is after the current ram range, skip the ram range */ if (base >= desc_end) { goto cont; } /* In all cases below, the current range is involved */ in_range = true; /* case 1: the current ram range is within the range: base, desc_base, desc_end, end */ if ((base <= desc_base) && (desc_end <= end)) { desc->type = EFI_RESERVED_TYPE; } /* case 2: overlapping: base, e820_base, end, e820_end */ else if ((desc_base >= base) && (end > desc_base) && (desc_end > end)) { /* split the current ram map */ if (!insert_after_region(i-1, desc_base, (end - desc_base), EFI_RESERVED_TYPE, desc->attribute)) { return false; } /* fixup the current ram map */ desc = efi_memmap_walk(desc); ++i; desc->physical_start = end; desc->num_pages = (desc_end - end) >> EFI_PAGE_SHIFT; /* no need to check more */ break; } /* case 3: overlapping: desc_base, base, desc_end, end */ else if ((base > desc_base) && (desc_end > base) && (end >= desc_end)) { /* fixup the current ram map */ desc->num_pages = (base - desc_base) >> EFI_PAGE_SHIFT; /* split the current ram map */ if (!insert_after_region(i, base, (desc_end - base), EFI_RESERVED_TYPE, desc->attribute)) { return false; } desc = efi_memmap_walk(desc); ++i; } /* case 4: the range is within the current ram range: desc_base, base, end, desc_end */ else if ((base > desc_base) && (desc_end > end)) { /* fixup the current ram map */ desc->num_pages = (base - desc_base) >> EFI_PAGE_SHIFT; /* split the current ram map */ if (!insert_after_region(i, base, length, EFI_RESERVED_TYPE, desc->attribute)) { return false; } ++i; /* fixup the rest of the current ram map */ if (!insert_after_region(i, end, (desc_end - end), desc->type, desc->attribute)) { return false; } desc = efi_memmap_walk(desc); desc = efi_memmap_walk(desc); ++i; /* no need to check more */ break; } else { printk(TBOOT_ERR"we should never get here\n"); return false; } cont: ++i; } /* Insert the new region */ if ( !in_range ) { desc = efi_memmap_walk(NULL); if( !insert_after_region(0, base, length, EFI_RESERVED_TYPE, 0) ) { return false; } } return true; } /** * @brief Print whole memory map */ void efi_memmap_dump(void) { efi_mem_descr_t* desc = NULL; while ((desc = efi_memmap_walk(desc)) != NULL) { printk(TBOOT_INFO" %016llx - %016llx (%-2d | 0x%llx)\n", desc->physical_start, desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT), desc->type, desc->attribute); } } /** * @brief Find in memory map highest avaliable free space that meets given * requirements * * Free space is a region in memory map of following types: * - EFI_LOADER_CODE * - EFI_LOADER_DATA * - EFI_CONVENTIONAL_MEMORY * Boot services memory is excluded because it can be occupied by tables * that Linux may want to access later, ex. EFI_MEMORY_ATTRIBUTES_TABLE * * @param size minimal size * @param limit highest possible address * @param ram_base return address of found region * @param ram_size return size of found region, bigger or equal @p size */ bool efi_memmap_get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size) { uint64_t last_fit_base = 0, last_fit_size = 0; if (ram_base == NULL || ram_size == NULL || !efi_mmap_available) { return false; } efi_mem_descr_t* desc = NULL; while ((desc = efi_memmap_walk(desc)) != NULL) { if (region_is_free(desc->type)) { uint64_t base = desc->physical_start; uint64_t length = desc->num_pages * (1 << EFI_PAGE_SHIFT); /* over 4GB so use the last region that fit */ if ( base + length > limit ) break; if ( size <= length ) { last_fit_base = base; last_fit_size = length; } } } printk("get_highest_sized_ram: size %llx -> base %llx, size %llx\n", size, last_fit_base, last_fit_size); if (last_fit_size == 0) { return false; } else { *ram_base = last_fit_base; *ram_size = last_fit_size; return true; } } static bool insert_after_region(uint32_t pos, uint64_t addr, uint64_t size, uint32_t type, uint64_t attr) { /* no more room */ if (efi_mmap->size / efi_mmap->descr_size + 1 > EFI_MEMMAP_MAX_ENTRIES) return false; pos *= efi_mmap->descr_size; /* shift (copy) everything up one entry */ for (uint32_t i = efi_mmap->size; i > pos; i -= efi_mmap->descr_size) { uint32_t bytes = efi_mmap->descr_size; void* to = efi_mmap->descr + i; void* from = efi_mmap->descr + i - bytes; tb_memcpy(to, from, bytes); } efi_mem_descr_t* desc = (efi_mem_descr_t*)(efi_mmap->descr + pos + efi_mmap->descr_size); tb_memset(desc, 0, efi_mmap->descr_size); desc->type = type; desc->physical_start = addr; desc->num_pages = size >> EFI_PAGE_SHIFT; desc->attribute = attr; efi_mmap->size += efi_mmap->descr_size; return true; } static bool region_is_free(uint32_t region_type) { if (region_type == EFI_LOADER_CODE || region_type == EFI_LOADER_DATA || region_type == EFI_CONVENTIONAL_MEMORY) { return true; } else { return false; } }tboot-1.10.5/tboot/common/elf.c0000644000000000000000000002035414210363175014412 0ustar 00000000000000/* * elf.c: support functions for manipulating ELF binaries * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include extern loader_ctx *g_ldr_ctx; bool elf64 = false; bool is_elf_image(const void *image, size_t size) { elf_header_t *elf; if ( image == NULL ) { printk(TBOOT_ERR"Error: Pointer is zero.\n"); return false; } /* check size */ if ( sizeof(elf_header_t) > size ) { printk(TBOOT_ERR"Error: Image size is smaller than ELF header size.\n"); return false; } elf = (elf_header_t *)image; /* check magic number for ELF */ if ( (elf->e_ident[EI_MAG0] != ELFMAG0) || (elf->e_ident[EI_MAG1] != ELFMAG1) || (elf->e_ident[EI_MAG2] != ELFMAG2) || (elf->e_ident[EI_MAG3] != ELFMAG3) ) { printk(TBOOT_WARN"ELF magic number is not matched, image is not ELF format.\n"); return false; } /* check data encoding in ELF */ if ( elf->e_ident[EI_DATA] != ELFDATA2LSB ) { printk(TBOOT_ERR"Error: ELF data encoding is not the least significant " "byte occupying the lowest address.\n"); return false; } /* check obj class in ELF */ if ( elf->e_ident[EI_CLASS] == ELFCLASS32 ) { printk(TBOOT_INFO"This is an ELF32 file.\n"); elf64 = false; elf_header_t *elf; elf = (elf_header_t *)image; /* check ELF image is executable? */ if ( elf->e_type != ET_EXEC ) { printk(TBOOT_ERR"Error: ELF image is not executable.\n"); return false; } /* check ELF image is for IA? */ if ( elf->e_machine != EM_386 && elf->e_machine != EM_AMD64 ) { printk(TBOOT_ERR"Error: ELF image is not for IA.\n"); return false; } /* check ELF version is valid? */ if ( elf->e_version != EV_CURRENT ) { printk(TBOOT_ERR"Error: ELF version is invalid.\n"); return false; } if ( sizeof(elf_program_header_t) > elf->e_phentsize ) { printk(TBOOT_ERR"Error: Program size is smaller than program " "header size.\n"); return false; } return true; } if ( elf->e_ident[EI_CLASS] == ELFCLASS64 ) { printk(TBOOT_INFO"This is an ELF64 file.\n"); elf64 = true; elf64_header_t *elf; elf = (elf64_header_t *)image; /* check ELF image is executable? */ if ( elf->e_type != ET_EXEC ) { printk(TBOOT_ERR"Error: ELF image is not executable.\n"); return false; } /* check ELF image is for IA? */ if ( elf->e_machine != EM_386 && elf->e_machine != EM_AMD64) { printk(TBOOT_ERR"Error: ELF image is not for IA.\n"); return false; } /* check ELF version is valid? */ if ( elf->e_version != EV_CURRENT ) { printk(TBOOT_ERR"Error: ELF version is invalid.\n"); return false; } if ( sizeof(elf64_program_header_t) > elf->e_phentsize ) { printk(TBOOT_ERR"Error: Program size is smaller than program " "header size.\n"); return false; } return true; } return false; } bool get_elf_image_range(const elf_header_t *elf, void **start, void **end) { uint32_t u_start, u_end; if (elf == NULL) { printk(TBOOT_ERR"Error: ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ if ((start == NULL) || (end == NULL)) { printk(TBOOT_ERR"Error: Output pointers are zero.\n"); return false; } u_start = 0; u_end = 0; for ( int i = 0; i < elf->e_phnum; i++ ) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if (ph->p_type == PT_LOAD) { if (u_start > ph->p_paddr) u_start = ph->p_paddr; if (u_end < ph->p_paddr+ph->p_memsz) u_end = ph->p_paddr+ph->p_memsz; } } if (u_start >= u_end) { printk(TBOOT_ERR"Error: PT_LOAD header not found\n"); *start = NULL; *end = NULL; return false; } else { *start = (void *)u_start; *end = (void *)u_end; return true; } } bool expand_elf_image(const void *image, void **entry_point) { if ( image == NULL ) { printk(TBOOT_ERR"Error: ELF header pointer is zero.\n"); return false; } if ( entry_point == NULL ) { printk(TBOOT_ERR"Error: Output pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ if (elf64) { elf64_header_t *elf; elf = (elf64_header_t *)image; /* load elf image into memory */ for ( int i = 0; i < elf->e_phnum; i++ ) { elf64_program_header_t *ph = (elf64_program_header_t *)((void *)elf + elf->e_phoff + i*elf->e_phentsize); if ( ph->p_type == PT_LOAD ) { tb_memcpy((void *)(unsigned long)ph->p_paddr, (void *)elf +(unsigned long) ph->p_offset,(unsigned long) ph->p_filesz); //tb_memcpy((void *)ph->p_paddr, (void *)elf + ph->p_offset, ph->p_filesz); tb_memset((void *)(unsigned long)(ph->p_paddr + ph->p_filesz), 0, (unsigned long)ph->p_memsz -(unsigned long) ph->p_filesz); //tb_memset((void *)(ph->p_paddr + ph->p_filesz), 0, ph->p_memsz - ph->p_filesz); } } *entry_point = (void *)(unsigned long)(elf->e_entry); //*entry_point = (void *)(elf->e_entry); return true; } else { elf_header_t *elf; elf = (elf_header_t *)image; /* load elf image into memory */ for ( int i = 0; i < elf->e_phnum; i++ ) { elf_program_header_t *ph = (elf_program_header_t *)((void *)elf + elf->e_phoff + i*elf->e_phentsize); if ( ph->p_type == PT_LOAD ) { tb_memcpy((void *)ph->p_paddr, (void *)elf + ph->p_offset, ph->p_filesz); tb_memset((void *)(ph->p_paddr + ph->p_filesz), 0, ph->p_memsz - ph->p_filesz); } } *entry_point = (void *)elf->e_entry; return true; } } bool jump_elf_image(void *entry_point, uint32_t magic) { __asm__ __volatile__ ( " jmp *%%ecx; " " ud2; " :: "a" (magic), "b" (g_ldr_ctx->addr), "c" (entry_point)); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/hash.c0000644000000000000000000001447014210363175014571 0ustar 00000000000000/* * hash.c: support functions for tb_hash_t type * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include /* * are_hashes_equal * * compare whether two hash values are equal. * */ bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { unsigned int len; if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) { printk(TBOOT_ERR"Error: hash pointer is zero.\n"); return false; } len = get_hash_size(hash_alg); if ( len > 0 ) return (tb_memcmp(hash1, hash2, len) == 0); else { printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg); return false; } } /* * hash_buffer * * hash the buffer according to the algorithm * */ bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { printk(TBOOT_ERR"Error: There is no space for output hash.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) { sha1_buffer(buf, size, hash->sha1); return true; } else if ( hash_alg == TB_HALG_SHA256 ) { sha256_buffer(buf, size, hash->sha256); return true; } else if ( hash_alg == TB_HALG_SHA384 ) { sha384_buffer(buf, size, hash->sha384); return true; } else if ( hash_alg == TB_HALG_SHA512 ) { sha512_buffer(buf, size, hash->sha512); return true; } else if ( hash_alg == TB_HALG_SM3 ) { printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg); return false; } else { printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg); return false; } } /* * extend_hash * * perform "extend" of two hashes (i.e. hash1 = SHA(hash1 || hash2) * */ bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { uint8_t buf[2*get_hash_size(hash_alg)]; if ( hash1 == NULL || hash2 == NULL ) { printk(TBOOT_ERR"Error: There is no space for output hash.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) { tb_memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); tb_memcpy(buf + sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1)); sha1_buffer(buf, 2*sizeof(hash1->sha1), hash1->sha1); return true; } else if ( hash_alg == TB_HALG_SHA256 ) { tb_memcpy(buf, &(hash1->sha256), sizeof(hash1->sha256)); tb_memcpy(buf + sizeof(hash1->sha256), &(hash2->sha256), sizeof(hash1->sha256)); sha256_buffer(buf, 2*sizeof(hash1->sha256), hash1->sha256); return true; } else if ( hash_alg == TB_HALG_SHA384 ) { tb_memcpy(buf, &(hash1->sha384), sizeof(hash1->sha384)); tb_memcpy(buf + sizeof(hash1->sha384), &(hash2->sha384), sizeof(hash1->sha384)); sha384_buffer(buf, 2*sizeof(hash1->sha384), hash1->sha384); return true; } else if ( hash_alg == TB_HALG_SHA512 ) { tb_memcpy(buf, &(hash1->sha512), sizeof(hash1->sha512)); tb_memcpy(buf + sizeof(hash1->sha512), &(hash2->sha512), sizeof(hash1->sha512)); sha512_buffer(buf, 2*sizeof(hash1->sha512), hash1->sha512); return true; } else if ( hash_alg == TB_HALG_SM3 ) { printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg); return false; } else { printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg); return false; } } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { printk(TBOOT_WARN"NULL"); return; } if ( hash_alg == TB_HALG_SHA1 ) print_hex(NULL, (uint8_t *)hash->sha1, sizeof(hash->sha1)); else if ( hash_alg == TB_HALG_SHA256 ) print_hex(NULL, (uint8_t *)hash->sha256, sizeof(hash->sha256)); else if ( hash_alg == TB_HALG_SM3 ) print_hex(NULL, (uint8_t *)hash->sm3, sizeof(hash->sm3)); else if ( hash_alg == TB_HALG_SHA384 ) print_hex(NULL, (uint8_t *)hash->sha384, sizeof(hash->sha384)); else { printk(TBOOT_WARN"unsupported hash alg (%u)\n", hash_alg); return; } } void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg) { unsigned int len; if ( dest_hash == NULL || src_hash == NULL ) { printk(TBOOT_WARN"hashes are NULL\n"); return; } len = get_hash_size(hash_alg); if ( len > 0 ) tb_memcpy(dest_hash, src_hash, len); else printk(TBOOT_WARN"unsupported hash alg (%u)\n", hash_alg); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/index.c0000644000000000000000000000377114210363175014757 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* * From: FreeBSD: sys/libkern/index.c */ #include /* * index() is also present as the strchr() in the kernel; it does exactly the * same thing as it's userland equivalent. */ char *tb_index(p, ch) const char *p; int ch; { union { const char *cp; char *p; } u; if (p == NULL) return(NULL); u.cp = p; for (;; ++u.p) { if (*u.p == ch) return(u.p); if (*u.p == '\0') return(NULL); } /* NOTREACHED */ } tboot-1.10.5/tboot/common/integrity.c0000644000000000000000000004343114210363175015663 0ustar 00000000000000/* * integrity.c: routines for memory integrity measurement & * verification. Memory integrity is protected with tpm seal * * Copyright (c) 2007-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char _end[]; /* put in .data section to that they aren't cleared on S3 resume */ /* state whose integrity needs to be maintained across S3 */ __data pre_k_s3_state_t g_pre_k_s3_state; __data post_k_s3_state_t g_post_k_s3_state; /* state sealed before extending PCRs and launching kernel */ static __data uint8_t sealed_pre_k_state[2048]; static __data uint32_t sealed_pre_k_state_size; /* state sealed just before entering S3 (after kernel shuts down) */ static __data uint8_t sealed_post_k_state[2048]; static __data uint32_t sealed_post_k_state_size; /* PCR 17+18 values post-launch and before extending (used to seal verified launch hashes and memory integrity UMAC) */ __data tpm_pcr_value_t post_launch_pcr17, post_launch_pcr18; extern tboot_shared_t _tboot_shared; extern bool hash_policy(tb_hash_t *hash, uint16_t hash_alg); extern void apply_policy(tb_error_t error); #define EVTTYPE_TB_MEASUREMENT (0x400 + 0x101) extern bool evtlog_append(uint8_t pcr, hash_list_t *hl, uint32_t type); typedef struct { uint8_t mac_key[POLY1305_KEY_SIZE]; uint8_t shared_key[sizeof(_tboot_shared.s3_key)]; } sealed_secrets_t; static bool extend_pcrs(void) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { if ( !tpm_fp->pcr_extend(tpm, 2, g_pre_k_s3_state.vl_entries[i].pcr, &g_pre_k_s3_state.vl_entries[i].hl) ) return false; if ( !evtlog_append(g_pre_k_s3_state.vl_entries[i].pcr, &g_pre_k_s3_state.vl_entries[i].hl, EVTTYPE_TB_MEASUREMENT) ) return false; } return true; } static void print_pre_k_s3_state(void) { struct tpm_if *tpm = get_tpm(); printk(TBOOT_DETA"pre_k_s3_state:\n"); printk(TBOOT_DETA"\t vtd_pmr_lo_base: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_lo_base); printk(TBOOT_DETA"\t vtd_pmr_lo_size: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_lo_size); printk(TBOOT_DETA"\t vtd_pmr_hi_base: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_hi_base); printk(TBOOT_DETA"\t vtd_pmr_hi_size: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_hi_size); printk(TBOOT_DETA"\t pol_hash: "); print_hash(&g_pre_k_s3_state.pol_hash, tpm->cur_alg); printk(TBOOT_DETA"\t VL measurements:\n"); for ( unsigned int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { printk(TBOOT_DETA"\t PCR %d (alg count %d):\n", g_pre_k_s3_state.vl_entries[i].pcr, g_pre_k_s3_state.vl_entries[i].hl.count); for ( unsigned int j = 0; j < g_pre_k_s3_state.vl_entries[i].hl.count; j++ ) { printk(TBOOT_DETA"\t\t alg %04X: ", g_pre_k_s3_state.vl_entries[i].hl.entries[j].alg); print_hash(&g_pre_k_s3_state.vl_entries[i].hl.entries[j].hash, g_pre_k_s3_state.vl_entries[i].hl.entries[j].alg); } } } static void print_post_k_s3_state(void) { printk(TBOOT_DETA"post_k_s3_state:\n"); printk(TBOOT_DETA"\t kernel_s3_resume_vector: 0x%Lx\n", g_post_k_s3_state.kernel_s3_resume_vector); printk(TBOOT_DETA"\t kernel_integ: "); print_hex(NULL, &g_post_k_s3_state.kernel_integ, sizeof(g_post_k_s3_state.kernel_integ)); } static bool seal_data(const void *data, size_t data_size, const void *secrets, size_t secrets_size, uint8_t *sealed_data, uint32_t *sealed_data_size) { /* TPM_Seal can only seal small data (like key or hash), so hash data */ struct __packed { sha256_hash_t data_hash; uint8_t secrets[secrets_size]; } blob; uint32_t err; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); tb_memset(&blob, 0, sizeof(blob)); if ( !hash_buffer(data, data_size, (tb_hash_t *)&blob.data_hash, TB_HALG_SHA256) ) { printk(TBOOT_ERR"failed to hash data\n"); return false; } if ( secrets != NULL && secrets_size > 0 ) tb_memcpy(blob.secrets, secrets, secrets_size); err = tpm_fp->seal(tpm, 2, sizeof(blob), (const uint8_t *)&blob, sealed_data_size, sealed_data); if ( !err ) printk(TBOOT_WARN"failed to seal data\n"); /* since blob might contain secret, clear it */ tb_memset(&blob, 0, sizeof(blob)); return err; } static bool verify_sealed_data(const uint8_t *sealed_data, uint32_t sealed_data_size, const void *curr_data, size_t curr_data_size, void *secrets, size_t secrets_size) { /* sealed data is hash of state data and optional secret */ struct __packed { sha256_hash_t data_hash; uint8_t secrets[secrets_size]; } blob; bool err = true; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); uint32_t data_size = sizeof(blob); if ( !tpm_fp->unseal(tpm, tpm->cur_loc, sealed_data_size, sealed_data, &data_size, (uint8_t *)&blob) ) { printk(TBOOT_ERR"failed to unseal blob\n"); return false; } if ( data_size != sizeof(blob) ) { printk(TBOOT_WARN"unsealed state data size mismatch\n"); goto done; } /* verify that (hash of) current data matches sealed hash */ tb_hash_t curr_data_hash; tb_memset(&curr_data_hash, 0, sizeof(curr_data_hash)); if ( !hash_buffer(curr_data, curr_data_size, &curr_data_hash, TB_HALG_SHA256) ) { printk(TBOOT_WARN"failed to hash state data\n"); goto done; } if ( !are_hashes_equal((tb_hash_t *)&blob.data_hash, &curr_data_hash, TB_HALG_SHA256) ) { printk(TBOOT_WARN"sealed hash does not match current hash\n"); goto done; } if ( secrets != NULL && secrets_size > 0 ) tb_memcpy(secrets, &blob.secrets, secrets_size); err = false; done: /* clear secret from local memory */ tb_memset(&blob, 0, sizeof(blob)); return !err; } /* * pre- PCR extend/kernel launch S3 data are sealed to PCRs 17+18 with * post-launch values (i.e. before extending) */ bool seal_pre_k_state(void) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); /* save hash of current policy into g_pre_k_s3_state */ tb_memset(&g_pre_k_s3_state.pol_hash, 0, sizeof(g_pre_k_s3_state.pol_hash)); if ( !hash_policy(&g_pre_k_s3_state.pol_hash, tpm->cur_alg) ) { printk(TBOOT_ERR"failed to hash policy\n"); goto error; } print_pre_k_s3_state(); /* read PCR 17/18, only for tpm1.2 */ if ( tpm->major == TPM12_VER_MAJOR ) { if ( !tpm_fp->pcr_read(tpm, 2, 17, &post_launch_pcr17) || !tpm_fp->pcr_read(tpm, 2, 18, &post_launch_pcr18) ) goto error; } sealed_pre_k_state_size = sizeof(sealed_pre_k_state); if ( !seal_data(&g_pre_k_s3_state, sizeof(g_pre_k_s3_state), NULL, 0, sealed_pre_k_state, &sealed_pre_k_state_size) ) goto error; /* we can't leave the system in a state without valid measurements of about-to-execute code in the PCRs, so this is a fatal error */ if ( !extend_pcrs() ) { apply_policy(TB_ERR_FATAL); return false; } return true; /* even if sealing fails, we must extend PCRs to represent valid measurements of about-to-execute code */ error: if ( !extend_pcrs() ) apply_policy(TB_ERR_FATAL); return false; } static bool measure_memory_integrity(uint8_t* mac, uint8_t* key) { POLY1305 ctx; unsigned long virt = MAC_VIRT_START; /* we require memory is 4K page aligned in tboot */ #define MAC_ALIGN PAGE_SIZE COMPILE_TIME_ASSERT(MAC_VIRT_SIZE >= MAC_PAGE_SIZE); COMPILE_TIME_ASSERT((unsigned long)(-1) - MAC_VIRT_START > MAC_VIRT_SIZE ); COMPILE_TIME_ASSERT(PAGE_SIZE % POLY1305_BLOCK_SIZE == 0); /* enable paging */ if ( !enable_paging() ) return false; sse_enable(); Poly1305_Init(&ctx, key); for ( unsigned int i = 0; i < _tboot_shared.num_mac_regions; i++ ) { uint64_t start = _tboot_shared.mac_regions[i].start; /* overflow? */ if ( plus_overflow_u64(start, _tboot_shared.mac_regions[i].size) ) { printk(TBOOT_ERR"start plus size overflows during MACing\n"); return false; } /* if not overflow, we get end */ uint64_t end = start + _tboot_shared.mac_regions[i].size; start = start & ~(MAC_ALIGN - 1); end = (end - 1) | (MAC_ALIGN - 1); /* overflow? */ if ( plus_overflow_u64(end, 1) ) { printk(TBOOT_ERR"end up to the alignment overflows during MACing\n"); return false; } /* if not overflow, we get end aligned */ end++; printk(TBOOT_DETA"MACing region %u: 0x%Lx - 0x%Lx\n", i, start, end); /* * spfn: start pfn in 2-Mbyte page * epfn: end pfn in 2-Mbyte page * align_base: start physical address, which is 2-Mbyte page aligned */ /* check overflow? */ if ( plus_overflow_u64(end, MAC_PAGE_SIZE) ) { printk(TBOOT_ERR"end plus MAC_PAGE_SIZE overflows during MACing\n"); return false; } unsigned long spfn; unsigned long epfn = (unsigned long)((end + MAC_PAGE_SIZE - 1) >> TB_L1_PAGETABLE_SHIFT); unsigned long nr_pfns, nr_virt_pfns; uint64_t align_base; unsigned long valign_base, vstart, vend; do { spfn = (unsigned long)(start >> TB_L1_PAGETABLE_SHIFT); align_base = (uint64_t)spfn << TB_L1_PAGETABLE_SHIFT; valign_base = virt; vstart = valign_base + (unsigned long)(start - align_base); nr_pfns = epfn - spfn; nr_virt_pfns = (MAC_VIRT_END - virt) >> TB_L1_PAGETABLE_SHIFT; if ( nr_virt_pfns >= nr_pfns ) { /* region can fit into the rest virtual space */ map_pages_to_tboot(valign_base, spfn, nr_pfns); vend = valign_base + (unsigned long)(end - align_base); virt += nr_pfns << TB_L1_PAGETABLE_SHIFT; start = end; } else { /* region cannot fit into the rest virtual space, will trunc */ map_pages_to_tboot(valign_base, spfn, nr_virt_pfns); vend = MAC_VIRT_END; virt = MAC_VIRT_START; start = align_base + (nr_virt_pfns << TB_L1_PAGETABLE_SHIFT); } /* MAC the 2-Mbyte pages */ while ( (vend > vstart) && ((vend - vstart) >= MAC_PAGE_SIZE) ) { Poly1305_Update(&ctx, (uint8_t *)(uintptr_t)vstart, MAC_PAGE_SIZE); vstart += MAC_PAGE_SIZE; } /* MAC the rest */ if ( vend > vstart ) Poly1305_Update(&ctx, (uint8_t *)(uintptr_t)vstart, vend - vstart); /* destroy the mapping */ if ( virt == MAC_VIRT_START ) destroy_tboot_mapping(MAC_VIRT_START, MAC_VIRT_END); } while ( start < end ); } Poly1305_Final(&ctx, mac); /* return to protected mode without paging */ if (!disable_paging()) return false; return true; } /* * verify memory integrity and sealed VL hashes, then re-extend hashes * * this must be called post-launch but before extending any modules or other * measurements into PCRs */ bool verify_integrity(void) { tpm_pcr_value_t pcr17, pcr18; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); /* read PCR 17/18, only for tpm1.2 */ if ( tpm->major == TPM12_VER_MAJOR ) { if ( !tpm_fp->pcr_read(tpm, 2, 17, &pcr17) || !tpm_fp->pcr_read(tpm, 2, 18, &pcr18) ) goto error; printk(TBOOT_DETA"PCRs before unseal:\n"); printk(TBOOT_DETA" PCR 17: "); print_hash((tb_hash_t *)&pcr17, TB_HALG_SHA1); printk(TBOOT_DETA" PCR 18: "); print_hash((tb_hash_t *)&pcr18, TB_HALG_SHA1); } /* verify integrity of pre-kernel state data */ printk(TBOOT_INFO"verifying pre_k_s3_state\n"); if ( !verify_sealed_data(sealed_pre_k_state, sealed_pre_k_state_size, &g_pre_k_s3_state, sizeof(g_pre_k_s3_state), NULL, 0) ) goto error; if ( !tpm_fp->verify_creation(tpm, sealed_post_k_state_size, sealed_post_k_state) ) { printk(TBOOT_ERR"extended PCR values don't match creation values in sealed blob.\n"); goto error; } /* verify integrity of post-kernel state data */ printk(TBOOT_INFO"verifying post_k_s3_state\n"); sealed_secrets_t secrets; if ( !verify_sealed_data(sealed_post_k_state, sealed_post_k_state_size, &g_post_k_s3_state, sizeof(g_post_k_s3_state), &secrets, sizeof(secrets)) ) goto error; /* Verify memory integrity against sealed value */ uint8_t mac[POLY1305_DIGEST_SIZE]; if ( !measure_memory_integrity(mac, secrets.mac_key) ) goto error; if ( tb_memcmp(&mac, &g_post_k_s3_state.kernel_integ, sizeof(mac)) ) { printk(TBOOT_INFO"memory integrity lost on S3 resume\n"); printk(TBOOT_DETA"MAC of current image is: "); print_hex(NULL, &mac, sizeof(mac)); printk(TBOOT_DETA"MAC of pre-S3 image is: "); print_hex(NULL, &g_post_k_s3_state.kernel_integ, sizeof(g_post_k_s3_state.kernel_integ)); goto error; } printk(TBOOT_INFO"memory integrity OK\n"); /* re-extend PCRs with VL measurements we can't leave the system in a state without valid measurements of about-to-execute code in the PCRs, so this is a fatal error */ if ( !extend_pcrs() ) { apply_policy(TB_ERR_FATAL); return false; } /* copy sealed shared key back to _tboot_shared.s3_key */ tb_memcpy(_tboot_shared.s3_key, secrets.shared_key, sizeof(_tboot_shared.s3_key)); /* wipe secrets from memory */ tb_memset(&secrets, 0, sizeof(secrets)); return true; error: /* since we can't leave the system without any measurments representing the code-about-to-execute, and yet there is no integrity of that code, just cap PCR 18 */ if ( !tpm_fp->cap_pcrs(tpm, tpm->cur_loc, 18) ) apply_policy(TB_ERR_FATAL); return false; } /* * post- kernel launch S3 state is sealed to PCRs 17+18 with post-launch * values (i.e. before extending with VL hashes) */ bool seal_post_k_state(void) { sealed_secrets_t secrets; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); /* since tboot relies on the module it launches for resource protection, that module should have at least one region for itself, otherwise it will not be protected against S3 resume attacks */ if ( _tboot_shared.num_mac_regions == 0 ) { printk(TBOOT_ERR"no memory regions to MAC\n"); return false; } /* calculate the memory integrity hash */ uint32_t key_size = sizeof(secrets.mac_key); /* key must be random and secret even though auth not necessary */ if ( !tpm_fp->get_random(tpm, tpm->cur_loc, secrets.mac_key, &key_size) ||key_size != sizeof(secrets.mac_key) ) return false; if ( !measure_memory_integrity(g_post_k_s3_state.kernel_integ, secrets.mac_key) ) return false; /* copy s3_key into secrets to be sealed */ tb_memcpy(secrets.shared_key, _tboot_shared.s3_key, sizeof(secrets.shared_key)); print_post_k_s3_state(); sealed_post_k_state_size = sizeof(sealed_post_k_state); if ( !seal_data(&g_post_k_s3_state, sizeof(g_post_k_s3_state), &secrets, sizeof(secrets), sealed_post_k_state, &sealed_post_k_state_size) ) return false; /* wipe secrets from memory */ tb_memset(&secrets, 0, sizeof(secrets)); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/linux.c0000644000000000000000000004605314210363175015007 0ustar 00000000000000/* * linux.c: support functions for manipulating Linux kernel binaries * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern loader_ctx *g_ldr_ctx; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; static boot_params_t *boot_params; extern void *get_tboot_mem_end(void); static void printk_long(const char *what) { /* chunk the command line into 70 byte chunks */ #define CHUNK_SIZE 70 int cmdlen = tb_strlen(what); const char *cptr = what; char cmdchunk[CHUNK_SIZE+1]; while (cmdlen > 0) { tb_strncpy(cmdchunk, cptr, CHUNK_SIZE); cmdchunk[CHUNK_SIZE] = 0; printk(TBOOT_INFO"\t%s\n", cmdchunk); cmdlen -= CHUNK_SIZE; cptr += CHUNK_SIZE; } } /* expand linux kernel with kernel image and initrd image */ bool expand_linux_image(const void *linux_image, size_t linux_size, const void *initrd_image, size_t initrd_size, void **entry_point, bool is_measured_launch) { linux_kernel_header_t *hdr; uint32_t real_mode_base, protected_mode_base; unsigned long real_mode_size, protected_mode_size; /* Note: real_mode_size + protected_mode_size = linux_size */ uint32_t initrd_base; int vid_mode = 0; /* Check param */ if ( linux_image == NULL ) { printk(TBOOT_ERR"Error: Linux kernel image is zero.\n"); return false; } if ( linux_size == 0 ) { printk(TBOOT_ERR"Error: Linux kernel size is zero.\n"); return false; } if ( linux_size < sizeof(linux_kernel_header_t) ) { printk(TBOOT_ERR"Error: Linux kernel size is too small.\n"); return false; } hdr = (linux_kernel_header_t *)(linux_image + KERNEL_HEADER_OFFSET); if ( hdr == NULL ) { printk(TBOOT_ERR"Error: Linux kernel header is zero.\n"); return false; } if ( entry_point == NULL ) { printk(TBOOT_ERR"Error: Output pointer is zero.\n"); return false; } /* recommended layout 0x0000 - 0x7FFF Real mode kernel 0x8000 - 0x8CFF Stack and heap 0x8D00 - 0x90FF Kernel command line for details, see linux_defns.h */ /* if setup_sects is zero, set to default value 4 */ if ( hdr->setup_sects == 0 ) hdr->setup_sects = DEFAULT_SECTOR_NUM; if ( hdr->setup_sects > MAX_SECTOR_NUM ) { printk(TBOOT_ERR "Error: Linux setup sectors %d exceed maximum limitation 64.\n", hdr->setup_sects); return false; } /* set vid_mode */ linux_parse_cmdline(get_cmdline(g_ldr_ctx)); if ( get_linux_vga(&vid_mode) ) hdr->vid_mode = vid_mode; /* compare to the magic number */ if ( hdr->header != HDRS_MAGIC ) { /* old kernel */ printk(TBOOT_ERR "Error: Old kernel (< 2.6.20) is not supported by tboot.\n"); return false; } if ( hdr->version < 0x0205 ) { printk(TBOOT_ERR "Error: Old kernel (<2.6.20) is not supported by tboot.\n"); return false; } /* boot loader is grub, set type_of_loader to 0x7 */ hdr->type_of_loader = LOADER_TYPE_GRUB; /* set loadflags and heap_end_ptr */ hdr->loadflags |= FLAG_CAN_USE_HEAP; /* can use heap */ hdr->heap_end_ptr = KERNEL_CMDLINE_OFFSET - BOOT_SECTOR_OFFSET; if ( initrd_size > 0 ) { /* load initrd and set ramdisk_image and ramdisk_size */ /* The initrd should typically be located as high in memory as possible, as it may otherwise get overwritten by the early kernel initialization sequence. */ /* check if Linux command line explicitly specified a memory limit */ uint64_t mem_limit; get_linux_mem(&mem_limit); if ( mem_limit > 0x100000000ULL || mem_limit == 0 ) mem_limit = 0x100000000ULL; uint64_t max_ram_base = 0, max_ram_size = 0; if (!efi_memmap_get_highest_sized_ram(initrd_size, mem_limit, &max_ram_base, &max_ram_size)) { if (!e820_get_highest_sized_ram(initrd_size, mem_limit, &max_ram_base, &max_ram_size)) { printk(TBOOT_ERR"not enough RAM for initrd\n"); return false; } } if ( initrd_size > max_ram_size ) { printk(TBOOT_ERR"initrd_size is too large\n"); return false; } if ( max_ram_base > ((uint64_t)(uint32_t)(~0)) ) { printk(TBOOT_ERR"max_ram_base is too high\n"); return false; } if ( plus_overflow_u32((uint32_t)max_ram_base, (uint32_t)(max_ram_size - initrd_size)) ) { printk(TBOOT_ERR"max_ram overflows\n"); return false; } initrd_base = (max_ram_base + max_ram_size - initrd_size) & PAGE_MASK; /* should not exceed initrd_addr_max */ if ( initrd_base + initrd_size > hdr->initrd_addr_max ) { if ( hdr->initrd_addr_max < initrd_size ) { printk(TBOOT_ERR"initrd_addr_max is too small\n"); return false; } initrd_base = hdr->initrd_addr_max - initrd_size; initrd_base = initrd_base & PAGE_MASK; } /* check for overlap with a kernel image placed high in memory */ if( (initrd_base < ((uint32_t)linux_image + linux_size)) && ((uint32_t)linux_image < (initrd_base+initrd_size)) ){ /* set the starting address just below the image */ initrd_base = (uint32_t)linux_image - initrd_size; initrd_base = initrd_base & PAGE_MASK; /* make sure we're still in usable RAM and above tboot end address*/ if( initrd_base < max_ram_base ){ printk(TBOOT_ERR"no available memory for initrd\n"); return false; } } tb_memmove((void *)initrd_base, initrd_image, initrd_size); printk(TBOOT_DETA"Initrd from 0x%lx to 0x%lx\n", (unsigned long)initrd_base, (unsigned long)(initrd_base + initrd_size)); } else initrd_base = (uint32_t)initrd_image; hdr->ramdisk_image = initrd_base; hdr->ramdisk_size = initrd_size; /* calc location of real mode part */ real_mode_base = LEGACY_REAL_START; if ( have_loader_memlimits(g_ldr_ctx)) real_mode_base = ((get_loader_mem_lower(g_ldr_ctx)) << 10) - REAL_MODE_SIZE; if ( real_mode_base < TBOOT_KERNEL_CMDLINE_ADDR + TBOOT_KERNEL_CMDLINE_SIZE ) real_mode_base = TBOOT_KERNEL_CMDLINE_ADDR + TBOOT_KERNEL_CMDLINE_SIZE; if ( real_mode_base > LEGACY_REAL_START ) real_mode_base = LEGACY_REAL_START; real_mode_size = (hdr->setup_sects + 1) * SECTOR_SIZE; if ( real_mode_size + sizeof(boot_params_t) > KERNEL_CMDLINE_OFFSET ) { printk(TBOOT_ERR"realmode data is too large\n"); return false; } /* calc location of protected mode part */ protected_mode_size = linux_size - real_mode_size; /* if kernel is relocatable then move it above tboot */ /* else it may expand over top of tboot */ if ( hdr->relocatable_kernel ) { protected_mode_base = (uint32_t)get_tboot_mem_end(); /* fix possible mbi overwrite in grub2 case */ /* assuming grub2 only used for relocatable kernel */ /* assuming mbi & components are contiguous */ unsigned long ldr_ctx_end = get_loader_ctx_end(g_ldr_ctx); if ( ldr_ctx_end > protected_mode_base ) protected_mode_base = ldr_ctx_end; /* overflow? */ if ( plus_overflow_u32(protected_mode_base, hdr->kernel_alignment - 1) ) { printk(TBOOT_ERR"protected_mode_base overflows\n"); return false; } /* round it up to kernel alignment */ protected_mode_base = (protected_mode_base + hdr->kernel_alignment - 1) & ~(hdr->kernel_alignment-1); hdr->code32_start = protected_mode_base; } else if ( hdr->loadflags & FLAG_LOAD_HIGH ) { protected_mode_base = BZIMAGE_PROTECTED_START; /* bzImage:0x100000 */ /* overflow? */ if ( plus_overflow_u32(protected_mode_base, protected_mode_size) ) { printk(TBOOT_ERR "protected_mode_base plus protected_mode_size overflows\n"); return false; } /* Check: protected mode part cannot exceed mem_upper */ if ( have_loader_memlimits(g_ldr_ctx)){ uint32_t mem_upper = get_loader_mem_upper(g_ldr_ctx); if ( (protected_mode_base + protected_mode_size) > ((mem_upper << 10) + 0x100000) ) { printk(TBOOT_ERR "Error: Linux protected mode part (0x%lx ~ 0x%lx) " "exceeds mem_upper (0x%lx ~ 0x%lx).\n", (unsigned long)protected_mode_base, (unsigned long) (protected_mode_base + protected_mode_size), (unsigned long)0x100000, (unsigned long)((mem_upper << 10) + 0x100000)); return false; } } } else { printk(TBOOT_ERR"Error: Linux protected mode not loaded high\n"); return false; } /* set cmd_line_ptr */ hdr->cmd_line_ptr = real_mode_base + KERNEL_CMDLINE_OFFSET; /* Save linux header struct to temp memory, in case the it is overwritten by tb_memmove below*/ linux_kernel_header_t temp_hdr; tb_memmove(&temp_hdr, hdr, sizeof(temp_hdr)); hdr = &temp_hdr; /* load protected-mode part */ tb_memmove((void *)protected_mode_base, linux_image + real_mode_size, protected_mode_size); printk(TBOOT_DETA"Kernel (protected mode) from 0x%lx to 0x%lx\n", (unsigned long)protected_mode_base, (unsigned long)(protected_mode_base + protected_mode_size)); /* load real-mode part */ tb_memmove((void *)real_mode_base, linux_image, real_mode_size); printk(TBOOT_DETA"Kernel (real mode) from 0x%lx to 0x%lx\n", (unsigned long)real_mode_base, (unsigned long)(real_mode_base + real_mode_size)); /* copy cmdline */ const char *kernel_cmdline = get_cmdline(g_ldr_ctx); if ( kernel_cmdline == NULL ) { printk(TBOOT_ERR"Error: kernel cmdline not available\n"); return false; } const size_t kernel_cmdline_size = REAL_END_OFFSET - KERNEL_CMDLINE_OFFSET; size_t kernel_cmdline_strlen = tb_strlen(kernel_cmdline); if (kernel_cmdline_strlen > kernel_cmdline_size - 1) kernel_cmdline_strlen = kernel_cmdline_size - 1; tb_memset((void *)hdr->cmd_line_ptr, 0, kernel_cmdline_size); tb_memcpy((void *)hdr->cmd_line_ptr, kernel_cmdline, kernel_cmdline_strlen); printk(TBOOT_INFO"Linux cmdline from 0x%lx to 0x%lx:\n", (unsigned long)hdr->cmd_line_ptr, (unsigned long)(hdr->cmd_line_ptr + kernel_cmdline_size)); printk_long((void *)hdr->cmd_line_ptr); /* need to put boot_params in real mode area so it gets mapped */ boot_params = (boot_params_t *)(real_mode_base + real_mode_size); tb_memset(boot_params, 0, sizeof(*boot_params)); tb_memcpy(&boot_params->hdr, hdr, sizeof(*hdr)); /* need to handle a few EFI things here if such is our parentage */ if (is_loader_launch_efi(g_ldr_ctx)){ struct efi_info *efi = (struct efi_info *)(boot_params->efi_info); uint32_t address = 0; uint64_t long_address = 0UL; uint32_t descr_size = 0, descr_vers = 0, mmap_size = 0, efi_mmap_addr = 0; /* loader signature */ tb_memcpy(&efi->efi_ldr_sig, "EL64", sizeof(uint32_t)); /* EFI system table addr */ { if (get_loader_efi_ptr(g_ldr_ctx, &address, &long_address)){ if (long_address){ efi->efi_systable = (uint32_t) (long_address & 0xffffffff); efi->efi_systable_hi = long_address >> 32; } else { efi->efi_systable = address; efi->efi_systable_hi = 0; } } else { printk(TBOOT_INFO"failed to get efi system table ptr\n"); } } efi_mmap_addr = efi_memmap_get_addr(&descr_size, &descr_vers, &mmap_size); if (!efi_mmap_addr) { printk(TBOOT_INFO"failed to get EFI memory map\n"); efi->efi_memdescr_size = 0x1; // Avoid div by 0 in kernel. efi->efi_memmap_size = 0; efi->efi_memmap = 0; } else { efi->efi_memdescr_size = descr_size; efi->efi_memdescr_ver = descr_vers; efi->efi_memmap_size = mmap_size; efi->efi_memmap = efi_mmap_addr; /* From Multiboot2 spec: * The bootloader must not load any part of the kernel, the modules, * the Multiboot2 information structure, etc. higher than 4 GiB - 1. */ efi->efi_memmap_hi = 0; if (get_tboot_dump_memmap()) { printk(TBOOT_INFO"EFI memory map after modifications:\n"); efi_memmap_dump(); } printk(TBOOT_INFO "EFI memmap: memmap base: 0x%x, memmap size: 0x%x\n", efi->efi_memmap, efi->efi_memmap_size); printk(TBOOT_INFO "EFI memmap: descr size: 0x%x, descr version: 0x%x\n", efi->efi_memdescr_size, efi->efi_memdescr_ver); } } screen_info_t *scr = (screen_info_t *)(boot_params->screen_info); if (!load_framebuffer_info(g_ldr_ctx, (void *)scr, is_loader_launch_efi(g_ldr_ctx))) { /* Fallback to 80x25 mode */ scr->orig_video_mode = 3; /* BIOS 80*25 text mode */ scr->orig_video_lines = 25; scr->orig_video_cols = 80; scr->orig_video_points = 16; /* set font height to 16 pixels */ scr->orig_video_isVGA = 1; /* use VGA text screen setups */ scr->orig_y = 24; /* start display text @ screen end*/ } /* detect e820 table */ if (have_loader_memmap(g_ldr_ctx)) { int i; memory_map_t *p = get_loader_memmap(g_ldr_ctx); if ( p == NULL ) { printk(TBOOT_ERR"Error: no memory map available\n"); return false; } uint32_t memmap_start = (uint32_t) p; uint32_t memmap_length = get_loader_memmap_length(g_ldr_ctx); for ( i = 0; (uint32_t)p < memmap_start + memmap_length; i++ ) { boot_params->e820_map[i].addr = ((uint64_t)p->base_addr_high << 32) | (uint64_t)p->base_addr_low; boot_params->e820_map[i].size = ((uint64_t)p->length_high << 32) | (uint64_t)p->length_low; boot_params->e820_map[i].type = p->type; p = (void *)p + sizeof(memory_map_t); } boot_params->e820_entries = i; } // if (0 == is_loader_launch_efi(g_ldr_ctx)){ // screen_info_t *screen = (screen_info_t *)&boot_params->screen_info; // screen->orig_video_mode = 3; /* BIOS 80*25 text mode */ // screen->orig_video_lines = 25; // screen->orig_video_cols = 80; // screen->orig_video_points = 16; /* set font height to 16 pixels */ // screen->orig_video_isVGA = 1; /* use VGA text screen setups */ // screen->orig_y = 24; /* start display text @ screen end*/ // } /* set address of tboot shared page */ if ( is_measured_launch ) *(uint64_t *)&boot_params->tboot_shared_addr = (uintptr_t)&_tboot_shared; *entry_point = (void *)hdr->code32_start; return true; } /* jump to protected-mode code of kernel */ bool jump_linux_image(void *entry_point) { #define __BOOT_CS 0x10 #define __BOOT_DS 0x18 static const uint64_t gdt_table[] __attribute__ ((aligned(16))) = { 0, 0, 0x00cf9b000000ffff, /* cs */ 0x00cf93000000ffff /* ds */ }; /* both 4G flat, CS: execute/read, DS: read/write */ static struct __packed { uint16_t length; uint32_t table; } gdt_desc; gdt_desc.length = sizeof(gdt_table) - 1; gdt_desc.table = (uint32_t)&gdt_table; /* load gdt with CS = 0x10 and DS = 0x18 */ __asm__ __volatile__ ( " lgdtl %0; " " mov %1, %%ecx; " " mov %%ecx, %%ds; " " mov %%ecx, %%es; " " mov %%ecx, %%fs; " " mov %%ecx, %%gs; " " mov %%ecx, %%ss; " " ljmp %2, $(1f); " " 1: " " xor %%ebp, %%ebp; " " xor %%edi, %%edi; " " xor %%ebx, %%ebx; " :: "m"(gdt_desc), "i"(__BOOT_DS), "i"(__BOOT_CS)); /* jump to protected-mode code */ __asm__ __volatile__ ( " cli; " " mov %0, %%esi; " /* esi holds address of boot_params */ " jmp *%%edx; " " ud2; " :: "a"(boot_params), "d"(entry_point)); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/loader.c0000644000000000000000000021401314210363175015107 0ustar 00000000000000/* * loader.c: support functions for manipulating ELF/Linux kernel * binaries * * Copyright (c) 2006-2013, Intel Corporation * Copyright (c) 2016 Real-Time Systems GmbH * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* copy of kernel/VMM command line so that can append 'tboot=0x1234' */ static char * volatile new_cmdline = (char *)TBOOT_KERNEL_CMDLINE_ADDR; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; /* multiboot struct saved so that post_launch() can use it (in tboot.c) */ extern loader_ctx *g_ldr_ctx; extern bool get_elf_image_range(const elf_header_t *elf, void **start, void **end); extern bool is_elf_image(const void *image, size_t size); extern bool expand_elf_image(const elf_header_t *elf, void **entry_point); extern bool expand_linux_image(const void *linux_image, size_t linux_size, const void *initrd_image, size_t initrd_size, void **entry_point, bool is_measured_launch); extern bool jump_elf_image(const void *entry_point, uint32_t magic); extern bool jump_linux_image(const void *entry_point); extern bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern void apply_policy(tb_error_t error); extern uint32_t g_mb_orig_size; #define LOADER_CTX_BAD(xctx) \ xctx == NULL ? true : \ xctx->addr == NULL ? true : \ xctx->type != 1 && xctx->type != 2 ? true : false #define MB_NONE 0 #define MB1_ONLY 1 #define MB2_ONLY 2 #define MB_BOTH 3 static void printk_long(char *what) { /* chunk the command line into 70 byte chunks */ #define CHUNK_SIZE 70 int cmdlen = tb_strlen(what); char *cptr = what; char cmdchunk[CHUNK_SIZE+1]; while (cmdlen > 0) { tb_strncpy(cmdchunk, cptr, CHUNK_SIZE); cmdchunk[CHUNK_SIZE] = 0; printk(TBOOT_INFO"\t%s\n", cmdchunk); cmdlen -= CHUNK_SIZE; cptr += CHUNK_SIZE; } } static module_t *get_module_mb1(const multiboot_info_t *mbi, unsigned int i) { if ( mbi == NULL ) { printk(TBOOT_ERR"Error: mbi pointer is zero.\n"); return NULL; } if ( i >= mbi->mods_count ) { printk(TBOOT_ERR"invalid module #\n"); return NULL; } return (module_t *)(mbi->mods_addr + i * sizeof(module_t)); } static struct mb2_tag *next_mb2_tag(struct mb2_tag *start) { /* given "start", what's the beginning of the next tag */ void *addr = (void *) start; if (start == NULL) return NULL; if (start->type == MB2_TAG_TYPE_END) return NULL; addr += ((start->size + 7) & ~7); return (struct mb2_tag *) addr; } static struct mb2_tag *find_mb2_tag_type(struct mb2_tag *start, uint32_t tag_type) { while (start != NULL){ if (start->type == tag_type) return start; start = next_mb2_tag(start); } return start; } static module_t *get_module_mb2(loader_ctx *lctx, unsigned int i) { struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); unsigned int ii; struct mb2_tag_module *tag_mod = NULL; module_t *mt = NULL; start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); if (start != NULL){ for (ii = 1; ii <= i; ii++){ if (start == NULL) return NULL; else { /* nudge off this hit */ start = next_mb2_tag(start); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); } } /* if we're here, we have the tag struct for the desired module */ tag_mod = (struct mb2_tag_module *) start; mt = (module_t *) &(tag_mod->mod_start); } return mt; } #if 0 void print_mbi(const multiboot_info_t *mbi) { /* print mbi for debug */ unsigned int i; printk(TBOOT_DETA"print mbi@%p ...\n", mbi); printk(TBOOT_DETA"\t flags: 0x%x\n", mbi->flags); if ( mbi->flags & MBI_MEMLIMITS ) printk(TBOOT_DETA"\t mem_lower: %uKB, mem_upper: %uKB\n", mbi->mem_lower, mbi->mem_upper); if ( mbi->flags & MBI_BOOTDEV ) { printk(TBOOT_DETA"\t boot_device.bios_driver: 0x%x\n", mbi->boot_device.bios_driver); printk(TBOOT_DETA"\t boot_device.top_level_partition: 0x%x\n", mbi->boot_device.top_level_partition); printk(TBOOT_DETA"\t boot_device.sub_partition: 0x%x\n", mbi->boot_device.sub_partition); printk(TBOOT_DETA"\t boot_device.third_partition: 0x%x\n", mbi->boot_device.third_partition); } if ( mbi->flags & MBI_CMDLINE ) { # define CHUNK_SIZE 72 /* Break the command line up into 72 byte chunks */ int cmdlen = tb_strlen(mbi->cmdline); char *cmdptr = (char *)mbi->cmdline; char chunk[CHUNK_SIZE+1]; printk(TBOOT_DETA"\t cmdline@0x%x: ", mbi->cmdline); chunk[CHUNK_SIZE] = '\0'; while (cmdlen > 0) { tb_strncpy(chunk, cmdptr, CHUNK_SIZE); printk(TBOOT_DETA"\n\t\"%s\"", chunk); cmdptr += CHUNK_SIZE; cmdlen -= CHUNK_SIZE; } printk(TBOOT_DETA"\n"); } if ( mbi->flags & MBI_MODULES ) { printk(TBOOT_DETA"\t mods_count: %u, mods_addr: 0x%x\n", mbi->mods_count, mbi->mods_addr); for ( i = 0; i < mbi->mods_count; i++ ) { module_t *p = (module_t *)(mbi->mods_addr + i*sizeof(module_t)); printk(TBOOT_DETA"\t %d : mod_start: 0x%x, mod_end: 0x%x\n", i, p->mod_start, p->mod_end); printk(TBOOT_DETA"\t string (@0x%x): \"%s\"\n", p->string, (char *)p->string); } } if ( mbi->flags & MBI_AOUT ) { const aout_t *p = &(mbi->syms.aout_image); printk(TBOOT_DETA "\t aout :: tabsize: 0x%x, strsize: 0x%x, addr: 0x%x\n", p->tabsize, p->strsize, p->addr); } if ( mbi->flags & MBI_ELF ) { const elf_t *p = &(mbi->syms.elf_image); printk(TBOOT_DETA "\t elf :: num: %u, size: 0x%x, addr: 0x%x, shndx: 0x%x\n", p->num, p->size, p->addr, p->shndx); } if ( mbi->flags & MBI_MEMMAP ) { memory_map_t *p; printk(TBOOT_DETA "\t mmap_length: 0x%x, mmap_addr: 0x%x\n", mbi->mmap_length, mbi->mmap_addr); for ( p = (memory_map_t *)mbi->mmap_addr; (uint32_t)p < mbi->mmap_addr + mbi->mmap_length; p=(memory_map_t *)((uint32_t)p + p->size + sizeof(p->size)) ) { printk(TBOOT_DETA"\t size: 0x%x, base_addr: 0x%04x%04x, " "length: 0x%04x%04x, type: %u\n", p->size, p->base_addr_high, p->base_addr_low, p->length_high, p->length_low, p->type); } } if ( mbi->flags & MBI_DRIVES ) { printk(TBOOT_DETA"\t drives_length: %u, drives_addr: 0x%x\n", mbi->drives_length, mbi->drives_addr); } if ( mbi->flags & MBI_CONFIG ) { printk(TBOOT_DETA"\t config_table: 0x%x\n", mbi->config_table); } if ( mbi->flags & MBI_BTLDNAME ) { printk(TBOOT_DETA"\t boot_loader_name@0x%x: %s\n", mbi->boot_loader_name, (char *)mbi->boot_loader_name); } if ( mbi->flags & MBI_APM ) { printk(TBOOT_DETA"\t apm_table: 0x%x\n", mbi->apm_table); } if ( mbi->flags & MBI_VBE ) { printk(TBOOT_DETA"\t vbe_control_info: 0x%x\n" "\t vbe_mode_info: 0x%x\n" "\t vbe_mode: 0x%x\n" "\t vbe_interface_seg: 0x%x\n" "\t vbe_interface_off: 0x%x\n" "\t vbe_interface_len: 0x%x\n", mbi->vbe_control_info, mbi->vbe_mode_info, mbi->vbe_mode, mbi->vbe_interface_seg, mbi->vbe_interface_off, mbi->vbe_interface_len ); } } #endif bool verify_loader_context(loader_ctx *lctx) { unsigned int count; if (LOADER_CTX_BAD(lctx)) return false; count = get_module_count(lctx); if (count < 1){ printk(TBOOT_ERR"Error: no MB%d modules\n", lctx->type); return false; } else { for (uint32_t i = 0; i < count; ++i) { module_t *m = get_module(lctx, i); if (m->mod_end < m->mod_start) { return false; } } return true; } } static bool remove_mb2_tag(loader_ctx *lctx, struct mb2_tag *cur) { uint8_t *s, *d, *e; struct mb2_tag *next, *end; next = next_mb2_tag(cur); if (next == NULL){ printk(TBOOT_ERR"missing next tag in remove_mb2_tag\n"); return false; } /* where do we stop? */ end = (struct mb2_tag *)(lctx->addr + 8); end = find_mb2_tag_type(end, MB2_TAG_TYPE_END); if (end == NULL){ printk(TBOOT_ERR"remove_mb2_tag, no end tag!!!!\n"); return false; } e = (uint8_t *) end + end->size; /* we'll do this byte-wise */ s = (uint8_t *) next; d = (uint8_t *) cur; while (s <= e){ *d = *s; d++; s++; } /* adjust MB2 length */ *((unsigned long *) lctx->addr) -= (uint8_t *)next - (uint8_t *)cur; /* sanity check */ /* print_loader_ctx(lctx); */ return true; } static bool grow_mb2_tag(loader_ctx *lctx, struct mb2_tag *which, uint32_t how_much) { struct mb2_tag *next, *new_next, *end; int growth, slack; uint8_t *s, *d; // uint32_t old_size = which->size; /* we're holding the tag struct to grow, get its successor */ next = next_mb2_tag(which); /* find the end--we will need it */ end = (struct mb2_tag *)(lctx->addr + 8); end = find_mb2_tag_type(end, MB2_TAG_TYPE_END); if ( end == NULL ) return false; /* How much bigger does it need to be? */ /* NOTE: this breaks the MBI 2 structure for walking * until we're done copying. */ which->size += how_much; /* what's the new growth for its successor? */ new_next = next_mb2_tag(which); growth = ((void *) new_next) - ((void *) next); /* check to make sure there's actually room for the growth */ slack = g_mb_orig_size - *(uint32_t *) (lctx->addr); if (growth > slack){ printk(TBOOT_ERR"YIKES!!! grow_mb2_tag slack %d < growth %d\n", slack, growth); apply_policy(TB_ERR_FATAL); } /* now we copy down from the bottom, going up */ s = ((uint8_t *) end) + end->size; d = s + growth; while (s >= (uint8_t *)next){ *d = *s; d--; s--; } /* adjust MB2 length */ *((uint32_t *) lctx->addr) += growth; return true; } static void *remove_module(loader_ctx *lctx, void *mod_start) { module_t *m = NULL; unsigned int i; if ( !verify_loader_context(lctx)) return NULL; for ( i = 0; i < get_module_count(lctx); i++ ) { m = get_module(lctx, i); if ( mod_start == NULL || (void *)m->mod_start == mod_start ) break; } /* not found */ if ( m == NULL ) { printk(TBOOT_ERR"could not find module to remove\n"); return NULL; } if (lctx->type == MB1_ONLY){ /* multiboot 1 */ /* if we're removing the first module (i.e. the "kernel") then */ /* need to adjust some mbi fields as well */ multiboot_info_t *mbi = (multiboot_info_t *) lctx->addr; if ( mod_start == NULL ) { mbi->cmdline = m->string; mbi->flags |= MBI_CMDLINE; mod_start = (void *)m->mod_start; } /* copy remaing mods down by one */ tb_memmove(m, m + 1, (mbi->mods_count - i - 1)*sizeof(module_t)); mbi->mods_count--; return mod_start; } if (lctx->type == MB2_ONLY){ /* multiboot 2 */ /* if we're removing the first module (i.e. the "kernel") then */ /* need to adjust some mbi fields as well */ char cmdbuf[TBOOT_KERNEL_CMDLINE_SIZE]; cmdbuf[0] = '\0'; if ( mod_start == NULL ) { char *cmdline = get_cmdline(lctx); char *mod_string = get_module_cmd(lctx, m); if ( cmdline == NULL ) { printk(TBOOT_ERR"could not find cmdline\n"); return NULL; } if ( mod_string == NULL ) { printk(TBOOT_ERR"could not find module cmdline\n"); return NULL; } if ((tb_strlen(mod_string)) > (tb_strlen(cmdline))){ if (tb_strlen(mod_string) >= TBOOT_KERNEL_CMDLINE_SIZE){ printk(TBOOT_ERR"No room to copy MB2 cmdline [%d < %d]\n", (int)(tb_strlen(cmdline)), (int)(tb_strlen(mod_string))); } else { char *s = mod_string; char *d = cmdbuf; while (*s){ *d = *s; d++; s++; } *d = *s; // strcpy(cmdbuf, mod_string); } } else { // strcpy(cmdline,mod_string); char *s = mod_string; char *d = cmdline; while (*s){ *d = *s; d++; s++; } *d = *s; /* note: we didn't adjust the "size" field, since it didn't * grow and this saves us the pain of shuffling everything * after cmdline (which is usually first) */ } mod_start = (void *)m->mod_start; } /* so MB2 is a different beast. The modules aren't necessarily * adjacent, first, last, anything. What we can do is bulk copy * everything after the thing we're killing over the top of it, * and shorten the total length of the MB2 structure. */ { struct mb2_tag *cur; struct mb2_tag_module *mod = NULL; module_t *cur_mod = NULL; cur = (struct mb2_tag *)(lctx->addr + 8); cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_MODULE); mod = (struct mb2_tag_module *) cur; if (mod != NULL) cur_mod = (module_t *)&(mod->mod_start); while (cur_mod != NULL && cur_mod != m){ /* nudge off current record */ cur = next_mb2_tag(cur); cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_MODULE); mod = (struct mb2_tag_module *) cur; if (mod != NULL) cur_mod = (module_t *)&(mod->mod_start); else cur_mod = NULL; } if (cur_mod == NULL){ printk(TBOOT_ERR"remove_module() for MB2 failed\n"); return NULL; } /* we're here. cur is the MB2 tag we need to overwrite. */ if (false == remove_mb2_tag(lctx, cur)) return NULL; } if (cmdbuf[0] != '\0'){ /* we need to grow the mb2_tag_string that holds the cmdline. * we know there's room, since we've shortened the MB2 by the * length of the module_tag we've removed, which contained * the longer string. */ struct mb2_tag *cur = (struct mb2_tag *)(lctx->addr + 8); struct mb2_tag_string *cmd; cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_CMDLINE); cmd = (struct mb2_tag_string *) cur; if (cmd == NULL){ printk(TBOOT_ERR"remove_modules MB2 shuffle NULL cmd\n"); return NULL; } grow_mb2_tag(lctx, cur, tb_strlen(cmdbuf) - tb_strlen(cmd->string)); /* now we're all good, except for fixing up cmd */ { char * s = cmdbuf; char *d = cmd->string; while (*s){ *d = *s; d++; s++; } *d = *s; } } return mod_start; } return NULL; } static bool adjust_kernel_cmdline(loader_ctx *lctx, const void *tboot_shared_addr) { const char *old_cmdline; if (lctx == NULL) return false; if (lctx->addr == NULL) return false; if (lctx->type == MB1_ONLY || lctx->type == MB2_ONLY){ old_cmdline = get_cmdline(lctx); if (old_cmdline == NULL) old_cmdline = ""; tb_snprintf(new_cmdline, TBOOT_KERNEL_CMDLINE_SIZE, "%s tboot=%p", old_cmdline, tboot_shared_addr); new_cmdline[TBOOT_KERNEL_CMDLINE_SIZE - 1] = '\0'; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ multiboot_info_t *mbi = (multiboot_info_t *) lctx->addr; /* assumes mbi is valid */ mbi->cmdline = (u32)new_cmdline; mbi->flags |= MBI_CMDLINE; return true; } if (lctx->type == MB2_ONLY){ /* multiboot 2 */ /* this is harder, since the strings sit inline */ /* we need to grow the mb2_tag_string that holds the cmdline. * TODO: should be checking that we're not running off the * end of the original MB2 space. */ struct mb2_tag *cur = (struct mb2_tag *)(lctx->addr + 8); struct mb2_tag_string *cmd; cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_CMDLINE); cmd = (struct mb2_tag_string *) cur; if (cmd == NULL){ printk(TBOOT_ERR"adjust_kernel_cmdline() NULL MB2 cmd\n"); return NULL; } uint32_t new_cmdline_tag_size = 2 * sizeof(uint32_t) + tb_strlen(new_cmdline) + 1; if ( new_cmdline_tag_size > cmd->size ){ if (false == grow_mb2_tag(lctx, cur, (new_cmdline_tag_size - cmd->size))) return false; } /* now we're all good, except for fixing up cmd */ { char *s = new_cmdline; char *d = cmd->string; while (*s){ *d = *s; d++; s++; } *d = *s; } // strcpy(cmd->string, cmdbuf); } return true; } return false; } bool is_kernel_linux(void) { if ( !verify_loader_context(g_ldr_ctx) ) return false; // module_t *m = (module_t *)g_mbi->mods_addr; module_t *m = get_module(g_ldr_ctx, 0); void *kernel_image = (void *)m->mod_start; size_t kernel_size = m->mod_end - m->mod_start; return !is_elf_image(kernel_image, kernel_size); } static bool find_module(loader_ctx *lctx, void **base, size_t *size, const void *data, size_t len) { if ( lctx == NULL || lctx->addr == NULL) { printk(TBOOT_ERR"Error: context pointer is zero.\n"); return false; } if ( base == NULL ) { printk(TBOOT_ERR"Error: base is NULL.\n"); return false; } *base = NULL; if ( size != NULL ) *size = 0; if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"Error: no module.\n"); return false; } for ( unsigned int i = get_module_count(lctx) - 1; i > 0; i-- ) { module_t *m = get_module(lctx, i); /* check size */ size_t mod_size = m->mod_end - m->mod_start; if ( len > mod_size ) { printk(TBOOT_ERR"Error: image size is smaller than data size.\n"); return false; } if ( tb_memcmp((void *)m->mod_start, data, len) == 0 ) { *base = (void *)m->mod_start; if ( size != NULL ) *size = mod_size; return true; } } return false; } bool find_lcp_module(loader_ctx *lctx, void **base, uint32_t *size) { size_t size2 = 0; void *base2 = NULL; if ( base != NULL ) *base = NULL; if ( size != NULL ) *size = 0; /* try policy data file for old version (0x00 or 0x01) */ find_module_by_uuid(lctx, &base2, &size2, &((uuid_t)LCP_POLICY_DATA_UUID)); /* not found */ if ( base2 == NULL ) { /* try policy data file for new version (0x0202) */ find_module_by_file_signature(lctx, &base2, &size2, LCP_POLICY_DATA_FILE_SIGNATURE); if ( base2 == NULL ) { printk(TBOOT_WARN"no LCP module found\n"); return false; } else printk(TBOOT_INFO"v2 LCP policy data found\n"); } else printk(TBOOT_INFO"v1 LCP policy data found\n"); if ( base != NULL ) *base = base2; if ( size != NULL ) *size = size2; return true; } /* * remove (all) SINIT and LCP policy data modules (if present) */ bool remove_txt_modules(loader_ctx *lctx) { if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"Error: no module.\n"); return false; } /* start at end of list so that we can remove w/in the loop */ for ( unsigned int i = get_module_count(lctx) - 1; i > 0; i-- ) { module_t *m = get_module(lctx, i); void *base = (void *)m->mod_start; if ( is_sinit_acmod(base, m->mod_end - (unsigned long)base, true) ) { printk(TBOOT_INFO"got sinit match on module #%d\n", i); if ( remove_module(lctx, base) == NULL ) { printk(TBOOT_ERR "failed to remove SINIT module from module list\n"); return false; } } } void *base = NULL; if ( find_lcp_module(lctx, &base, NULL) ) { if ( remove_module(lctx, base) == NULL ) { printk(TBOOT_ERR"failed to remove LCP module from module list\n"); return false; } } return true; } extern unsigned long get_tboot_mem_end(void); static bool below_tboot(unsigned long addr) { return addr >= 0x100000 && addr < TBOOT_BASE_ADDR; } static unsigned long max(unsigned long a, unsigned long b) { return (a > b) ? a : b; } static unsigned long get_mbi_mem_end_mb1(const multiboot_info_t *mbi) { unsigned long end = (unsigned long)(mbi + 1); if ( mbi->flags & MBI_CMDLINE ) end = max(end, mbi->cmdline + tb_strlen((char *)mbi->cmdline) + 1); if ( mbi->flags & MBI_MODULES ) { end = max(end, mbi->mods_addr + mbi->mods_count * sizeof(module_t)); unsigned int i; for ( i = 0; i < mbi->mods_count; i++ ) { module_t *p = get_module_mb1(mbi, i); if ( p == NULL ) break; end = max(end, p->string + tb_strlen((char *)p->string) + 1); } } if ( mbi->flags & MBI_AOUT ) { const aout_t *p = &(mbi->syms.aout_image); end = max(end, p->addr + p->tabsize + sizeof(unsigned long) + p->strsize); } if ( mbi->flags & MBI_ELF ) { const elf_t *p = &(mbi->syms.elf_image); end = max(end, p->addr + p->num * p->size); } if ( mbi->flags & MBI_MEMMAP ) end = max(end, mbi->mmap_addr + mbi->mmap_length); if ( mbi->flags & MBI_DRIVES ) end = max(end, mbi->drives_addr + mbi->drives_length); /* mbi->config_table field should contain */ /* "the address of the rom configuration table returned by the */ /* GET CONFIGURATION bios call", so skip it */ if ( mbi->flags & MBI_BTLDNAME ) end = max(end, mbi->boot_loader_name + tb_strlen((char *)mbi->boot_loader_name) + 1); if ( mbi->flags & MBI_APM ) /* per Grub-multiboot-Main Part2 Rev94-Structures, apm size is 20 */ end = max(end, mbi->apm_table + 20); if ( mbi->flags & MBI_VBE ) { /* VBE2.0, VBE Function 00 return 512 bytes*/ end = max(end, mbi->vbe_control_info + 512); /* VBE2.0, VBE Function 01 return 256 bytes*/ end = max(end, mbi->vbe_mode_info + 256); } return PAGE_UP(end); } /* * Move all mbi components/modules/mbi to end of memory */ static bool move_modules_to_high_memory(loader_ctx *lctx) { uint32_t memRequired; uint64_t max_ram_base = 0, max_ram_size = 0, ld_ceiling; uint32_t module_count, mod_i, mods_remaining; module_t *m; if (LOADER_CTX_BAD(lctx)) return false; /* Determine the size of memory required to pack all modules together */ module_count = get_module_count(lctx); for( memRequired=0, mod_i=0; mod_i < module_count; mod_i++ ){ m = get_module(lctx, mod_i); memRequired += PAGE_UP(m->mod_end - m->mod_start); } /* NOTE: the memory maps have been modified already to reserve critical memory regions (tboot memory, etc ...). get_highest_sized_ram will return a range that excludes critical memory regions. */ if (!efi_memmap_get_highest_sized_ram(memRequired, 0x100000000ULL, &max_ram_base, &max_ram_size)) { if (!e820_get_highest_sized_ram(memRequired, 0x100000000ULL, &max_ram_base, &max_ram_size)) { printk(TBOOT_INFO"ERROR No memory area found for image" "relocation!\n"); printk(TBOOT_INFO"required 0x%X\n", memRequired); return false; } } printk(TBOOT_INFO"highest suitable area @ 0x%llX (size 0x%llX)\n", max_ram_base, max_ram_size); ld_ceiling = PAGE_DOWN(max_ram_base + max_ram_size); /* Move modules below the load ceiling upto the ceiling: Prevent module corruption: - Move modules in order of highest to lowest. - Only move modules completely below the load ceiling. */ for( mods_remaining=module_count; mods_remaining > 0; mods_remaining--){ uint32_t highest_mod_i = 0, highest_mod_base = 0, highest_mod_end = 0; bool mod_found = false; for( mod_i=0; mod_imod_start < ld_ceiling) ){ if( (m->mod_end > highest_mod_end) || !mod_found ){ highest_mod_i = mod_i; highest_mod_base= m->mod_start; highest_mod_end = m->mod_end; mod_found = true; } } } /* If no modules found, all modules are above ld_ceiling, We're done. */ if( !mod_found ) break; m = get_module(lctx, highest_mod_i); /* only move the highest module if explicitly below the ceiling */ if(highest_mod_end < ld_ceiling){ uint32_t size = highest_mod_end - highest_mod_base; uint32_t highest_mod_newbase = PAGE_DOWN(ld_ceiling-size); printk(TBOOT_INFO"moving module %u (%u B) from 0x%08X to 0x%08X\n", highest_mod_i, size, highest_mod_base, highest_mod_newbase); tb_memcpy((void *)highest_mod_newbase, (void *)highest_mod_base, size); m->mod_start= highest_mod_newbase; m->mod_end = highest_mod_newbase+size; } /* lower the celing to the base address of the highest module */ ld_ceiling = PAGE_DOWN(m->mod_start); } return true; } /* * Move any mbi components/modules/mbi that just above the kernel */ static bool move_modules_above_elf_kernel( loader_ctx *lctx, elf_header_t *kernel_image) { void *elf_start, *elf_end; uint32_t ld_floor, ld_ceiling; uint32_t module_count, mod_i, mods_remaining; module_t *m; if (LOADER_CTX_BAD(lctx)) return false; /* get end address of loaded elf image */ if ( !get_elf_image_range(kernel_image, &elf_start, &elf_end) ){ printk(TBOOT_INFO"ERROR: failed to get elf image range\n"); return false; } printk(TBOOT_INFO"ELF kernel top is at 0x%X\n", (uint32_t)elf_end); /* compute the lowest base address of all the modules: the ld ceiling */ module_count = get_module_count(lctx); for( mod_i=0, ld_ceiling=0; mod_i < module_count; mod_i++ ){ m = get_module(lctx,mod_i); ld_ceiling = (ld_ceiling < m->mod_start)? m->mod_start : ld_ceiling; } /* set ld_floor to the highest of tboot end address or the ELF-image end address, and then page align */ ld_floor = get_tboot_mem_end(); ld_floor = (ld_floor < (uint32_t)elf_end)? (uint32_t)elf_end : ld_floor; ld_floor = PAGE_UP(ld_floor); /* Ensures all modules are above ld_floor: only move mods down, never up. Failing this check is an indication ELF-loading may have corrupted one of the modules. */ if( (uint32_t)ld_floor > ld_ceiling ){ printk( TBOOT_INFO"Load floor (0x%08X) > load ceiling (0x%08X)\n", ld_floor, ld_ceiling); return false; } /* the i-th iteration of this loop will move the i-th lowest module in memory to ld_floor and raise ld_floor to the new end address of the i-th lowest module */ for( mods_remaining = module_count; mods_remaining > 0; mods_remaining--){ uint32_t lowest_mod_i = 0, lowest_mod_base = 0, lowest_mod_end = 0; bool mod_found = false; /* find the lowest module above the floor */ for( mod_i=0; mod_imod_start >= ld_floor){ if( (m->mod_start < lowest_mod_base) || !mod_found ){ lowest_mod_i = mod_i; lowest_mod_base= m->mod_start; lowest_mod_end = m->mod_end; mod_found = true; } } } m = get_module(lctx, lowest_mod_i); /* only move the lowest module if not already at the floor */ if(lowest_mod_base > ld_floor){ uint32_t size = lowest_mod_end - lowest_mod_base; uint32_t lowest_mod_newbase = ld_floor; /* already page aligned */ printk(TBOOT_INFO"moving module %u (%u B) from 0x%08X to 0x%08X\n", lowest_mod_i, size, lowest_mod_base, lowest_mod_newbase); tb_memcpy((void *)lowest_mod_newbase, (void *)lowest_mod_base, size); m->mod_start= lowest_mod_newbase; m->mod_end = lowest_mod_newbase+size; } /* raise the floor to the end address of the lowest module */ ld_floor = PAGE_UP(m->mod_end); } return true; } static void fixup_modules(loader_ctx *lctx, size_t offset) { unsigned int module_count = get_module_count(lctx); for ( unsigned int i = 0; i < module_count; i++ ) { module_t *m = get_module(lctx, i); if ( below_tboot(m->mod_start) ) { m->mod_start += offset; m->mod_end += offset; } /* MB2 module strings are inline, not addresses */ if (lctx->type == 1) if ( below_tboot(m->string) ) m->string += offset; } } /* * fixup_loader_ctx() is to be called after modules and/or mbi are moved from * below tboot memory to above tboot. It will fixup all pointers in mbi if * mbi was moved; fixup modules table if any modules are moved. If mbi was * moved, adjust the addr field in context, otherwise, leave alone. */ static void fixup_loader_ctx(loader_ctx *lctx, size_t offset) { if (LOADER_CTX_BAD(lctx)) return; bool moving_ctx = below_tboot((unsigned long)lctx->addr); multiboot_info_t *mbi = lctx->addr; if ( moving_ctx ) { printk(TBOOT_INFO"loader context was moved from %p to ", lctx->addr); lctx->addr += offset; printk(TBOOT_INFO"%p\n", lctx->addr); } if (0 < get_module_count(lctx)) { if (lctx->type == MB1_ONLY) if ( below_tboot(mbi->mods_addr) ) mbi->mods_addr += offset; /* not required for MB2--if we moved the pile, we moved this too */ fixup_modules(lctx, offset); } if (lctx->type == MB1_ONLY){ /* RLM change. There's no use passing these on to Xen or whatever, * since they will be tboot's addrs, not the target's! We don't * want the thing we launch using tboot image addresses to deduce * anything about itself! */ if (mbi->flags & MBI_AOUT){ mbi->syms.aout_image.addr = 0; mbi->flags &= ~MBI_AOUT; } if (mbi->flags & MBI_ELF){ mbi->syms.elf_image.addr = 0; mbi->flags &= ~MBI_ELF; } } if (lctx->type == MB2_ONLY){ struct mb2_tag *start, *victim; /* as above, we need to remove ELF tag if we have it */ start = (struct mb2_tag *) (lctx->addr + 8); victim = find_mb2_tag_type(start, MB2_TAG_TYPE_ELF_SECTIONS); if (victim != NULL) (void) remove_mb2_tag(lctx,victim); /* and that's all, folks! */ return; } if ( !moving_ctx) return; /* tboot replace mmap_addr w/ a copy, and make a copy of cmdline * because we modify it. Those pointers don't need offset adjustment. * To make it general and depend less on such kind of changes, just * check whether we need to adjust offset before trying to do it for * each field */ if ( (mbi->flags & MBI_CMDLINE) && below_tboot(mbi->cmdline) ) mbi->cmdline += offset; if ( (mbi->flags & MBI_MEMMAP) && below_tboot(mbi->mmap_addr) ) mbi->mmap_addr += offset; if ( (mbi->flags & MBI_DRIVES) && below_tboot(mbi->drives_addr) ) mbi->drives_addr += offset; if ( (mbi->flags & MBI_CONFIG) && below_tboot(mbi->config_table) ) mbi->config_table += offset; if ( (mbi->flags & MBI_BTLDNAME) && below_tboot(mbi->boot_loader_name) ) mbi->boot_loader_name += offset; if ( (mbi->flags & MBI_APM) && below_tboot(mbi->apm_table) ) mbi->apm_table += offset; if ( mbi->flags & MBI_VBE ) { if ( below_tboot(mbi->vbe_control_info) ) mbi->vbe_control_info += offset; if ( below_tboot(mbi->vbe_mode_info) ) mbi->vbe_mode_info += offset; } return; } static uint32_t get_lowest_mod_start_below_tboot(loader_ctx *lctx) { uint32_t lowest = 0xffffffff; unsigned int mod_count = get_module_count(lctx); for ( unsigned int i = 0; i < mod_count; i++ ) { module_t *m = get_module(lctx, i); if ( m->mod_start < lowest && below_tboot(m->mod_start)) lowest = m->mod_start; } return lowest; } static uint32_t get_highest_mod_end(loader_ctx *lctx) { uint32_t highest = 0; unsigned int mod_count = get_module_count(lctx); for ( unsigned int i = 0; i < mod_count; i++ ) { module_t *m = get_module(lctx, i); if ( m->mod_end > highest ) highest = m->mod_end; } return highest; } /* * Move any mbi components/modules/mbi that are below tboot to just above tboot */ static void move_modules(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return; unsigned long lowest = get_lowest_mod_start_below_tboot(lctx); unsigned long from = 0; if ( below_tboot(lowest) ) from = lowest; else if ( below_tboot((unsigned long)lctx->addr) ) from = (unsigned long)lctx->addr; else return; unsigned long highest = get_highest_mod_end(lctx); unsigned long to = PAGE_UP(highest); if ( to < get_tboot_mem_end() ) to = get_tboot_mem_end(); /* * assuming that all of the members of mbi (e.g. cmdline, * syms.aout_image.addr, etc.) are contiguous with the mbi structure */ if ( to < get_loader_ctx_end(lctx) ) to = get_loader_ctx_end(lctx); tb_memcpy((void *)to, (void *)from, TBOOT_BASE_ADDR - from); printk(TBOOT_DETA"0x%lx bytes copied from 0x%lx to 0x%lx\n", TBOOT_BASE_ADDR - from, from, to); fixup_loader_ctx(lctx, to - from); return; } module_t *get_module(loader_ctx *lctx, unsigned int i) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY){ return(get_module_mb1((multiboot_info_t *) lctx->addr, i)); } else { /* so currently, must be type 2 */ return(get_module_mb2(lctx, i)); } } static void *remove_first_module(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; return(remove_module(lctx, NULL)); } /* a shame this has to be so big, but if we get an MB2 VBE struct, * those are pretty close to 1K on their own. */ #define MB2_TEMP_SIZE 512 static uint32_t mb2_temp[MB2_TEMP_SIZE]; static bool convert_mb2_to_mb1(void) { /* it's too hard to do this in place. MB2 "data" is all inline, so * it can be copied to a new location, as is, and still be intact. MB1 * has pointers in the info struct to other stuff further along in its * stuff, so it doesn't copy/move well. We'll make a copy of the MB2 * info, and then build the MB1 in place where the MB2 we started with was. */ uint32_t mb2_size; multiboot_info_t *mbi; uint32_t i, obd; if (LOADER_CTX_BAD(g_ldr_ctx)) return false; if (g_ldr_ctx->type != MB2_ONLY) return false; mb2_size = *((uint32_t *)g_ldr_ctx->addr); if (mb2_size >= MB2_TEMP_SIZE * 4) return false; /* copy it all to temp */ { uint8_t *s, *d; s = (uint8_t *) g_ldr_ctx->addr; d = (uint8_t *) mb2_temp; for (i = 0; i < mb2_size; i++) d[i] = s[i]; mbi = (multiboot_info_t *) g_ldr_ctx->addr; g_ldr_ctx->addr = mb2_temp; for (i = 0; i < mb2_size; i++) ((uint8_t *)mbi)[i] = 0; } /* out of band data pointer */ obd = (uint32_t) mbi + sizeof(multiboot_info_t); /* uint32 align it, just in case */ obd = (obd + 3) & ~3; /* do we have mem_limits? */ if (have_loader_memlimits(g_ldr_ctx)){ mbi->flags |= MBI_MEMLIMITS; mbi->mem_lower = get_loader_mem_lower(g_ldr_ctx); mbi->mem_upper = get_loader_mem_upper(g_ldr_ctx); } /* do we have a boot device? */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_BOOTDEV); if (start != NULL){ struct mb2_tag_bootdev *bd = (struct mb2_tag_bootdev *) start; mbi->flags |= MBI_BOOTDEV; mbi->boot_device.bios_driver = bd->biosdev; mbi->boot_device.top_level_partition = bd->part; mbi->boot_device.sub_partition = bd->slice; mbi->boot_device.third_partition = 0xff; } } /* command line */ { const char *mb2_cmd = get_cmdline(g_ldr_ctx); if (mb2_cmd){ char *mb1_cmd = (char *) obd; while (*mb2_cmd){ *mb1_cmd = *mb2_cmd; mb1_cmd++; mb2_cmd++; obd++; } /* uint32_t align it again */ obd = (obd + 3) & ~3; mbi->flags |= MBI_CMDLINE; } } /* modules--in MB1, this is a count and a pointer to an array of module_t */ mbi->mods_count = get_module_count(g_ldr_ctx); if (mbi->mods_count > 0){ /* for mb1, the modulke strings are out-of-band */ uint32_t obd_str = obd + (mbi->mods_count * sizeof(module_t)); mbi->mods_addr = obd; for (i = 0; i < mbi->mods_count; i++){ module_t *mb1_mt = (module_t *) obd; module_t *mb2_mt = get_module(g_ldr_ctx, i); char *s = (char *)&mb2_mt->string; mb1_mt->mod_start = mb2_mt->mod_start; mb1_mt->mod_end = mb2_mt->mod_end; mb1_mt->reserved = 0; if (*s){ char *d = (char *) obd_str; mb1_mt->string = obd_str; while (*s){ *d = *s; d++; s++; obd_str++; } *d = *s; obd_str++; } else { mb1_mt->string = 0; } } /* uint32_t align past the strings */ obd = (obd_str + 3) & ~3; mbi->flags |= MBI_MODULES; } /* a.out/elf sections--we know these are not there */ /* memory map--we can just use the modified copy for this one */ if (have_loader_memmap(g_ldr_ctx)){ mbi->mmap_addr = (uint32_t)get_e820_copy(); mbi->mmap_length = (get_nr_map()) * sizeof(memory_map_t); mbi->flags |= MBI_MEMMAP; } /* drives info --there's no equivalent in MB2 */ /* config table -- again, nothing equivalent? */ /* boot loader name */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_LOADER_NAME); if (start){ struct mb2_tag_string *bload = (struct mb2_tag_string *) start; char *s, *d; mbi->boot_loader_name = obd; s = (char *) &bload->string[0]; d = (char *) obd; while (*s){ *d = *s; s++; d++; obd++; } *d = *s; obd++; obd = (obd + 3) & ~3; mbi->flags |= MBI_BTLDNAME; } } /* apm table */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_APM); if (start){ struct mb2_tag_apm *apm = (struct mb2_tag_apm *) start; uint8_t *s, *d; s = (uint8_t *)&apm->version; d = (uint8_t *) obd; mbi->apm_table = obd; for (i = 0; i < sizeof(struct mb2_tag_apm) - 2*sizeof(uint32_t); i++){ *d = *s; d++; s++; obd++; } obd = (obd + 3) & ~3; mbi->flags |= MBI_APM; } } /* vbe poop, if we can get these to map across */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_VBE); if (start){ struct mb2_tag_vbe *vbe = (struct mb2_tag_vbe *) start; uint8_t *s, *d; mbi->vbe_mode = vbe->vbe_mode; mbi->vbe_interface_seg = vbe->vbe_interface_seg; mbi->vbe_interface_off = vbe->vbe_interface_off; mbi->vbe_interface_len = vbe->vbe_interface_len; mbi->vbe_control_info = obd; d = (uint8_t *) obd; s = &vbe->vbe_control_info.external_specification[0]; for (i = 0; i < 512; i++){ *d = *s; d++; s++; obd++; } /* if obd was aligned before, it still is */ mbi->vbe_mode_info = obd; d = (uint8_t *) obd; s = &vbe->vbe_mode_info.external_specification[0]; for (i = 0; i < 256; i++){ *d = *s; d++; s++; obd++; } mbi->flags |= MBI_VBE; } } /* all good--point g_ldr_ctx addr to new, fix type */ g_ldr_ctx->addr = (void *)&mbi; g_ldr_ctx->type = MB1_ONLY; return true; } static uint32_t determine_multiboot_type(void *image) { /* walk through the allowed region looking for multiboot header magic */ /* note that we're going low-tech--we're not verifying a valid header, * and probably should. */ int result = MB_NONE; void *walker; for (walker = image; walker < image + MULTIBOOT_HEADER_SEARCH_LIMIT; walker += sizeof(uint32_t)){ if (*((uint32_t *)walker) == MULTIBOOT_HEADER_MAGIC){ result += MB1_ONLY; break; } } for (walker = image; walker < image + MB2_HEADER_SEARCH_LIMIT; walker += sizeof(uint64_t)){ if (*((uint32_t *)walker) == MB2_HEADER_MAGIC){ result += MB2_ONLY; break; } } return result; } bool launch_kernel(bool is_measured_launch) { enum { ELF, LINUX } kernel_type; void *kernel_entry_point; uint32_t mb_type = MB_NONE; struct tpm_if *tpm = get_tpm(); if (g_tpm_family != TPM_IF_20_CRB ) { if (!release_locality(tpm->cur_loc)) printk(TBOOT_ERR"Release TPM FIFO locality %d failed \n", tpm->cur_loc); } else { if (!tpm_relinquish_locality_crb(tpm->cur_loc)) printk(TBOOT_ERR"Relinquish TPM CRB locality %d failed \n", tpm->cur_loc); if (!tpm_workaround_crb()) printk(TBOOT_ERR"CRB workaround failed \n"); } /* if using memory logging, reserve log area */ if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY ) { uint64_t base = TBOOT_SERIAL_LOG_ADDR; uint64_t size = TBOOT_SERIAL_LOG_SIZE; printk(TBOOT_INFO"reserving tboot memory log (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) apply_policy(TB_ERR_FATAL); if (!efi_memmap_reserve(base, size)) { apply_policy(TB_ERR_FATAL); } } /* replace map in loader context with copy */ replace_e820_map(g_ldr_ctx); if (get_tboot_dump_memmap()) { printk(TBOOT_DETA"adjusted e820 map:\n"); print_e820_map(); } if ( !verify_loader_context(g_ldr_ctx) ) return false; /* remove all SINIT and LCP modules since kernel may not handle */ remove_txt_modules(g_ldr_ctx); module_t *m = get_module(g_ldr_ctx,0); void *kernel_image = (void *)m->mod_start; size_t kernel_size = m->mod_end - m->mod_start; if ( is_elf_image(kernel_image, kernel_size) ) { printk(TBOOT_INFO"kernel is ELF format\n"); kernel_type = ELF; mb_type = determine_multiboot_type(kernel_image); switch (mb_type){ case MB1_ONLY: /* if this is an EFI boot, this is not sufficient */ if (is_loader_launch_efi(g_ldr_ctx)){ printk(TBOOT_ERR"Target kernel only supports multiboot1 "); printk(TBOOT_ERR"which will not suffice for EFI launch\n"); return false; } /* if we got MB2 and they want MB1 and this is trad BIOS, * we can downrev the MB data to MB1 and pass that along. */ if (g_ldr_ctx->type == MB2_ONLY){ if (false == convert_mb2_to_mb1()) return false; } break; case MB2_ONLY: /* if we got MB1, we need to die here */ if (g_ldr_ctx->type == MB1_ONLY){ printk(TBOOT_ERR"Target requires multiboot 2, loader only "); printk(TBOOT_ERR"supplied multiboot 1m giving up\n"); return false; } break; case MB_BOTH: /* we'll pass through whichever we got, and hope */ mb_type = g_ldr_ctx->type; break; default: printk(TBOOT_INFO"but kernel does not have multiboot header\n"); return false; } /* fix for GRUB2, which may load modules into memory before tboot */ move_modules(g_ldr_ctx); /* move modules out of the way (to top og memory below 4G) */ printk(TBOOT_INFO"move modules to high memory\n"); if(!move_modules_to_high_memory(g_ldr_ctx)) return false; } else { printk(TBOOT_INFO"assuming kernel is Linux format\n"); kernel_type = LINUX; } /* print_mbi(g_mbi); */ kernel_image = remove_first_module(g_ldr_ctx); if ( kernel_image == NULL ) return false; if ( kernel_type == ELF ) { if ( is_measured_launch ) adjust_kernel_cmdline(g_ldr_ctx, &_tboot_shared); if ( !expand_elf_image((elf_header_t *)kernel_image, &kernel_entry_point) ) return false; /* move modules on top of expanded kernel */ if(!move_modules_above_elf_kernel(g_ldr_ctx, (elf_header_t *)kernel_image)) return false; printk(TBOOT_INFO"transfering control to kernel @%p...\n", kernel_entry_point); /* (optionally) pause when transferring to kernel */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); return jump_elf_image(kernel_entry_point, mb_type == MB1_ONLY ? MB_MAGIC : MB2_LOADER_MAGIC); } else if ( kernel_type == LINUX ) { void *initrd_image; size_t initrd_size; if ( get_module_count(g_ldr_ctx) == 0 ) { initrd_size = 0; initrd_image = 0; } else { m = get_module(g_ldr_ctx,0); initrd_image = (void *)m->mod_start; initrd_size = m->mod_end - m->mod_start; } expand_linux_image(kernel_image, kernel_size, initrd_image, initrd_size, &kernel_entry_point, is_measured_launch); printk(TBOOT_INFO"transfering control to kernel @%p...\n", kernel_entry_point); /* (optionally) pause when transferring to kernel */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); return jump_linux_image(kernel_entry_point); } printk(TBOOT_ERR"unknown kernel type\n"); return false; } /* * find_module_by_uuid * * find a module by its uuid * */ bool find_module_by_uuid(loader_ctx *lctx, void **base, size_t *size, const uuid_t *uuid) { return find_module(lctx, base, size, uuid, sizeof(*uuid)); } /* * find_module_by_file_signature * * find a module by its file signature * */ bool find_module_by_file_signature(loader_ctx *lctx, void **base, size_t *size, const char* file_signature) { return find_module(lctx, base, size, file_signature, tb_strlen(file_signature)); } bool verify_modules(loader_ctx *lctx) { uint64_t base, size; module_t *m; uint32_t module_count; if (LOADER_CTX_BAD(lctx)) return false; module_count = get_module_count(lctx); /* verify e820 map to make sure each module is OK in e820 map */ /* check modules in mbi should be in RAM */ for ( unsigned int i = 0; i < module_count; i++ ) { m = get_module(lctx,i); base = m->mod_start; size = m->mod_end - m->mod_start; printk(TBOOT_INFO "verifying module %d of mbi (%Lx - %Lx) in e820 table\n\t", i, base, (base + size - 1)); if ( e820_check_region(base, size) != E820_RAM ) { printk(TBOOT_ERR": failed.\n"); return false; } else printk(TBOOT_INFO": succeeded.\n"); } return true; } char *get_module_cmd(loader_ctx *lctx, module_t *mod) { if (LOADER_CTX_BAD(lctx) || mod == NULL) return NULL; if (lctx->type == MB1_ONLY) return (char *) mod->string; else /* currently must be type 2 */ return (char *)&(mod->string); } char *get_first_module_cmd(loader_ctx *lctx) { module_t *mod = get_module(lctx, 0); return get_module_cmd(lctx, mod); } char *get_cmdline(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ if (((multiboot_info_t *)lctx->addr)->flags & MBI_CMDLINE){ return (char *) ((multiboot_info_t *)lctx->addr)->cmdline; } else { return NULL; } } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_CMDLINE); if (start != NULL){ struct mb2_tag_string *cmd = (struct mb2_tag_string *) start; return (char *) &(cmd->string); } return NULL; } } bool have_loader_memlimits(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return false; if (lctx->type == MB1_ONLY){ return (((multiboot_info_t *)lctx->addr)->flags & MBI_MEMLIMITS) != 0; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MEMLIMITS); return (start != NULL); } } uint32_t get_loader_mem_lower(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ return ((multiboot_info_t *)lctx->addr)->mem_lower; } /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MEMLIMITS); if (start != NULL){ struct mb2_tag_memlimits *lim = (struct mb2_tag_memlimits *) start; return lim->mem_lower; } return 0; } uint32_t get_loader_mem_upper(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ return ((multiboot_info_t *)lctx->addr)->mem_upper; } /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MEMLIMITS); if (start != NULL){ struct mb2_tag_memlimits *lim = (struct mb2_tag_memlimits *) start; return lim->mem_upper; } return 0; } unsigned int get_module_count(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ return(((multiboot_info_t *) lctx->addr)->mods_count); } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); unsigned int count = 0; start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); while (start != NULL){ count++; /* nudge off this guy */ start = next_mb2_tag(start); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); } return count; } } bool have_loader_memmap(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return false; if (lctx->type == MB1_ONLY){ return (((multiboot_info_t *) lctx->addr)->flags & MBI_MEMMAP) != 0; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MMAP); return (start != NULL); } } memory_map_t *get_loader_memmap(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ return (memory_map_t *)((multiboot_info_t *) lctx->addr)->mmap_addr; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MMAP); if (start != NULL){ struct mb2_tag_mmap *mmap = (struct mb2_tag_mmap *) start; /* note here: the MB2 mem entries start with the 64-bit address. * the memory_map_t starts with four bytes of dummy "size". * Pointing to the MB2 mmap "entry_version" instead of the entries * lines the two tables up. */ return (memory_map_t *) &(mmap->entry_version); } return NULL; } } uint32_t get_loader_memmap_length(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ return (uint32_t)((multiboot_info_t *) lctx->addr)->mmap_length; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MMAP); if (start != NULL){ struct mb2_tag_mmap *mmap = (struct mb2_tag_mmap *) start; /* mmap->size is the size of the whole tag. We have 16 bytes * ahead of the entries */ return mmap->size - 16; } return 0; } } unsigned long get_loader_ctx_end(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == 1){ /* multiboot 1 */ return (get_mbi_mem_end_mb1((multiboot_info_t *) lctx->addr)); } else { /* currently must be type 2 */ unsigned long mb2_size = *((unsigned long *) lctx->addr); return PAGE_UP(mb2_size + (unsigned long) lctx->addr); } } /* * will go through all modules to find an RACM that matches the platform * (size can be NULL) */ bool find_platform_racm(loader_ctx *lctx, void **base, uint32_t *size) { if ( base != NULL ) *base = NULL; if ( size != NULL ) *size = 0; if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"no module info\n"); return false; } for ( int i = get_module_count(lctx) - 1; i >= 0; i-- ) { module_t *m = get_module(lctx, i); printk(TBOOT_DETA "checking if module %s is an RACM for this platform...\n", get_module_cmd(lctx, m)); void *base2 = (void *)m->mod_start; uint32_t size2 = m->mod_end - (unsigned long)(base2); if ( is_racm_acmod(base2, size2, false) && does_acmod_match_platform((acm_hdr_t *)base2) ) { if ( base != NULL ) *base = base2; if ( size != NULL ) *size = size2; printk(TBOOT_DETA"RACM matches platform\n"); return true; } } /* no RACM found for this platform */ printk(TBOOT_ERR"no RACM found\n"); return false; } /* * will go through all modules to find an SINIT that matches the platform * (size can be NULL) */ bool find_platform_sinit_module(loader_ctx *lctx, void **base, uint32_t *size) { if ( base != NULL ) *base = NULL; if ( size != NULL ) *size = 0; if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"no module info\n"); return false; } for ( unsigned int i = get_module_count(lctx) - 1; i > 0; i-- ) { module_t *m = get_module(lctx, i); if (lctx->type == 1) printk(TBOOT_DETA "checking if module %s is an SINIT for this platform...\n", (const char *)m->string); if (lctx->type == 2) printk(TBOOT_DETA "checking if module %s is an SINIT for this platform...\n", (const char *)&(m->string)); void *base2 = (void *)m->mod_start; uint32_t size2 = m->mod_end - (unsigned long)(base2); if ( is_sinit_acmod(base2, size2, false) && does_acmod_match_platform((acm_hdr_t *)base2) ) { if ( base != NULL ) *base = base2; if ( size != NULL ) *size = size2; printk(TBOOT_DETA"SINIT matches platform\n"); return true; } } /* no SINIT found for this platform */ printk(TBOOT_ERR"no SINIT AC module found\n"); return false; } void replace_e820_map(loader_ctx *lctx) { /* replace original with the copy */ if (LOADER_CTX_BAD(lctx)) return; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ multiboot_info_t *mbi = (multiboot_info_t *) lctx->addr; mbi->mmap_addr = (uint32_t)get_e820_copy(); mbi->mmap_length = (get_nr_map()) * sizeof(memory_map_t); mbi->flags |= MBI_MEMMAP; /* in case only MBI_MEMLIMITS was set */ return; } else { /* currently must be type 2 */ memory_map_t *old, *new; uint32_t i; uint32_t old_memmap_size = get_loader_memmap_length(lctx); uint32_t old_memmap_entry_count = old_memmap_size / sizeof(memory_map_t); if (old_memmap_entry_count < (get_nr_map())){ /* we have to grow */ struct mb2_tag *map = (struct mb2_tag *)(lctx->addr + 8); map = find_mb2_tag_type(map, MB2_TAG_TYPE_MMAP); if (map == NULL){ printk(TBOOT_ERR"MB2 map not found\n"); return; } if (false == grow_mb2_tag(lctx, map, sizeof(memory_map_t) * ((get_nr_map()) - old_memmap_entry_count))){ printk(TBOOT_ERR"MB2 failed to grow e820 map tag\n"); return; } } /* copy in new data */ { /* RLM: for now, we'll leave the entries in MB1 format (with real * size). That may need revisited. */ new = get_e820_copy(); old = get_loader_memmap(lctx); if ( old == NULL ) { printk(TBOOT_ERR"old memory map not found\n"); return; } for (i = 0; i < (get_nr_map()); i++){ *old = *new; old++, new++; } } return; } return; } void print_loader_ctx(loader_ctx *lctx) { if (lctx->type != MB2_ONLY){ printk(TBOOT_ERR"this routine only prints out multiboot 2\n"); return; } else { struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); printk(TBOOT_INFO"MB2 dump: addr %p, size %d\n", lctx->addr, *(uint32_t *)lctx->addr); while (start != NULL){ printk(TBOOT_INFO"MB2 tag found of type %d size %d ", start->type, start->size); switch (start->type){ case MB2_TAG_TYPE_CMDLINE: case MB2_TAG_TYPE_LOADER_NAME: { struct mb2_tag_string *ts = (struct mb2_tag_string *) start; printk(TBOOT_INFO"%s", ts->string); } break; case MB2_TAG_TYPE_MODULE: { struct mb2_tag_module *ts = (struct mb2_tag_module *) start; printk(TBOOT_INFO"mod_start: 0x%x, mod_end: 0x%x", ts->mod_start, ts->mod_end); printk_long(ts->cmdline); } break; default: break; } printk(TBOOT_INFO"\n"); start = next_mb2_tag(start); } return; } } uint8_t *get_loader_rsdp(loader_ctx *lctx, uint32_t *length) { struct mb2_tag *start; struct mb2_tag_new_acpi *new_acpi; if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type != MB2_ONLY) return NULL; if (length == NULL) return NULL; start = (struct mb2_tag *) (lctx->addr + 8); new_acpi = (struct mb2_tag_new_acpi *) find_mb2_tag_type(start, MB2_TAG_TYPE_ACPI_NEW); if (new_acpi == NULL){ /* we'll try the old type--the tag structs are the same */ new_acpi = (struct mb2_tag_new_acpi *) find_mb2_tag_type(start, MB2_TAG_TYPE_ACPI_OLD); if (new_acpi == NULL) return NULL; } *length = new_acpi->size - 8; return new_acpi->rsdp; } bool get_loader_efi_ptr(loader_ctx *lctx, uint32_t *address, uint64_t *long_address) { struct mb2_tag *start, *hit; struct mb2_tag_efi32 *efi32; struct mb2_tag_efi64 *efi64; if (LOADER_CTX_BAD(lctx)) return false; if (lctx->type != MB2_ONLY) return false; start = (struct mb2_tag *)(lctx->addr + 8); hit = find_mb2_tag_type(start, MB2_TAG_TYPE_EFI32); if (hit != NULL){ efi32 = (struct mb2_tag_efi32 *) hit; *address = (uint32_t) efi32->pointer; *long_address = 0; return true; } hit = find_mb2_tag_type(start, MB2_TAG_TYPE_EFI64); if (hit != NULL){ efi64 = (struct mb2_tag_efi64 *) hit; *long_address = (uint64_t) efi64->pointer; *address = 0; return true; } return false; } uint32_t find_efi_memmap(loader_ctx *lctx, uint32_t *descr_size, uint32_t *descr_vers, uint32_t *mmap_size) { struct mb2_tag *start = NULL, *hit = NULL; struct mb2_tag_efi_mmap *efi_mmap = NULL; if (LOADER_CTX_BAD(lctx) || lctx->type != MB2_ONLY) { return 0; } if (descr_size == NULL || descr_vers == NULL || mmap_size == NULL) { return 0; } start = (struct mb2_tag *)(lctx->addr + 8); hit = find_mb2_tag_type(start, MB2_TAG_TYPE_EFI_MMAP); if (hit == NULL) { return 0; } efi_mmap = (struct mb2_tag_efi_mmap *)hit; *descr_size = efi_mmap->descr_size; *descr_vers = efi_mmap->descr_vers; *mmap_size = efi_mmap->size - sizeof(struct mb2_tag_efi_mmap); if (*mmap_size % *descr_size) { printk(TBOOT_WARN "EFI memmmap (0x%x) should be a multiple of descriptor size (0x%x)\n", *mmap_size, *descr_size); } return (uint32_t)(&efi_mmap->efi_mmap); } bool is_loader_launch_efi(loader_ctx *lctx) { uint32_t addr = 0; uint64_t long_addr = 0; if (LOADER_CTX_BAD(lctx)) return false; return (get_loader_efi_ptr(lctx, &addr, &long_addr)); } bool load_framebuffer_info(loader_ctx *lctx, void *vscr, bool efifb) { screen_info_t *scr = (screen_info_t *) vscr; struct mb2_tag *start; if (scr == NULL) return false; if (LOADER_CTX_BAD(lctx) || lctx->type != MB2_ONLY) return false; start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_FRAMEBUFFER); if (start != NULL){ u32 ext_lfb_base; struct mb2_fb *mbf = (struct mb2_fb *) start; scr->lfb_base = (uint32_t) mbf->common.fb_addr; ext_lfb_base = (u64)mbf->common.fb_addr >> 32; if (ext_lfb_base != 0) { scr->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; scr->ext_lfb_base = ext_lfb_base; } scr->lfb_width = mbf->common.fb_width; scr->lfb_height = mbf->common.fb_height; scr->lfb_depth = mbf->common.fb_bpp; scr->lfb_line_len = mbf->common.fb_pitch; scr->red_mask_size = mbf->fb_red_mask_size; scr->red_field_pos = mbf->fb_red_field_position; scr->blue_mask_size = mbf->fb_blue_mask_size; scr->blue_field_pos = mbf->fb_blue_field_position; scr->green_mask_size = mbf->fb_green_mask_size; scr->green_field_pos = mbf->fb_green_field_position; scr->lfb_size = scr->lfb_line_len * scr->lfb_height; /* round up to next 64k */ scr->lfb_size = (scr->lfb_size + 65535) & 65535; if (efifb) { scr->orig_video_isVGA = 0x70; /* EFI FB */ } else { scr->orig_video_isVGA = 0x23; /* VESA VGA */ } scr->orig_y = 24; return true; } else { return false; } } struct mb2_fb* get_framebuffer_info(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx) || lctx->type != MB2_ONLY) { return NULL; } struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); return (struct mb2_fb*)find_mb2_tag_type(start, MB2_TAG_TYPE_FRAMEBUFFER); } void determine_loader_type(void *addr, uint32_t magic) { if (g_ldr_ctx->addr == NULL){ /* brave new world */ g_ldr_ctx->addr = addr; /* save for post launch */ switch (magic){ case MB_MAGIC: g_ldr_ctx->type = MB1_ONLY; { /* we may as well do this here--if we received an ELF * sections tag, we won't use it, and it's useless to * Xen downstream, since it's OUR ELF sections, not Xen's */ multiboot_info_t *mbi = (multiboot_info_t *) addr; if (mbi->flags & MBI_AOUT){ mbi->flags &= ~MBI_AOUT; } if (mbi->flags & MBI_ELF){ mbi->flags &= ~MBI_ELF; } } break; case MB2_LOADER_MAGIC: g_ldr_ctx->type = MB2_ONLY; /* save the original MB2 info size, since we have * to put updates inline */ g_mb_orig_size = *(uint32_t *) addr; { /* we may as well do this here--if we received an ELF * sections tag, we won't use it, and it's useless to * Xen downstream, since it's OUR ELF sections, not Xen's */ struct mb2_tag *start = (struct mb2_tag *)(addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_ELF_SECTIONS); if (start != NULL) (void) remove_mb2_tag(g_ldr_ctx, start); } break; default: g_ldr_ctx->type = 0; break; } } /* so at this point, g_ldr_ctx->type has one of three values: * 0: not a multiboot launch--we're doomed * 1: MB1 launch * 2: MB2 launch */ } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/lz.c0000644000000000000000000003142314210363175014270 0ustar 00000000000000/************************************************************************* * Name: lz.c * Author: Marcus Geelnard * Description: LZ77 coder/decoder implementation. * Reentrant: Yes * * The LZ77 compression scheme is a substitutional compression scheme * proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in * its design, and uses no fancy bit level compression. * * This is my first attempt at an implementation of a LZ77 code/decoder. * * The principle of the LZ77 compression algorithm is to store repeated * occurrences of strings as references to previous occurrences of the same * string. The point is that the reference consumes less space than the * string itself, provided that the string is long enough (in this * implementation, the string has to be at least 4 bytes long, since the * minimum coded reference is 3 bytes long). Also note that the term * "string" refers to any kind of byte sequence (it does not have to be * an ASCII string, for instance). * * The coder uses a brute force approach to finding string matches in the * history buffer (or "sliding window", if you wish), which is very, very * slow. I recon the complexity is somewhere between O(n^2) and O(n^3), * depending on the input data. * * There is also a faster implementation that uses a large working buffer * in which a "jump table" is stored, which is used to quickly find * possible string matches (see the source code for LZ_CompressFast() for * more information). The faster method is an order of magnitude faster, * but still quite slow compared to other compression methods. * * The upside is that decompression is very fast, and the compression ratio * is often very good. * * The reference to a string is coded as a (length,offset) pair, where the * length indicates the length of the string, and the offset gives the * offset from the current data position. To distinguish between string * references and literal strings (uncompressed bytes), a string reference * is preceded by a marker byte, which is chosen as the least common byte * symbol in the input data stream (this marker byte is stored in the * output stream as the first byte). * * Occurrences of the marker byte in the stream are encoded as the marker * byte followed by a zero byte, which means that occurrences of the marker * byte have to be coded with two bytes. * * The lengths and offsets are coded in a variable length fashion, allowing * values of any magnitude (up to 4294967295 in this implementation). * * With this compression scheme, the worst case compression result is * (257/256)*insize + 1. * *------------------------------------------------------------------------- * Copyright (c) 2003-2010 Marcus Geelnard * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would * be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * * Marcus Geelnard * marcus.geelnard at home.se *************************************************************************/ /************************************************************************* * Constants used for LZ77 coding *************************************************************************/ /* Maximum offset (can be any size < 2^31). Lower values give faster compression, while higher values gives better compression. The default value of 100000 is quite high. Experiment to see what works best for you. */ #define LZ_MAX_OFFSET 5000 /************************************************************************* * INTERNAL FUNCTIONS * *************************************************************************/ /************************************************************************* * _LZ_StringCompare() - Return maximum length string match. *************************************************************************/ static unsigned int _LZ_StringCompare( char * str1, char * str2, unsigned int minlen, unsigned int maxlen ) { unsigned int len; for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len ); return len; } /************************************************************************* * _LZ_WriteVarSize() - Write unsigned integer with variable number of * bytes depending on value. *************************************************************************/ /*will write at most 5 bytes to buf*/ static int _LZ_WriteVarSize( unsigned int x, char * buf ) { unsigned int y; int num_bytes, i, b; /* Determine number of bytes needed to store the number x */ y = x >> 3; for( num_bytes = 5; num_bytes >= 2; -- num_bytes ) { if( y & 0xfe000000 ) break; y <<= 7; } /* Write all bytes, seven bits in each, with 8:th bit set for all */ /* but the last byte. */ for( i = num_bytes-1; i >= 0; -- i ) { b = (x >> (i*7)) & 0x0000007f; if( i > 0 ) { b |= 0x00000080; } *buf ++ = (char) b; } /* Return number of bytes written */ return num_bytes; } /************************************************************************* * _LZ_ReadVarSize() - Read unsigned integer with variable number of * bytes depending on value. *************************************************************************/ static int _LZ_ReadVarSize( unsigned int * x, char * buf ) { unsigned int y, b, num_bytes; /* Read complete value (stop when byte contains zero in 8:th bit) */ y = 0; num_bytes = 0; do { b = (unsigned int) (*buf ++); y = (y << 7) | (b & 0x0000007f); ++ num_bytes; } while( b & 0x00000080 ); /* Store value in x */ *x = y; /* Return number of bytes read */ return num_bytes; } /************************************************************************* * PUBLIC FUNCTIONS * *************************************************************************/ /************************************************************************* * LZ_Compress() - Compress a block of data using an LZ77 coder. * in - Input (uncompressed) buffer. * out - Output (compressed) buffer. This buffer must be 0.4% larger * than the input buffer, plus one byte. * insize - Number of input bytes. * outsize - Number of bytes that can be stored in the output buffer. * The function returns the size of the compressed data or (-1) if there * is insufficient space in the output buffer. *************************************************************************/ int LZ_Compress( char *in, char *out, unsigned int insize, unsigned int outsize) { char marker, symbol; unsigned int inpos, outpos, bytesleft, i; unsigned int maxoffset, offset, bestoffset; unsigned int length, bestlength; unsigned int histogram[ 256 ]; char *ptr1, *ptr2; /* Do we have anything to compress? */ if( insize < 1 ) { return 0; } if( outsize < 1 ) { return -1; } /* Create histogram */ for( i = 0; i < 256; ++ i ) { histogram[ i ] = 0; } for( i = 0; i < insize; ++ i ) { ++ histogram[(unsigned char) in[ i ] ]; } /* Find the least common byte, and use it as the marker symbol */ marker = 0; for( i = 1; i < 256; ++ i ) { if( histogram[ i ] < histogram[(unsigned char) marker ] ) { marker = i; } } /* Remember the marker symbol for the decoder */ out[ 0 ] = marker; /* Start of compression */ inpos = 0; outpos = 1; /* Main compression loop */ bytesleft = insize; do { /* Determine most distant position */ if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET; else maxoffset = inpos; /* Get pointer to current position */ ptr1 = &in[ inpos ]; /* Search history window for maximum length string match */ bestlength = 3; bestoffset = 0; for( offset = 1; offset <= maxoffset; ++ offset ) { /* Get pointer to candidate string */ ptr2 = &ptr1[ -(int)offset ]; /* Quickly determine if this is a candidate (for speed) */ if( (ptr1[ 0 ] == ptr2[ 0 ]) && (ptr1[ bestlength ] == ptr2[ bestlength ]) ) { /* Count maximum length match at this offset */ length = _LZ_StringCompare( ptr1, ptr2, 0, bytesleft ); /* Better match than any previous match? */ if( length > bestlength ) { bestlength = length; bestoffset = offset; } } } /* Was there a good enough match? */ if( (bestlength >= 8) || ((bestlength == 4) && (bestoffset <= 0x0000007f)) || ((bestlength == 5) && (bestoffset <= 0x00003fff)) || ((bestlength == 6) && (bestoffset <= 0x001fffff)) || ((bestlength == 7) && (bestoffset <= 0x0fffffff)) ) { if( (outpos + 1 + 5 + 5) > outsize ) return -1; out[ outpos ++ ] = (char) marker; outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] ); outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] ); inpos += bestlength; bytesleft -= bestlength; } else { if( (outpos + 2) > outsize ) return -1; /* Output single byte (or two bytes if marker byte) */ symbol = in[ inpos ++ ]; out[ outpos ++ ] = symbol; if( symbol == marker ) { out[ outpos ++ ] = 0; } -- bytesleft; } } while( bytesleft > 3 ); /* Dump remaining bytes, if any */ if( (outpos + bytesleft*2) > outsize ) return -1; while( inpos < insize ) { if( in[ inpos ] == marker ) { out[ outpos ++ ] = marker; out[ outpos ++ ] = 0; } else { out[ outpos ++ ] = in[ inpos ]; } ++ inpos; } return outpos; } /************************************************************************* * LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder. * in - Input (compressed) buffer. * out - Output (uncompressed) buffer. This buffer must be large * enough to hold the uncompressed data. * insize - Number of input bytes. * outsize - Number of bytes that can be stored in the output buffer. * The function returns the size of the uncompressed data or (-1) if there * is insufficient space in the output buffer. *************************************************************************/ int LZ_Uncompress( char *in, char *out, unsigned int insize, unsigned int outsize ) { char marker, symbol; unsigned int i, inpos, outpos, length, offset; /* Do we have anything to uncompress? */ if( insize < 1 ) { return -1; } /* Get marker symbol from input stream */ marker = in[ 0 ]; inpos = 1; /* Main decompression loop */ outpos = 0; do { if( outpos >= outsize ) return -1; symbol = in[ inpos ++ ]; if( symbol == marker ) { /* We had a marker byte */ if( in[ inpos ] == 0 ) { /* It was a single occurrence of the marker byte */ out[ outpos ++ ] = marker; ++ inpos; } else { /* Extract true length and offset */ inpos += _LZ_ReadVarSize( &length, &in[ inpos ] ); inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] ); if( outpos + length > outsize ) return -1; /* Copy corresponding data from history window */ for( i = 0; i < length; ++ i ) { out[ outpos ] = out[ outpos - offset ]; ++ outpos; } } } else { /* No marker, plain copy */ out[ outpos ++ ] = symbol; } } while( inpos < insize ); return outpos; } tboot-1.10.5/tboot/common/memcmp.c0000644000000000000000000000417014210363175015120 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* $FreeBSD: src/sys/libkern/memcmp.c,v 1.1 2008/09/23 14:45:10 obrien Exp $ */ /* * Portions copyright (c) 2010-2018, Intel Corporation */ #include /* * Compare memory regions. */ int tb_memcmp(const void *s1, const void *s2, size_t n) { if (s1 == NULL || s2 == NULL) return (-1); if (s1 == s2) return (0); if (n != 0) { const unsigned char *p1 = s1, *p2 = s2; do { if (*p1++ != *p2++) return (*--p1 - *--p2); } while (--n != 0); } return (0); } tboot-1.10.5/tboot/common/memcpy.c0000644000000000000000000000723614210363175015142 0ustar 00000000000000/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* $FreeBSD: src/sys/powerpc/powerpc/bcopy.c,v 1.5.24.1 2010/02/10 00:26:20 kensmith Exp $ */ #include /* * sizeof(word) MUST BE A POWER OF TWO * SO THAT wmask BELOW IS ALL ONES */ typedef int word; /* "word" used for optimal copy speed */ #define wsize sizeof(word) #define wmask (wsize - 1) /* * Copy a block of memory, handling overlap. * This is the routine that actually implements * (the portable versions of) bcopy, memcpy, and memmove. */ void *tb_memcpy(void *dst0, const void *src0, size_t length) { char *dst; const char *src; size_t t; dst = dst0; src = src0; if (dst0 == NULL || src0 == NULL) return NULL; if (length == 0 || dst == src) { /* nothing to do */ goto done; } /* * Macros: loop-t-times; and loop-t-times, t>0 */ #define TLOOP(s) if (t) TLOOP1(s) #define TLOOP1(s) do { s; } while (--t) if ((unsigned long)dst < (unsigned long)src) { /* * Copy forward. */ t = (int)src; /* only need low bits */ if ((t | (int)dst) & wmask) { /* * Try to align operands. This cannot be done * unless the low bits match. */ if ((t ^ (int)dst) & wmask || length < wsize) { t = length; } else { t = wsize - (t & wmask); } length -= t; TLOOP1(*dst++ = *src++); } /* * Copy whole words, then mop up any trailing bytes. */ t = length / wsize; TLOOP(*(word *)dst = *(const word *)src; src += wsize; dst += wsize); t = length & wmask; TLOOP(*dst++ = *src++); } else { /* * Copy backwards. Otherwise essentially the same. * Alignment works as before, except that it takes * (t&wmask) bytes to align, not wsize-(t&wmask). */ src += length; dst += length; t = (int)src; if ((t | (int)dst) & wmask) { if ((t ^ (int)dst) & wmask || length <= wsize) { t = length; } else { t &= wmask; } length -= t; TLOOP1(*--dst = *--src); } t = length / wsize; TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(const word *)src); t = length & wmask; TLOOP(*--dst = *--src); } done: return (dst0); } tboot-1.10.5/tboot/common/memlog.c0000644000000000000000000001432414210363175015124 0ustar 00000000000000/* * memlog.h: log messages to memory * * Copyright (c) 2006-2020, Intel Corporation * 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 Intel Corporation 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 OWNER 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. */ #include #include #include #include #include #include #include #include #include /* memory-based serial log (ensure in .data section so that not cleared) */ __data tboot_log_t *g_log = NULL; void memlog_init(void) { if ( g_log == NULL ) { g_log = (tboot_log_t *)TBOOT_SERIAL_LOG_ADDR; uuid_t uuid = (uuid_t)TBOOT_LOG_UUID; tb_memcpy((void *) &g_log->uuid, (const void *) &uuid, sizeof(uuid_t)); g_log->curr_pos = 0; g_log->zip_count = 0; for ( uint8_t i = 0; i < ZIP_COUNT_MAX; i++ ) g_log->zip_pos[i] = 0; for ( uint8_t i = 0; i < ZIP_COUNT_MAX; i++ ) g_log->zip_size[i] = 0; } /* initialize these post-launch as well, since bad/malicious values */ /* could compromise environment */ g_log = (tboot_log_t *)TBOOT_SERIAL_LOG_ADDR; g_log->max_size = TBOOT_SERIAL_LOG_SIZE - sizeof(*g_log); /* if we're calling this post-launch, verify that curr_pos is valid */ if ( g_log->zip_pos[g_log->zip_count] > g_log->max_size && g_log != NULL ){ g_log->curr_pos = 0; uint8_t zero = 0; tb_memcpy((void *) &g_log->uuid, (const void *) &zero, sizeof(uint8_t)); for ( uint8_t i = 0; i < ZIP_COUNT_MAX; i++ ) g_log->zip_pos[i] = 0; for ( uint8_t i = 0; i < ZIP_COUNT_MAX; i++ ) g_log->zip_size[i] = 0; } if ( g_log->curr_pos > g_log->max_size ) g_log->curr_pos = g_log->zip_pos[g_log->zip_count]; } void memlog_write(const char *str, unsigned int count) { if ( g_log == NULL || count > g_log->max_size ) { return; } /* Check if there is space for the new string and a null terminator */ if (g_log->curr_pos + count + 1> g_log->max_size) { memlog_compress(count); } tb_memcpy(&g_log->buf[g_log->curr_pos], str, count); g_log->curr_pos += count; /* if the string wasn't NULL-terminated, then NULL-terminate the log */ if ( str[count-1] != '\0' ) g_log->buf[g_log->curr_pos] = '\0'; else { /* so that curr_pos will point to the NULL and be overwritten */ /* on next copy */ g_log->curr_pos--; } } void memlog_compress(uint32_t required_space) { /* allocate a 32K temp buffer for compressed log */ static char buf[32*1024]; char *out=buf; int zip_size; uint32_t zip_pos; bool log_reset_flag; if (required_space == 0 && g_log->curr_pos < g_log->max_size / 2) { /* Flush was requested, but we have over half buffer free, skip it */ return; } /* If there are space issues, only then log will be reset */ log_reset_flag = false; /* Check if there is space to add another compressed chunk */ if(g_log->zip_count >= ZIP_COUNT_MAX) log_reset_flag = true; else{ /* Get the start position of the new compressed chunk */ zip_pos = g_log->zip_pos[g_log->zip_count]; /* Compress the last part of the log buffer that is not compressed, and put the compressed output in out (buf) */ zip_size = LZ_Compress(&g_log->buf[zip_pos], out, (g_log->curr_pos - zip_pos), sizeof(buf) ); /* Check if buf was large enough for LZ_compress to succeed */ if( zip_size < 0 ) log_reset_flag = true; else{ /* Check if there is space to add the compressed string, the new string and a null terminator to the log */ if( (zip_pos + zip_size + required_space + 1) > g_log->max_size ) log_reset_flag = true; else{ /* Add the new compressed chunk to the log buffer, over-writing the last part of the log that was just compressed */ tb_memcpy(&g_log->buf[zip_pos], out, zip_size); g_log->zip_size[g_log->zip_count] = zip_size; g_log->zip_count++; g_log->curr_pos = zip_pos + zip_size; /* Set a NULL ending */ g_log->buf[g_log->curr_pos] ='\0'; /* Only if there is space to add another compressed chunk, prepare its start position. */ if( g_log->zip_count < ZIP_COUNT_MAX ) g_log->zip_pos[g_log->zip_count] = g_log->curr_pos; } } } /* There was some space-shortage problem. Reset the log. */ if ( log_reset_flag ){ g_log->curr_pos = 0; for( uint8_t i = 0; i < ZIP_COUNT_MAX; i++ ) g_log->zip_pos[i] = 0; for( uint8_t i = 0; i < ZIP_COUNT_MAX; i++ ) g_log->zip_size[i] = 0; g_log->zip_count = 0; } }tboot-1.10.5/tboot/common/misc.c0000644000000000000000000002340314210363175014575 0ustar 00000000000000/* * misc.c: miscellaneous support fns * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include /* * if 'prefix' != NULL, print it before each line of hex string */ void print_hex(const char *prefix, const void *prtptr, size_t size) { for ( size_t i = 0; i < size; i++ ) { if ( i % 16 == 0 && prefix != NULL ) printk(TBOOT_DETA"\n%s", prefix); printk(TBOOT_DETA"%02x ", *(uint8_t *)prtptr++); } printk(TBOOT_DETA"\n"); } static bool g_calibrated = false; static uint64_t g_ticks_per_millisec; #define TIMER_FREQ 1193182 #define TIMER_DIV(hz) ((TIMER_FREQ+(hz)/2)/(hz)) static void wait_tsc_uip(void) { do { outb(0x43, 0xe8); cpu_relax(); } while ( !(inb(0x42) & 0x80) ); do { outb(0x43, 0xe8); cpu_relax(); } while ( inb(0x42) & 0x80 ); } static void calibrate_tsc(void) { if ( g_calibrated ) return; /* disable speeker */ uint8_t val = inb(0x61); val = ((val & ~0x2) | 0x1); outb(0x61, val); /* 0xb6 - counter2, low then high byte write */ /* mode 3, binary */ outb(0x43, 0xb6); /* 0x4a9 - divisor to get 1ms period time */ /* 1.19318 MHz / 1193 = 1000.15Hz */ uint16_t latch = TIMER_DIV(1000); outb(0x42, latch & 0xff); outb(0x42, latch >> 8); /* 0xe8 - read back command, don't get count */ /* get status, counter2 select */ do { outb(0x43, 0xe8); cpu_relax(); } while ( inb(0x42) & 0x40 ); wait_tsc_uip(); /* get starting TSC val */ uint64_t start = rdtsc(); wait_tsc_uip(); uint64_t end = rdtsc(); /* # ticks in 1 millisecond */ g_ticks_per_millisec = end - start; /* restore timer 1 programming */ outb(0x43, 0x54); outb(0x41, 0x12); g_calibrated = true; } void delay(int millisecs) { if ( millisecs <= 0 ) return; calibrate_tsc(); uint64_t rtc = rdtsc(); uint64_t end_ticks = rtc + millisecs * g_ticks_per_millisec; while ( rtc < end_ticks ) { cpu_relax(); rtc = rdtsc(); } } /* used by isXXX() in ctype.h */ /* originally from: * http://fxr.watson.org/fxr/source/dist/acpica/utclib.c?v=NETBSD5 * re-licensed by Intel Corporation */ const uint8_t _ctype[257] = { _CN, /* 0x0 0. */ _CN, /* 0x1 1. */ _CN, /* 0x2 2. */ _CN, /* 0x3 3. */ _CN, /* 0x4 4. */ _CN, /* 0x5 5. */ _CN, /* 0x6 6. */ _CN, /* 0x7 7. */ _CN, /* 0x8 8. */ _CN|_SP, /* 0x9 9. */ _CN|_SP, /* 0xA 10. */ _CN|_SP, /* 0xB 11. */ _CN|_SP, /* 0xC 12. */ _CN|_SP, /* 0xD 13. */ _CN, /* 0xE 14. */ _CN, /* 0xF 15. */ _CN, /* 0x10 16. */ _CN, /* 0x11 17. */ _CN, /* 0x12 18. */ _CN, /* 0x13 19. */ _CN, /* 0x14 20. */ _CN, /* 0x15 21. */ _CN, /* 0x16 22. */ _CN, /* 0x17 23. */ _CN, /* 0x18 24. */ _CN, /* 0x19 25. */ _CN, /* 0x1A 26. */ _CN, /* 0x1B 27. */ _CN, /* 0x1C 28. */ _CN, /* 0x1D 29. */ _CN, /* 0x1E 30. */ _CN, /* 0x1F 31. */ _XS|_SP, /* 0x20 32. ' ' */ _PU, /* 0x21 33. '!' */ _PU, /* 0x22 34. '"' */ _PU, /* 0x23 35. '#' */ _PU, /* 0x24 36. '$' */ _PU, /* 0x25 37. '%' */ _PU, /* 0x26 38. '&' */ _PU, /* 0x27 39. ''' */ _PU, /* 0x28 40. '(' */ _PU, /* 0x29 41. ')' */ _PU, /* 0x2A 42. '*' */ _PU, /* 0x2B 43. '+' */ _PU, /* 0x2C 44. ',' */ _PU, /* 0x2D 45. '-' */ _PU, /* 0x2E 46. '.' */ _PU, /* 0x2F 47. '/' */ _XD|_DI, /* 0x30 48. '' */ _XD|_DI, /* 0x31 49. '1' */ _XD|_DI, /* 0x32 50. '2' */ _XD|_DI, /* 0x33 51. '3' */ _XD|_DI, /* 0x34 52. '4' */ _XD|_DI, /* 0x35 53. '5' */ _XD|_DI, /* 0x36 54. '6' */ _XD|_DI, /* 0x37 55. '7' */ _XD|_DI, /* 0x38 56. '8' */ _XD|_DI, /* 0x39 57. '9' */ _PU, /* 0x3A 58. ':' */ _PU, /* 0x3B 59. ';' */ _PU, /* 0x3C 60. '<' */ _PU, /* 0x3D 61. '=' */ _PU, /* 0x3E 62. '>' */ _PU, /* 0x3F 63. '?' */ _PU, /* 0x40 64. '@' */ _XD|_UP, /* 0x41 65. 'A' */ _XD|_UP, /* 0x42 66. 'B' */ _XD|_UP, /* 0x43 67. 'C' */ _XD|_UP, /* 0x44 68. 'D' */ _XD|_UP, /* 0x45 69. 'E' */ _XD|_UP, /* 0x46 70. 'F' */ _UP, /* 0x47 71. 'G' */ _UP, /* 0x48 72. 'H' */ _UP, /* 0x49 73. 'I' */ _UP, /* 0x4A 74. 'J' */ _UP, /* 0x4B 75. 'K' */ _UP, /* 0x4C 76. 'L' */ _UP, /* 0x4D 77. 'M' */ _UP, /* 0x4E 78. 'N' */ _UP, /* 0x4F 79. 'O' */ _UP, /* 0x50 80. 'P' */ _UP, /* 0x51 81. 'Q' */ _UP, /* 0x52 82. 'R' */ _UP, /* 0x53 83. 'S' */ _UP, /* 0x54 84. 'T' */ _UP, /* 0x55 85. 'U' */ _UP, /* 0x56 86. 'V' */ _UP, /* 0x57 87. 'W' */ _UP, /* 0x58 88. 'X' */ _UP, /* 0x59 89. 'Y' */ _UP, /* 0x5A 90. 'Z' */ _PU, /* 0x5B 91. '[' */ _PU, /* 0x5C 92. '\' */ _PU, /* 0x5D 93. ']' */ _PU, /* 0x5E 94. '^' */ _PU, /* 0x5F 95. '_' */ _PU, /* 0x60 96. '`' */ _XD|_LO, /* 0x61 97. 'a' */ _XD|_LO, /* 0x62 98. 'b' */ _XD|_LO, /* 0x63 99. 'c' */ _XD|_LO, /* 0x64 100. 'd' */ _XD|_LO, /* 0x65 101. 'e' */ _XD|_LO, /* 0x66 102. 'f' */ _LO, /* 0x67 103. 'g' */ _LO, /* 0x68 104. 'h' */ _LO, /* 0x69 105. 'i' */ _LO, /* 0x6A 106. 'j' */ _LO, /* 0x6B 107. 'k' */ _LO, /* 0x6C 108. 'l' */ _LO, /* 0x6D 109. 'm' */ _LO, /* 0x6E 110. 'n' */ _LO, /* 0x6F 111. 'o' */ _LO, /* 0x70 112. 'p' */ _LO, /* 0x71 113. 'q' */ _LO, /* 0x72 114. 'r' */ _LO, /* 0x73 115. 's' */ _LO, /* 0x74 116. 't' */ _LO, /* 0x75 117. 'u' */ _LO, /* 0x76 118. 'v' */ _LO, /* 0x77 119. 'w' */ _LO, /* 0x78 120. 'x' */ _LO, /* 0x79 121. 'y' */ _LO, /* 0x7A 122. 'z' */ _PU, /* 0x7B 123. '{' */ _PU, /* 0x7C 124. '|' */ _PU, /* 0x7D 125. '}' */ _PU, /* 0x7E 126. '~' */ _CN, /* 0x7F 127. */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 to 0x8F */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90 to 0x9F */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xA0 to 0xAF */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xB0 to 0xBF */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xC0 to 0xCF */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xD0 to 0xDF */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xE0 to 0xEF */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xF0 to 0x100 */ }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/mutex.S0000644000000000000000000000372114210363175014765 0ustar 00000000000000/* $OpenBSD: mutex.S,v 1.6 2009/04/27 21:48:56 kettenis Exp $ */ /* * Copyright (c) 2004 Artur Grabowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Portions copyright (c) 2010, Intel Corporation */ #include .code32 /* stack offset of mutex pointer parameter */ #define SOFF 8 ENTRY(mtx_init) pushl %ebp movl %esp, %ebp movl SOFF(%ebp), %eax xorl %edx, %edx movl %edx, (%eax) leave ret ENTRY(mtx_enter) pushl %ebp movl %esp, %ebp 1: movl SOFF(%ebp), %ecx /* * %ecx contains the mtx. */ movl $1, %eax xchgl %eax, (%ecx) # test_and_set(mtx->mtx_lock) testl %eax, %eax # if (already held) jnz 2f leave ret 2: pause movl (%ecx), %eax testl %eax, %eax jz 1b jmp 2b ENTRY(mtx_leave) pushl %ebp movl %esp, %ebp movl SOFF(%ebp), %ecx xorl %eax, %eax movl %eax, (%ecx) leave ret tboot-1.10.5/tboot/common/paging.c0000644000000000000000000001605614210363175015115 0ustar 00000000000000/* * paging.c: enable PAE paging and map pages in tboot * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include /* Page-Directory-Pointer Table */ uint64_t __attribute__ ((__section__ (".bss.page_aligned"))) pdptr_table[TB_L2_PAGETABLE_ENTRIES]; /* Page Directory */ uint64_t __attribute__ ((__section__ (".bss.page_aligned"))) pd_table[4*TB_L1_PAGETABLE_ENTRIES]; extern char _start[]; extern char _end[]; extern void apply_policy(tb_error_t error); static uint64_t *get_pdptre(unsigned long virt) { return pdptr_table + pdptr_table_offset(virt); } /* get the Page-Directory Entry according to the virtual address */ static uint64_t *get_pde(unsigned long virt) { unsigned long pdptr_tab_offset; uint64_t *ppde, *ppdptre; uint64_t *p; ppdptre = get_pdptre(virt); if ( !(get_pdptre_flags(*ppdptre) & _PAGE_PRESENT) ) { /* If not present, create Page Directory */ pdptr_tab_offset = pdptr_table_offset(virt); p = pd_table + pdptr_tab_offset * TB_L1_PAGETABLE_ENTRIES; tb_memset(p, 0, sizeof(uint64_t) * TB_L1_PAGETABLE_ENTRIES); *ppdptre = MAKE_TB_PDPTE((unsigned long)p); } ppde = (uint64_t *)(unsigned long)get_pdptre_paddr(*ppdptre); ppde += pd_table_offset(virt); return ppde; } static inline void flush_tlb(void) { write_cr3(read_cr3()); } /* * map 2-Mbyte pages to tboot: * tboot pages are mapped into DIRECTMAP_VIRT_START ~ DIRECTMAP_VIRT_END; * other pages for MACing are mapped into MAC_VIRT_START ~ MAC_VIRT_END. */ void map_pages_to_tboot(unsigned long vstart, unsigned long pfn, unsigned long nr_pfns) { uint64_t start, end; uint64_t *ppde; start = (uint64_t)pfn << TB_L1_PAGETABLE_SHIFT; end = (uint64_t)(pfn + nr_pfns) << TB_L1_PAGETABLE_SHIFT; do { ppde = get_pde(vstart); *ppde = MAKE_TB_PDE(start); start += MAC_PAGE_SIZE; vstart += MAC_PAGE_SIZE; } while ( start < end ); flush_tlb(); } /* map tboot pages into tboot */ static void map_tboot_pages(unsigned long pfn, unsigned long nr_pfns) { uint64_t start, end; start = (uint64_t)pfn << TB_L1_PAGETABLE_SHIFT; end = (uint64_t)(pfn + nr_pfns) << TB_L1_PAGETABLE_SHIFT; /* older gcc versions don't understand '#pragma GCC diagnostic ignored' and thus won't disable the 'unsinged comparison against 0' warning, so assert that DIRECTMAP_VIRT_START == 0 and then we don't need to compare 'start >= DIRECTMAP_VIRT_START' */ COMPILE_TIME_ASSERT(DIRECTMAP_VIRT_START == 0); if ( end > DIRECTMAP_VIRT_END ) { printk(TBOOT_ERR"0x%llx ~ 0x%llx cannot be mapped as direct map\n", start, end); disable_paging(); apply_policy(TB_ERR_FATAL); } map_pages_to_tboot(start, pfn, nr_pfns); } /* destroy the map */ void destroy_tboot_mapping(unsigned long vstart, unsigned long vend) { unsigned long virt; uint64_t *ppdptre, *ppde; if (((vstart & ~MAC_PAGE_MASK) == 0 ) || ((vend & ~MAC_PAGE_MASK) == 0 )) return; virt = vstart; while ( virt < vend ) { ppdptre = get_pdptre(virt); if ( !(get_pdptre_flags(*ppdptre) & _PAGE_PRESENT) ) { virt += 1UL << TB_L2_PAGETABLE_SHIFT; virt &= ~((1UL << TB_L2_PAGETABLE_SHIFT) - 1); continue; } ppde = get_pde(virt); if ( get_pde_flags(*ppde) & _PAGE_PRESENT ) *ppde = 0; virt += MAC_PAGE_SIZE; virt &= MAC_PAGE_MASK; } flush_tlb(); } static unsigned long build_directmap_pagetable(void) { unsigned int i; uint64_t *ppdptre; unsigned long tboot_spfn, tboot_epfn; tb_memset(pdptr_table, 0, sizeof(pdptr_table)); tb_memset(pd_table, 0, sizeof(pd_table)); for ( i = 0; i < ARRAY_SIZE(pd_table)/TB_L1_PAGETABLE_ENTRIES; i++ ) { ppdptre = &pdptr_table[i]; *ppdptre = MAKE_TB_PDPTE((unsigned long)( pd_table + i * TB_L1_PAGETABLE_ENTRIES)); } /* map serial log address ~ kernel command address */ tboot_spfn = (unsigned long)TBOOT_SERIAL_LOG_ADDR >> TB_L1_PAGETABLE_SHIFT; tboot_epfn = ((unsigned long)(TBOOT_KERNEL_CMDLINE_ADDR + TBOOT_KERNEL_CMDLINE_SIZE + MAC_PAGE_SIZE - 1)) >> TB_L1_PAGETABLE_SHIFT; map_tboot_pages(tboot_spfn, tboot_epfn - tboot_spfn); /* map tboot */ tboot_spfn = (unsigned long)&_start >> TB_L1_PAGETABLE_SHIFT; tboot_epfn = ((unsigned long)&_end + MAC_PAGE_SIZE - 1) >> TB_L1_PAGETABLE_SHIFT; map_tboot_pages(tboot_spfn, tboot_epfn - tboot_spfn); return (unsigned long)pdptr_table; } static unsigned long cr0, cr4; bool enable_paging(void) { unsigned long eflags; /* disable interrupts */ eflags = read_eflags(); disable_intr(); /* flush caches */ wbinvd(); /* save old cr0 & cr4 */ cr0 = read_cr0(); cr4 = read_cr4(); write_cr4((cr4 | CR4_PAE | CR4_PSE) & ~CR4_PGE); write_cr3(build_directmap_pagetable()); write_cr0(cr0 | CR0_PG); /* enable interrupts */ write_eflags(eflags); return (read_cr0() & CR0_PG); } bool disable_paging(void) { /* restore cr0 & cr4 */ write_cr0(cr0); write_cr4(cr4); return !(read_cr0() & CR0_PG); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/pci_cfgreg.c0000644000000000000000000001012014210363175015722 0ustar 00000000000000/* * Copyright (c) 1997, Stefan Esser * Copyright (c) 2000, Michael Smith * Copyright (c) 2000, BSDi * Copyright (c) 2004, Scott Long * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* from: * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.134.2.2.2.1 2010/06/14 02:09:06 kensmith Exp $ */ /* * Portions copyright (c) 2010, Intel Corporation */ #include #include #include #include enum { CFGMECH_NONE = 0, CFGMECH_1, CFGMECH_2, CFGMECH_PCIE, }; struct mutex pcicfg_mtx; static const int cfgmech = CFGMECH_1; /* * Configuration space access using direct register operations */ /* enable configuration space accesses and return data port address */ static int pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) { int dataport = 0; if (bus <= PCI_BUSMAX && slot <= PCI_SLOTMAX && func <= PCI_FUNCMAX && (unsigned)reg <= PCI_REGMAX && bytes != 3 && (unsigned)bytes <= 4 && (reg & (bytes - 1)) == 0) { switch (cfgmech) { case CFGMECH_PCIE: case CFGMECH_1: outl(CONF1_ADDR_PORT, (1 << 31) | (bus << 16) | (slot << 11) | (func << 8) | (reg & ~0x03)); dataport = CONF1_DATA_PORT + (reg & 0x03); break; case CFGMECH_2: outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); outb(CONF2_FORWARD_PORT, bus); dataport = 0xc000 | (slot << 8) | reg; break; default: break; } } return (dataport); } /* disable configuration space accesses */ static void pci_cfgdisable(void) { switch (cfgmech) { case CFGMECH_PCIE: case CFGMECH_1: /* * Do nothing for the config mechanism 1 case. * Writing a 0 to the address port can apparently * confuse some bridges and cause spurious * access failures. */ break; case CFGMECH_2: outb(CONF2_ENABLE_PORT, 0); break; default: break; } } int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes) { int data = -1; int port; mtx_enter(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { switch (bytes) { case 1: data = inb(port); break; case 2: data = inw(port); break; case 4: data = inl(port); break; default: break; } pci_cfgdisable(); } mtx_leave(&pcicfg_mtx); return (data); } void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes) { int port; mtx_enter(&pcicfg_mtx); port = pci_cfgenable(bus, slot, func, reg, bytes); if (port != 0) { switch (bytes) { case 1: outb(port, data); break; case 2: outw(port, data); break; case 4: outl(port, data); break; default: break; } pci_cfgdisable(); } mtx_leave(&pcicfg_mtx); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/policy.c0000644000000000000000000010335614210363175015147 0ustar 00000000000000/* * policy.c: support functions for tboot verification launch * * Copyright (c) 2006-2014, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PRINT printk #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAJOR_VER(v) ((v) >> 8) extern void shutdown(void); extern void s3_launch(void); /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; extern long s3_flag; /* * policy actions */ typedef enum { TB_POLACT_CONTINUE, TB_POLACT_UNMEASURED_LAUNCH, TB_POLACT_HALT, } tb_policy_action_t; /* policy map types */ typedef struct { tb_error_t error; tb_policy_action_t action; } tb_policy_map_entry_t; typedef struct { uint8_t policy_type; tb_policy_action_t default_action; tb_policy_map_entry_t exception_action_table[TB_ERR_MAX]; /* have TB_ERR_NONE as last entry */ } tb_policy_map_t; /* map */ static const tb_policy_map_t g_policy_map[] = { { TB_POLTYPE_CONT_NON_FATAL, TB_POLACT_CONTINUE, { {TB_ERR_FATAL, TB_POLACT_HALT}, {TB_ERR_PREV_TXT_ERROR, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_TPM_NOT_READY, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_SMX_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_VMX_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_VTD_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_TXT_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_SINIT_NOT_PRESENT, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_ACMOD_VERIFY_FAILED, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_NONE, TB_POLACT_CONTINUE}, } }, { TB_POLTYPE_CONT_VERIFY_FAIL, TB_POLACT_HALT, { {TB_ERR_MODULE_VERIFICATION_FAILED, TB_POLACT_CONTINUE}, {TB_ERR_NV_VERIFICATION_FAILED, TB_POLACT_CONTINUE}, {TB_ERR_POLICY_NOT_PRESENT, TB_POLACT_CONTINUE}, {TB_ERR_POLICY_INVALID, TB_POLACT_CONTINUE}, {TB_ERR_NONE, TB_POLACT_CONTINUE}, } }, { TB_POLTYPE_HALT, TB_POLACT_HALT, { {TB_ERR_NONE, TB_POLACT_CONTINUE}, } }, }; /* buffer for policy as read from TPM NV */ #define MAX_POLICY_SIZE \ (( MAX_TB_POLICY_SIZE > sizeof(lcp_policy_t) ) \ ? MAX_TB_POLICY_SIZE \ : sizeof(lcp_policy_t) ) static uint8_t _policy_index_buf[MAX_POLICY_SIZE]; /* default policy */ static const tb_policy_t _def_policy = { version : 2, policy_type : TB_POLTYPE_CONT_NON_FATAL, hash_alg : TB_HALG_SHA256, policy_control : TB_POLCTL_EXTEND_PCR17, num_entries : 3, entries : { { /* mod 0 is extended to PCR 18 by default, so don't re-extend it */ mod_num : 0, pcr : TB_POL_PCR_NONE, hash_type : TB_HTYPE_ANY, num_hashes : 0 }, { /* all other modules are extended to PCR 19 */ mod_num : TB_POL_MOD_NUM_ANY, pcr : 19, hash_type : TB_HTYPE_ANY, num_hashes : 0 }, { /* NV index for geo-tagging will be extended to PCR 22 */ mod_num : TB_POL_MOD_NUM_NV_RAW, pcr : 22, hash_type : TB_HTYPE_ANY, nv_index : 0x40000010, num_hashes : 0 } } }; /* default policy for TPM 1.2 */ static const tb_policy_t _def_policy_12 = { version : 2, policy_type : TB_POLTYPE_CONT_NON_FATAL, hash_alg : TB_HALG_SHA1, policy_control : TB_POLCTL_EXTEND_PCR17, num_entries : 3, entries : { { /* mod 0 is extended to PCR 18 by default, so don't re-extend it */ mod_num : 0, pcr : TB_POL_PCR_NONE, hash_type : TB_HTYPE_ANY, num_hashes : 0 }, { /* all other modules are extended to PCR 19 */ mod_num : TB_POL_MOD_NUM_ANY, pcr : 19, hash_type : TB_HTYPE_ANY, num_hashes : 0 }, { /* NV index for geo-tagging will be extended to PCR 22 */ mod_num : TB_POL_MOD_NUM_NV_RAW, pcr : 22, hash_type : TB_HTYPE_ANY, nv_index : 0x40000010, num_hashes : 0 } } }; /* default policy for Details/Authorities pcr mapping */ static const tb_policy_t _def_policy_da = { version : 2, policy_type : TB_POLTYPE_CONT_NON_FATAL, hash_alg : TB_HALG_SHA256, policy_control : TB_POLCTL_EXTEND_PCR17, num_entries : 3, entries : { { /* mod 0 is extended to PCR 17 by default, so don't re-extend it */ mod_num : 0, pcr : TB_POL_PCR_NONE, hash_type : TB_HTYPE_ANY, num_hashes : 0 }, { /* all other modules are extended to PCR 17 */ mod_num : TB_POL_MOD_NUM_ANY, pcr : 17, hash_type : TB_HTYPE_ANY, num_hashes : 0 }, { /* NV index for geo-tagging will be extended to PCR 22 */ mod_num : TB_POL_MOD_NUM_NV_RAW, pcr : 22, hash_type : TB_HTYPE_ANY, nv_index : 0x40000010, num_hashes : 0 } } }; /* current policy */ static const tb_policy_t* g_policy = &_def_policy; /* * read_policy_from_tpm * * read policy from TPM NV into buffer * * policy_index_size is in/out */ static bool read_policy_from_tpm(uint32_t index, void* policy_index, size_t *policy_index_size) { #define NV_READ_SEG_SIZE 256 unsigned int offset = 0; unsigned int data_size = 0; uint32_t ret, index_size; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); if ( policy_index_size == NULL ) { printk(TBOOT_ERR"size is NULL\n"); return false; } ret = tpm_fp->get_nvindex_size(tpm, tpm->cur_loc, index, &index_size); if ( !ret ) return false; if ( index_size > *policy_index_size ) { printk(TBOOT_WARN"policy in TPM NV %x was too big for buffer\n", index); index_size = *policy_index_size; } do { /* get data_size */ if ( (index_size - offset) > NV_READ_SEG_SIZE ) data_size = NV_READ_SEG_SIZE; else data_size = (uint32_t)(index_size - offset); /* read! */ ret = tpm_fp->nv_read(tpm, tpm->cur_loc, index, offset, (uint8_t *)policy_index + offset, &data_size); if ( !ret || data_size == 0 ) break; /* adjust offset */ offset += data_size; } while ( offset < index_size ); if ( offset == 0 && !ret ) { printk(TBOOT_ERR"Error: read TPM error: 0x%x from index %x.\n", ret, index); return false; } *policy_index_size = offset; return true; } bool check_index_attribute(uint32_t index) { uint32_t attribute; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); if ( !tpm_fp->get_nvindex_permission(tpm, 0, index, &attribute) ) { printk(TBOOT_ERR"\treading nv index permission failed\n"); return false; } if (attribute & TPM_NV_PER_PPWRITE) { printk(TBOOT_ERR"\tnv index should not be TPMA_NV_PPWRITE\n"); return false; } return true; } /* * unwrap_lcp_policy * * unwrap custom element in lcp policy into tb policy * assume sinit has already verified lcp policy and lcp policy data. */ static bool unwrap_lcp_policy(void) { void* lcp_base; lcp_policy_element_t *elt; uint32_t lcp_size; uint16_t list_ver; // scaffolding printk(TBOOT_INFO"in unwrap_lcp_policy\n"); if ( txt_is_launched() ) { txt_heap_t *txt_heap = get_txt_heap(); os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap); lcp_base = (void *)(unsigned long)os_sinit_data->lcp_po_base; lcp_size = (uint32_t)os_sinit_data->lcp_po_size; } else { extern loader_ctx *g_ldr_ctx; if ( !find_lcp_module(g_ldr_ctx, &lcp_base, &lcp_size) ) return false; } /* if lcp policy data version is 2+ */ if ( tb_memcmp((void *)lcp_base, LCP_POLICY_DATA_FILE_SIGNATURE, LCP_FILE_SIG_LENGTH) == 0 ) { uint32_t elts_size; uint32_t all_elt_size; //Value from lcp list PolicyElementsSize field lcp_policy_data_t2 *poldata = (lcp_policy_data_t2 *)lcp_base; lcp_list_t *pollist = &poldata->policy_lists[0]; //Read list version tb_memcpy((void*)&list_ver, (const void *)pollist, sizeof(uint16_t)); for ( int i = 0; i < poldata->num_lists; i++ ) { if (MAJOR_VER(list_ver) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION)) { elt = pollist->tpm12_policy_list.policy_elements; elts_size = 0; all_elt_size = pollist->tpm12_policy_list.policy_elements_size; } else if (MAJOR_VER(list_ver) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION)) { elt = pollist->tpm20_policy_list.policy_elements; elts_size = 0; all_elt_size = pollist->tpm20_policy_list.policy_elements_size; } else if (MAJOR_VER(list_ver) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300)) { elt = pollist->tpm20_policy_list_2_1.PolicyElements; elts_size = 0; all_elt_size = pollist->tpm20_policy_list_2_1.PolicyElementsSize; } else { printk(TBOOT_ERR"Error: Policy list version not recognized: 0x%x.\n", list_ver); return false; } while ( elt ) { /* check element type */ if ( elt->type == LCP_POLELT_TYPE_CUSTOM || elt->type == LCP_POLELT_TYPE_CUSTOM2 ) { lcp_custom_element_t *custom = (lcp_custom_element_t *)&elt->data; /* check uuid in custom element */ if ( are_uuids_equal(&custom->uuid, &((uuid_t)LCP_CUSTOM_ELEMENT_TBOOT_UUID)) ) { tb_memcpy(_policy_index_buf, &custom->data, elt->size - sizeof(*elt) - sizeof(uuid_t)); return true; /* find tb policy */ } } elts_size += elt->size; if ( elts_size >= all_elt_size ) break; elt = (void *)elt + elt->size; } //If necessary go to next list. if ( MAJOR_VER(list_ver) == MAJOR_VER(LCP_TPM12_POLICY_LIST_VERSION)) { pollist = (void *)pollist + get_tpm12_policy_list_size((lcp_policy_list_t *)pollist); } else if ( MAJOR_VER(list_ver) == MAJOR_VER(LCP_TPM20_POLICY_LIST_VERSION)) { pollist = (void *)pollist + get_tpm20_policy_list_size((lcp_policy_list_t2 *)pollist); } else if ( MAJOR_VER(list_ver) == MAJOR_VER(LCP_TPM20_POLICY_LIST2_1_VERSION_300) ){ pollist = (void *)pollist + get_raw_tpm20_list_2_1_size(&pollist->tpm20_policy_list_2_1); } } } return false; } /* * set_policy * * load policy from TPM NV and validate it, else use default * */ tb_error_t set_policy(void) { const struct tpm_if *tpm = get_tpm(); /* try to read tboot policy from TB_POLICY_INDEX in TPM NV */ size_t policy_index_size = sizeof(_policy_index_buf); printk(TBOOT_INFO"reading Verified Launch Policy from TPM NV...\n"); if (read_policy_from_tpm(tpm->tb_policy_index, _policy_index_buf, &policy_index_size) && check_index_attribute(tpm->tb_policy_index)) { printk(TBOOT_DETA"\t:%lu bytes read\n", policy_index_size); if ( verify_policy((tb_policy_t *)_policy_index_buf, policy_index_size, true) ) { goto policy_found; } } printk(TBOOT_WARN"\t:reading failed\n"); /* tboot policy not found in TB_POLICY_INDEX, so see if it is wrapped * in a custom element in the PO policy; if so, SINIT will have verified * the policy and policy data for us; we just need to ensure the policy * type is LCP_POLTYPE_LIST (since we could have been give a policy data * file even though the policy was not a LIST */ printk(TBOOT_INFO"reading Launch Control Policy from TPM NV...\n"); if (read_policy_from_tpm(tpm->lcp_own_index, _policy_index_buf, &policy_index_size) && check_index_attribute(tpm->lcp_own_index)) { printk(TBOOT_DETA"\t:%lu bytes read\n", policy_index_size); /* assume lcp policy has been verified by sinit already */ lcp_policy_t *pol = (lcp_policy_t *)_policy_index_buf; if ( MAJOR_VER(pol->version) == MAJOR_VER(LCP_DEFAULT_POLICY_VERSION_2) && pol->policy_type == LCP_POLTYPE_LIST && unwrap_lcp_policy() ) { if ( verify_policy((tb_policy_t *)_policy_index_buf, calc_policy_size((tb_policy_t *)_policy_index_buf), true) ) goto policy_found; } lcp_policy_t2 *pol2 = (lcp_policy_t2 *)_policy_index_buf; /*Only check if major version is 3, minor is checked by sinit*/ if ( MAJOR_VER(pol2->version) == MAJOR_VER(LCP_DEFAULT_POLICY_VERSION) && pol2->policy_type == LCP_POLTYPE_LIST && unwrap_lcp_policy() ) { if ( verify_policy((tb_policy_t *)_policy_index_buf, calc_policy_size((tb_policy_t *)_policy_index_buf), true) ) goto policy_found; } } printk(TBOOT_WARN"\t:reading failed\n"); /* either no policy in TPM NV or policy is invalid, so use default */ printk(TBOOT_WARN"failed to read policy from TPM NV, using default\n"); if (g_tpm_ver == TPM_VER_12) { g_policy = &_def_policy_12; } else { g_policy = g_using_da ? &_def_policy_da : &_def_policy; } policy_index_size = calc_policy_size(g_policy); /* sanity check; but if it fails something is really wrong */ if ( !verify_policy(g_policy, policy_index_size, true) ) return TB_ERR_FATAL; else return TB_ERR_POLICY_NOT_PRESENT; policy_found: /* compatible with tb_policy tools for TPM 1.2 */ { tb_policy_t *tmp_policy = (tb_policy_t *)_policy_index_buf; if (tmp_policy->hash_alg == 0) tmp_policy->hash_alg = TB_HALG_SHA1; } g_policy = (tb_policy_t *)_policy_index_buf; return TB_ERR_NONE; } /* hash current policy */ bool hash_policy(tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { printk(TBOOT_ERR"Error: input parameter is wrong.\n"); return false; } return hash_buffer((unsigned char *)g_policy, calc_policy_size(g_policy), hash, hash_alg); } /* generate hash by hashing cmdline and module image */ static bool hash_module(hash_list_t *hl, const char* cmdline, void *base, size_t size) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); if ( hl == NULL ) { printk(TBOOT_ERR"Error: input parameter is wrong.\n"); return false; } /* final hash is SHA-1( SHA-1(cmdline) | SHA-1(image) ) */ /* where cmdline is first stripped of leading spaces, file name, then */ /* any spaces until the next non-space char */ /* (e.g. " /foo/bar baz" -> "baz"; "/foo/bar" -> "") */ /* hash command line */ if ( cmdline == NULL ) cmdline = ""; // else // cmdline = skip_filename(cmdline); switch (tpm->extpol) { case TB_EXTPOL_FIXED: hl->count = 1; hl->entries[0].alg = tpm->cur_alg; if ( !hash_buffer((const unsigned char *)cmdline, tb_strlen(cmdline), &hl->entries[0].hash, tpm->cur_alg) ) return false; /* hash image and extend into cmdline hash */ tb_hash_t img_hash; if ( !hash_buffer(base, size, &img_hash, tpm->cur_alg) ) return false; if ( !extend_hash(&hl->entries[0].hash, &img_hash, tpm->cur_alg) ) return false; break; case TB_EXTPOL_AGILE: { hash_list_t img_hl, final_hl; if ( !tpm_fp->hash(tpm, 2, (const unsigned char *)cmdline, tb_strlen(cmdline), hl) ) return false; uint8_t buf[2*sizeof(tb_hash_t)]; if ( !tpm_fp->hash(tpm, 2, base, size, &img_hl) ) return false; for (unsigned int i=0; icount; i++) { for (unsigned int j=0; jentries[i].alg == img_hl.entries[j].alg) { copy_hash((tb_hash_t *)buf, &hl->entries[i].hash, hl->entries[i].alg); copy_hash((tb_hash_t *)(buf + get_hash_size(hl->entries[i].alg)), &img_hl.entries[j].hash, hl->entries[i].alg); if ( !tpm_fp->hash(tpm, 2, buf, 2*get_hash_size(hl->entries[i].alg), &final_hl) ) return false; for (unsigned int k=0; kentries[i].alg == final_hl.entries[k].alg) { copy_hash(&hl->entries[i].hash, &final_hl.entries[k].hash, hl->entries[i].alg); break; } } break; } } } break; } case TB_EXTPOL_EMBEDDED: { tb_hash_t img_hash; hl->count = tpm->alg_count; for (unsigned int i=0; icount; i++) { hl->entries[i].alg = tpm->algs[i]; if ( !hash_buffer((const unsigned char *)cmdline, tb_strlen(cmdline), &hl->entries[i].hash, tpm->algs[i]) ) return false; if ( !hash_buffer(base, size, &img_hash, tpm->algs[i]) ) return false; if ( !extend_hash(&hl->entries[i].hash, &img_hash, tpm->algs[i]) ) return false; } break; } default: return false; } return true; } static bool is_hash_in_policy_entry(const tb_policy_entry_t *pol_entry, tb_hash_t *hash, uint16_t hash_alg) { /* assumes policy entry has been validated */ if ( pol_entry == NULL || hash == NULL) { printk(TBOOT_ERR"Error: input parameter is wrong.\n"); return false; } if ( pol_entry->hash_type == TB_HTYPE_ANY ) return true; else if ( pol_entry->hash_type == TB_HTYPE_IMAGE ) { for ( int i = 0; i < pol_entry->num_hashes; i++ ) { if ( are_hashes_equal(get_policy_entry_hash(pol_entry, hash_alg, i), hash, hash_alg) ) return true; } } return false; } /* * map policy type + error -> action */ static tb_policy_action_t evaluate_error(tb_error_t error) { tb_policy_action_t action = TB_POLACT_HALT; if ( error == TB_ERR_NONE ) return TB_POLACT_CONTINUE; for ( unsigned int i = 0; i < ARRAY_SIZE(g_policy_map); i++ ) { if ( g_policy_map[i].policy_type == g_policy->policy_type ) { action = g_policy_map[i].default_action; for ( unsigned int j = 0; j < ARRAY_SIZE(g_policy_map[i].exception_action_table); j++ ) { if ( g_policy_map[i].exception_action_table[j].error == error ) action = g_policy_map[i].exception_action_table[j].action; if ( g_policy_map[i].exception_action_table[j].error == TB_ERR_NONE ) break; } } } return action; } /* * apply policy according to error happened. */ void apply_policy(tb_error_t error) { tb_policy_action_t action; /* save the error to TPM NV */ write_tb_error_code(error); if ( error != TB_ERR_NONE ) print_tb_error_msg(error); action = evaluate_error(error); switch ( action ) { case TB_POLACT_CONTINUE: return; case TB_POLACT_UNMEASURED_LAUNCH: /* restore mtrr state saved before */ restore_mtrrs(NULL); if ( s3_flag ) s3_launch(); else launch_kernel(false); break; /* if launch xen fails, do halt at the end */ case TB_POLACT_HALT: break; /* do halt at the end */ default: printk(TBOOT_ERR"Error: invalid policy action (%d)\n", action); /* do halt at the end */ } _tboot_shared.shutdown_type = TB_SHUTDOWN_HALT; shutdown(); } #define VL_ENTRIES(i) g_pre_k_s3_state.vl_entries[i] #define NUM_VL_ENTRIES g_pre_k_s3_state.num_vl_entries /* * verify modules against Verified Launch policy and save hash * if pol_entry is NULL, assume it is for module 0, which gets extended * to PCR 18 */ static tb_error_t verify_module(module_t *module, tb_policy_entry_t *pol_entry, uint16_t hash_alg) { /* assumes module is valid */ void *base = (void *)module->mod_start; size_t size = module->mod_end - module->mod_start; char *cmdline = get_module_cmd(g_ldr_ctx, module); if (cmdline == NULL) { printk(TBOOT_ERR"Error: failed to get module cmdline\n"); return TB_ERR_MODULE_VERIFICATION_FAILED; } const struct tpm_if *tpm = get_tpm(); if ( pol_entry != NULL ) { /* chunk the command line into 80 byte chunks */ #define CHUNK_SIZE 80 int cmdlen = tb_strlen(cmdline); char *cptr = cmdline; char cmdchunk[CHUNK_SIZE+1]; printk(TBOOT_INFO"verifying module \""); while (cmdlen > 0) { tb_strncpy(cmdchunk, cptr, CHUNK_SIZE); cmdchunk[CHUNK_SIZE] = 0; printk(TBOOT_INFO"\n%s", cmdchunk); cmdlen -= CHUNK_SIZE; cptr += CHUNK_SIZE; } printk(TBOOT_INFO"\"...\n"); } hash_list_t hl; if ( !hash_module(&hl, cmdline, base, size) ) { printk(TBOOT_ERR"\t hash cannot be generated.\n"); return TB_ERR_MODULE_VERIFICATION_FAILED; } /* add new hash to list (unless it doesn't get put in a PCR) we'll just drop it if the list is full, but that will mean S3 resume PCRs won't match pre-S3 NULL pol_entry means this is module 0 which is extended to PCR 18 */ if ( NUM_VL_ENTRIES >= MAX_VL_HASHES ) printk(TBOOT_WARN"\t too many hashes to save\n"); else if ( pol_entry == NULL || pol_entry->pcr != TB_POL_PCR_NONE ) { uint8_t pcr = (pol_entry == NULL ) ? (g_using_da ? 17 : 18) : pol_entry->pcr; VL_ENTRIES(NUM_VL_ENTRIES).pcr = pcr; VL_ENTRIES(NUM_VL_ENTRIES++).hl = hl; } if ( tpm->extpol != TB_EXTPOL_FIXED ) return TB_ERR_NONE; if ( pol_entry != NULL && !is_hash_in_policy_entry(pol_entry, &hl.entries[0].hash, hash_alg) ) { printk(TBOOT_ERR"\t verification failed\n"); return TB_ERR_MODULE_VERIFICATION_FAILED; } if ( pol_entry != NULL ) { printk(TBOOT_DETA"\t OK : "); print_hash(&hl.entries[0].hash, hash_alg); } return TB_ERR_NONE; } static void verify_g_policy(void) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); /* assumes mbi is valid */ printk(TBOOT_INFO"verifying policy \n"); /* add entry for policy control field and (optionally) policy */ /* hash will be | */ /* where will be 0s if TB_POLCTL_EXTEND_PCR17 is clear */ static uint8_t buf[sizeof(tb_hash_t) + sizeof(g_policy->policy_control)]; tb_memset(buf, 0, sizeof(buf)); tb_memcpy(buf, &g_policy->policy_control, sizeof(g_policy->policy_control)); if ( g_policy->policy_control & TB_POLCTL_EXTEND_PCR17 ) { if ( !hash_policy((tb_hash_t *)&buf[sizeof(g_policy->policy_control)], tpm->cur_alg) ) { printk(TBOOT_ERR"policy hash failed\n"); apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); } } u32 size = get_hash_size(tpm->cur_alg) + sizeof(g_policy->policy_control); switch (tpm->extpol) { case TB_EXTPOL_FIXED: VL_ENTRIES(NUM_VL_ENTRIES).hl.count = 1; VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].alg = tpm->cur_alg; if ( !hash_buffer(buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].hash, tpm->cur_alg) ) apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); break; case TB_EXTPOL_AGILE: if ( !tpm_fp->hash(tpm, 2, buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl) ) apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); break; case TB_EXTPOL_EMBEDDED: { VL_ENTRIES(NUM_VL_ENTRIES).hl.count = tpm->alg_count; for (int i=0; ialg_count; i++) { VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[i].alg = tpm->algs[i]; if ( !hash_buffer(buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[i].hash, tpm->algs[i]) ) return; } break; } default: apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); break; } VL_ENTRIES(NUM_VL_ENTRIES++).pcr = 17; if ( g_using_da ) { /* copying hash of policy_control into PCR 18 */ if ( NUM_VL_ENTRIES >= MAX_VL_HASHES ) printk(TBOOT_ERR"\t too many hashes to save for DA\n"); else { VL_ENTRIES(NUM_VL_ENTRIES).hl = VL_ENTRIES(NUM_VL_ENTRIES-1).hl; VL_ENTRIES(NUM_VL_ENTRIES++).pcr = 18; } } } void verify_all_modules(loader_ctx *lctx) { if (!verify_loader_context(lctx)) { printk(TBOOT_ERR"Error: Invalid loader context\n"); apply_policy(TB_ERR_FATAL); } /* assumes mbi is valid */ verify_g_policy(); /* module 0 is always extended to PCR 18, so add entry for it */ apply_policy(verify_module(get_module(lctx, 0), NULL, g_policy->hash_alg)); /* now verify each module and add its hash */ for ( unsigned int i = 0; i < get_module_count(lctx); i++ ) { module_t *module = get_module(lctx, i); tb_policy_entry_t *pol_entry = find_policy_entry(g_policy, i); if ( module == NULL ) { printk(TBOOT_ERR"missing module entry %u\n", i); apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); } else if ( pol_entry == NULL ) { printk(TBOOT_ERR"policy entry for module %u not found\n", i); apply_policy(TB_ERR_MODULES_NOT_IN_POLICY); } else apply_policy(verify_module(module, pol_entry, g_policy->hash_alg)); } printk(TBOOT_INFO"all modules are verified\n"); } static int find_first_nvpolicy_entry(const tb_policy_t *policy) { if ( policy == NULL ) { PRINT(TBOOT_ERR"Error: policy pointer is NULL\n"); return -1; } for ( int i = 0; i < policy->num_entries; i++ ) { tb_policy_entry_t *pol_entry = get_policy_entry(policy, i); if ( pol_entry == NULL ) return -1; if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV || pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) return i; } return -1; } static int find_next_nvpolicy_entry(const tb_policy_t *policy, int i) { if ( policy == NULL || i < 0 || i >= policy->num_entries ) return -1; for ( i++; i < policy->num_entries; i++ ) { tb_policy_entry_t *pol_entry = get_policy_entry(policy, i); if ( pol_entry == NULL ) return -1; if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV || pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) return i; } return -1; } static uint8_t nv_buf[4096]; static tb_error_t verify_nvindex(tb_policy_entry_t *pol_entry, uint16_t hash_alg) { size_t nv_size = sizeof(nv_buf); tb_hash_t digest; uint32_t attribute; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); if ( pol_entry == NULL ) return TB_ERR_NV_VERIFICATION_FAILED; printk(TBOOT_INFO"verifying nv index 0x%08X\n", pol_entry->nv_index); /* check nv attribute */ if ( !tpm_fp->get_nvindex_permission(tpm, 0, pol_entry->nv_index, &attribute) ) { printk(TBOOT_ERR"\t :reading nv index permission failed\n"); return TB_ERR_NV_VERIFICATION_FAILED; } if ( !(attribute & (TPM_NV_PER_OWNERWRITE | TPM_NV_PER_AUTHWRITE)) ) { printk(TBOOT_ERR"\t :nv index should be OWNERWRITE or AUTHWRITE, bad permission!\n"); return TB_ERR_NV_VERIFICATION_FAILED; } /* get nv content */ tb_memset(nv_buf, 0, sizeof(nv_buf)); if ( !read_policy_from_tpm(pol_entry->nv_index, nv_buf, &nv_size) ) { printk(TBOOT_ERR"\t :reading nv index 0x%08X failed\n", pol_entry->nv_index); return TB_ERR_NV_VERIFICATION_FAILED; } /* hash the buffer if needed */ switch ( pol_entry->mod_num ) { case TB_POL_MOD_NUM_NV: if ( !hash_buffer((const uint8_t*)nv_buf, nv_size, &digest, TB_HALG_SHA1) ) { printk(TBOOT_ERR"\t :nv content hash failed\n"); return TB_ERR_NV_VERIFICATION_FAILED; } break; case TB_POL_MOD_NUM_NV_RAW: if ( nv_size != sizeof(digest.sha1) ) { printk(TBOOT_ERR"\t :raw nv with wrong size (%d), should be %d\n", (int)nv_size, sizeof(digest.sha1)); return TB_ERR_NV_VERIFICATION_FAILED; } tb_memcpy(digest.sha1, nv_buf, nv_size); break; default: printk(TBOOT_ERR"\t :bad mod number for NV measuring in policy entry: %d\n", pol_entry->mod_num); return TB_ERR_NV_VERIFICATION_FAILED; } /* add new hash to list (unless it doesn't get put in a PCR) we'll just drop it if the list is full, but that will mean S3 resume PCRs won't match pre-S3 */ if ( NUM_VL_ENTRIES >= MAX_VL_HASHES ) printk(TBOOT_WARN"\t too many hashes to save\n"); else if ( pol_entry->pcr != TB_POL_PCR_NONE ) { VL_ENTRIES(NUM_VL_ENTRIES).pcr = pol_entry->pcr; VL_ENTRIES(NUM_VL_ENTRIES).hl.count = 1; VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].alg = TB_HALG_SHA1; tb_memcpy(VL_ENTRIES(NUM_VL_ENTRIES++).hl.entries[0].hash.sha1, digest.sha1, SHA1_LENGTH); } /* verify nv content */ if ( !is_hash_in_policy_entry(pol_entry, &digest, hash_alg) ) { printk(TBOOT_ERR"\t verification failed\n"); return TB_ERR_NV_VERIFICATION_FAILED; } printk(TBOOT_DETA"\t OK : "); print_hash(&digest, hash_alg); return TB_ERR_NONE; } void verify_all_nvindices(void) { /* go through nv policies in tb policy */ for ( int i = find_first_nvpolicy_entry(g_policy); i >= 0; i = find_next_nvpolicy_entry(g_policy, i) ) { tb_policy_entry_t *pol_entry = get_policy_entry(g_policy, i); apply_policy(verify_nvindex(pol_entry, g_policy->hash_alg)); } } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/poly1305/poly1305-x86.pl0000644000000000000000000014502014210363175017246 0ustar 00000000000000#! /usr/bin/env perl # Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html # # ==================================================================== # Written by Andy Polyakov for the OpenSSL # project. The module is, however, dual licensed under OpenSSL and # CRYPTOGAMS licenses depending on where you obtain it. For further # details see http://www.openssl.org/~appro/cryptogams/. # ==================================================================== # # This module implements Poly1305 hash for x86. # # April 2015 # # Numbers are cycles per processed byte with poly1305_blocks alone, # measured with rdtsc at fixed clock frequency. # # IALU/gcc-3.4(*) SSE2(**) AVX2 # Pentium 15.7/+80% - # PIII 6.21/+90% - # P4 19.8/+40% 3.24 # Core 2 4.85/+90% 1.80 # Westmere 4.58/+100% 1.43 # Sandy Bridge 3.90/+100% 1.36 # Haswell 3.88/+70% 1.18 0.72 # Skylake 3.10/+60% 1.14 0.62 # Silvermont 11.0/+40% 4.80 # Goldmont 4.10/+200% 2.10 # VIA Nano 6.71/+90% 2.47 # Sledgehammer 3.51/+180% 4.27 # Bulldozer 4.53/+140% 1.31 # # (*) gcc 4.8 for some reason generated worse code; # (**) besides SSE2 there are floating-point and AVX options; FP # is deemed unnecessary, because pre-SSE2 processor are too # old to care about, while it's not the fastest option on # SSE2-capable ones; AVX is omitted, because it doesn't give # a lot of improvement, 5-10% depending on processor; $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; push(@INC,"${dir}","${dir}."); require "x86asm.pl"; $output=pop and open STDOUT,">$output"; &asm_init($ARGV[0],$ARGV[$#ARGV] eq "386"); $sse2=$avx=0; for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } if ($sse2) { &static_label("const_sse2"); &static_label("enter_blocks"); &static_label("enter_emit"); &external_label("OPENSSL_ia32cap_P"); if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` =~ /GNU assembler version ([2-9]\.[0-9]+)/) { $avx = ($1>=2.19) + ($1>=2.22); } if (!$avx && $ARGV[0] eq "win32n" && `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { $avx = ($1>=2.09) + ($1>=2.10); } if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|based on LLVM) ([0-9]+\.[0-9]+)/) { $avx = ($2>=3.0) + ($2>3.0); } } ######################################################################## # Layout of opaque area is following. # # unsigned __int32 h[5]; # current hash value base 2^32 # unsigned __int32 pad; # is_base2_26 in vector context # unsigned __int32 r[4]; # key value base 2^32 &align(64); &function_begin("poly1305_init"); &mov ("edi",&wparam(0)); # context &mov ("esi",&wparam(1)); # key &mov ("ebp",&wparam(2)); # function table &xor ("eax","eax"); &mov (&DWP(4*0,"edi"),"eax"); # zero hash value &mov (&DWP(4*1,"edi"),"eax"); &mov (&DWP(4*2,"edi"),"eax"); &mov (&DWP(4*3,"edi"),"eax"); &mov (&DWP(4*4,"edi"),"eax"); &mov (&DWP(4*5,"edi"),"eax"); # is_base2_26 &cmp ("esi",0); &je (&label("nokey")); if ($sse2) { &call (&label("pic_point")); &set_label("pic_point"); &blindpop("ebx"); &lea ("eax",&DWP("poly1305_blocks-".&label("pic_point"),"ebx")); &lea ("edx",&DWP("poly1305_emit-".&label("pic_point"),"ebx")); &picmeup("edi","OPENSSL_ia32cap_P","ebx",&label("pic_point")); &mov ("ecx",&DWP(0,"edi")); &and ("ecx",1<<26|1<<24); &cmp ("ecx",1<<26|1<<24); # SSE2 and XMM? &jne (&label("no_sse2")); &lea ("eax",&DWP("_poly1305_blocks_sse2-".&label("pic_point"),"ebx")); &lea ("edx",&DWP("_poly1305_emit_sse2-".&label("pic_point"),"ebx")); if ($avx>1) { &mov ("ecx",&DWP(8,"edi")); &test ("ecx",1<<5); # AVX2? &jz (&label("no_sse2")); &lea ("eax",&DWP("_poly1305_blocks_avx2-".&label("pic_point"),"ebx")); } &set_label("no_sse2"); &mov ("edi",&wparam(0)); # reload context &mov (&DWP(0,"ebp"),"eax"); # fill function table &mov (&DWP(4,"ebp"),"edx"); } &mov ("eax",&DWP(4*0,"esi")); # load input key &mov ("ebx",&DWP(4*1,"esi")); &mov ("ecx",&DWP(4*2,"esi")); &mov ("edx",&DWP(4*3,"esi")); &and ("eax",0x0fffffff); &and ("ebx",0x0ffffffc); &and ("ecx",0x0ffffffc); &and ("edx",0x0ffffffc); &mov (&DWP(4*6,"edi"),"eax"); &mov (&DWP(4*7,"edi"),"ebx"); &mov (&DWP(4*8,"edi"),"ecx"); &mov (&DWP(4*9,"edi"),"edx"); &mov ("eax",$sse2); &set_label("nokey"); &function_end("poly1305_init"); ($h0,$h1,$h2,$h3,$h4, $d0,$d1,$d2,$d3, $r0,$r1,$r2,$r3, $s1,$s2,$s3)=map(4*$_,(0..15)); &function_begin("poly1305_blocks"); &mov ("edi",&wparam(0)); # ctx &mov ("esi",&wparam(1)); # inp &mov ("ecx",&wparam(2)); # len &set_label("enter_blocks"); &and ("ecx",-15); &jz (&label("nodata")); &stack_push(16); &mov ("eax",&DWP(4*6,"edi")); # r0 &mov ("ebx",&DWP(4*7,"edi")); # r1 &lea ("ebp",&DWP(0,"esi","ecx")); # end of input &mov ("ecx",&DWP(4*8,"edi")); # r2 &mov ("edx",&DWP(4*9,"edi")); # r3 &mov (&wparam(2),"ebp"); &mov ("ebp","esi"); &mov (&DWP($r0,"esp"),"eax"); # r0 &mov ("eax","ebx"); &shr ("eax",2); &mov (&DWP($r1,"esp"),"ebx"); # r1 &add ("eax","ebx"); # s1 &mov ("ebx","ecx"); &shr ("ebx",2); &mov (&DWP($r2,"esp"),"ecx"); # r2 &add ("ebx","ecx"); # s2 &mov ("ecx","edx"); &shr ("ecx",2); &mov (&DWP($r3,"esp"),"edx"); # r3 &add ("ecx","edx"); # s3 &mov (&DWP($s1,"esp"),"eax"); # s1 &mov (&DWP($s2,"esp"),"ebx"); # s2 &mov (&DWP($s3,"esp"),"ecx"); # s3 &mov ("eax",&DWP(4*0,"edi")); # load hash value &mov ("ebx",&DWP(4*1,"edi")); &mov ("ecx",&DWP(4*2,"edi")); &mov ("esi",&DWP(4*3,"edi")); &mov ("edi",&DWP(4*4,"edi")); &jmp (&label("loop")); &set_label("loop",32); &add ("eax",&DWP(4*0,"ebp")); # accumulate input &adc ("ebx",&DWP(4*1,"ebp")); &adc ("ecx",&DWP(4*2,"ebp")); &adc ("esi",&DWP(4*3,"ebp")); &lea ("ebp",&DWP(4*4,"ebp")); &adc ("edi",&wparam(3)); # padbit &mov (&DWP($h0,"esp"),"eax"); # put aside hash[+inp] &mov (&DWP($h3,"esp"),"esi"); &mul (&DWP($r0,"esp")); # h0*r0 &mov (&DWP($h4,"esp"),"edi"); &mov ("edi","eax"); &mov ("eax","ebx"); # h1 &mov ("esi","edx"); &mul (&DWP($s3,"esp")); # h1*s3 &add ("edi","eax"); &mov ("eax","ecx"); # h2 &adc ("esi","edx"); &mul (&DWP($s2,"esp")); # h2*s2 &add ("edi","eax"); &mov ("eax",&DWP($h3,"esp")); &adc ("esi","edx"); &mul (&DWP($s1,"esp")); # h3*s1 &add ("edi","eax"); &mov ("eax",&DWP($h0,"esp")); &adc ("esi","edx"); &mul (&DWP($r1,"esp")); # h0*r1 &mov (&DWP($d0,"esp"),"edi"); &xor ("edi","edi"); &add ("esi","eax"); &mov ("eax","ebx"); # h1 &adc ("edi","edx"); &mul (&DWP($r0,"esp")); # h1*r0 &add ("esi","eax"); &mov ("eax","ecx"); # h2 &adc ("edi","edx"); &mul (&DWP($s3,"esp")); # h2*s3 &add ("esi","eax"); &mov ("eax",&DWP($h3,"esp")); &adc ("edi","edx"); &mul (&DWP($s2,"esp")); # h3*s2 &add ("esi","eax"); &mov ("eax",&DWP($h4,"esp")); &adc ("edi","edx"); &imul ("eax",&DWP($s1,"esp")); # h4*s1 &add ("esi","eax"); &mov ("eax",&DWP($h0,"esp")); &adc ("edi",0); &mul (&DWP($r2,"esp")); # h0*r2 &mov (&DWP($d1,"esp"),"esi"); &xor ("esi","esi"); &add ("edi","eax"); &mov ("eax","ebx"); # h1 &adc ("esi","edx"); &mul (&DWP($r1,"esp")); # h1*r1 &add ("edi","eax"); &mov ("eax","ecx"); # h2 &adc ("esi","edx"); &mul (&DWP($r0,"esp")); # h2*r0 &add ("edi","eax"); &mov ("eax",&DWP($h3,"esp")); &adc ("esi","edx"); &mul (&DWP($s3,"esp")); # h3*s3 &add ("edi","eax"); &mov ("eax",&DWP($h4,"esp")); &adc ("esi","edx"); &imul ("eax",&DWP($s2,"esp")); # h4*s2 &add ("edi","eax"); &mov ("eax",&DWP($h0,"esp")); &adc ("esi",0); &mul (&DWP($r3,"esp")); # h0*r3 &mov (&DWP($d2,"esp"),"edi"); &xor ("edi","edi"); &add ("esi","eax"); &mov ("eax","ebx"); # h1 &adc ("edi","edx"); &mul (&DWP($r2,"esp")); # h1*r2 &add ("esi","eax"); &mov ("eax","ecx"); # h2 &adc ("edi","edx"); &mul (&DWP($r1,"esp")); # h2*r1 &add ("esi","eax"); &mov ("eax",&DWP($h3,"esp")); &adc ("edi","edx"); &mul (&DWP($r0,"esp")); # h3*r0 &add ("esi","eax"); &mov ("ecx",&DWP($h4,"esp")); &adc ("edi","edx"); &mov ("edx","ecx"); &imul ("ecx",&DWP($s3,"esp")); # h4*s3 &add ("esi","ecx"); &mov ("eax",&DWP($d0,"esp")); &adc ("edi",0); &imul ("edx",&DWP($r0,"esp")); # h4*r0 &add ("edx","edi"); &mov ("ebx",&DWP($d1,"esp")); &mov ("ecx",&DWP($d2,"esp")); &mov ("edi","edx"); # last reduction step &shr ("edx",2); &and ("edi",3); &lea ("edx",&DWP(0,"edx","edx",4)); # *5 &add ("eax","edx"); &adc ("ebx",0); &adc ("ecx",0); &adc ("esi",0); &adc ("edi",0); &cmp ("ebp",&wparam(2)); # done yet? &jne (&label("loop")); &mov ("edx",&wparam(0)); # ctx &stack_pop(16); &mov (&DWP(4*0,"edx"),"eax"); # store hash value &mov (&DWP(4*1,"edx"),"ebx"); &mov (&DWP(4*2,"edx"),"ecx"); &mov (&DWP(4*3,"edx"),"esi"); &mov (&DWP(4*4,"edx"),"edi"); &set_label("nodata"); &function_end("poly1305_blocks"); &function_begin("poly1305_emit"); &mov ("ebp",&wparam(0)); # context &set_label("enter_emit"); &mov ("edi",&wparam(1)); # output &mov ("eax",&DWP(4*0,"ebp")); # load hash value &mov ("ebx",&DWP(4*1,"ebp")); &mov ("ecx",&DWP(4*2,"ebp")); &mov ("edx",&DWP(4*3,"ebp")); &mov ("esi",&DWP(4*4,"ebp")); &add ("eax",5); # compare to modulus &adc ("ebx",0); &adc ("ecx",0); &adc ("edx",0); &adc ("esi",0); &shr ("esi",2); # did it carry/borrow? &neg ("esi"); # do we choose hash-modulus? &and ("eax","esi"); &and ("ebx","esi"); &and ("ecx","esi"); &and ("edx","esi"); &mov (&DWP(4*0,"edi"),"eax"); &mov (&DWP(4*1,"edi"),"ebx"); &mov (&DWP(4*2,"edi"),"ecx"); &mov (&DWP(4*3,"edi"),"edx"); ¬ ("esi"); # or original hash value? &mov ("eax",&DWP(4*0,"ebp")); &mov ("ebx",&DWP(4*1,"ebp")); &mov ("ecx",&DWP(4*2,"ebp")); &mov ("edx",&DWP(4*3,"ebp")); &mov ("ebp",&wparam(2)); &and ("eax","esi"); &and ("ebx","esi"); &and ("ecx","esi"); &and ("edx","esi"); &or ("eax",&DWP(4*0,"edi")); &or ("ebx",&DWP(4*1,"edi")); &or ("ecx",&DWP(4*2,"edi")); &or ("edx",&DWP(4*3,"edi")); &add ("eax",&DWP(4*0,"ebp")); # accumulate key &adc ("ebx",&DWP(4*1,"ebp")); &adc ("ecx",&DWP(4*2,"ebp")); &adc ("edx",&DWP(4*3,"ebp")); &mov (&DWP(4*0,"edi"),"eax"); &mov (&DWP(4*1,"edi"),"ebx"); &mov (&DWP(4*2,"edi"),"ecx"); &mov (&DWP(4*3,"edi"),"edx"); &function_end("poly1305_emit"); if ($sse2) { ######################################################################## # Layout of opaque area is following. # # unsigned __int32 h[5]; # current hash value base 2^26 # unsigned __int32 is_base2_26; # unsigned __int32 r[4]; # key value base 2^32 # unsigned __int32 pad[2]; # struct { unsigned __int32 r^4, r^3, r^2, r^1; } r[9]; # # where r^n are base 2^26 digits of degrees of multiplier key. There are # 5 digits, but last four are interleaved with multiples of 5, totalling # in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4. my ($D0,$D1,$D2,$D3,$D4,$T0,$T1,$T2)=map("xmm$_",(0..7)); my $MASK=$T2; # borrow and keep in mind &align (32); &function_begin_B("_poly1305_init_sse2"); &movdqu ($D4,&QWP(4*6,"edi")); # key base 2^32 &lea ("edi",&DWP(16*3,"edi")); # size optimization &mov ("ebp","esp"); &sub ("esp",16*(9+5)); &and ("esp",-16); #&pand ($D4,&QWP(96,"ebx")); # magic mask &movq ($MASK,&QWP(64,"ebx")); &movdqa ($D0,$D4); &movdqa ($D1,$D4); &movdqa ($D2,$D4); &pand ($D0,$MASK); # -> base 2^26 &psrlq ($D1,26); &psrldq ($D2,6); &pand ($D1,$MASK); &movdqa ($D3,$D2); &psrlq ($D2,4) &psrlq ($D3,30); &pand ($D2,$MASK); &pand ($D3,$MASK); &psrldq ($D4,13); &lea ("edx",&DWP(16*9,"esp")); # size optimization &mov ("ecx",2); &set_label("square"); &movdqa (&QWP(16*0,"esp"),$D0); &movdqa (&QWP(16*1,"esp"),$D1); &movdqa (&QWP(16*2,"esp"),$D2); &movdqa (&QWP(16*3,"esp"),$D3); &movdqa (&QWP(16*4,"esp"),$D4); &movdqa ($T1,$D1); &movdqa ($T0,$D2); &pslld ($T1,2); &pslld ($T0,2); &paddd ($T1,$D1); # *5 &paddd ($T0,$D2); # *5 &movdqa (&QWP(16*5,"esp"),$T1); &movdqa (&QWP(16*6,"esp"),$T0); &movdqa ($T1,$D3); &movdqa ($T0,$D4); &pslld ($T1,2); &pslld ($T0,2); &paddd ($T1,$D3); # *5 &paddd ($T0,$D4); # *5 &movdqa (&QWP(16*7,"esp"),$T1); &movdqa (&QWP(16*8,"esp"),$T0); &pshufd ($T1,$D0,0b01000100); &movdqa ($T0,$D1); &pshufd ($D1,$D1,0b01000100); &pshufd ($D2,$D2,0b01000100); &pshufd ($D3,$D3,0b01000100); &pshufd ($D4,$D4,0b01000100); &movdqa (&QWP(16*0,"edx"),$T1); &movdqa (&QWP(16*1,"edx"),$D1); &movdqa (&QWP(16*2,"edx"),$D2); &movdqa (&QWP(16*3,"edx"),$D3); &movdqa (&QWP(16*4,"edx"),$D4); ################################################################ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 &pmuludq ($D4,$D0); # h4*r0 &pmuludq ($D3,$D0); # h3*r0 &pmuludq ($D2,$D0); # h2*r0 &pmuludq ($D1,$D0); # h1*r0 &pmuludq ($D0,$T1); # h0*r0 sub pmuladd { my $load = shift; my $base = shift; $base = "esp" if (!defined($base)); ################################################################ # As for choice to "rotate" $T0-$T2 in order to move paddq # past next multiplication. While it makes code harder to read # and doesn't have significant effect on most processors, it # makes a lot of difference on Atom, up to 30% improvement. &movdqa ($T1,$T0); &pmuludq ($T0,&QWP(16*3,$base)); # r1*h3 &movdqa ($T2,$T1); &pmuludq ($T1,&QWP(16*2,$base)); # r1*h2 &paddq ($D4,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&QWP(16*1,$base)); # r1*h1 &paddq ($D3,$T1); &$load ($T1,5); # s1 &pmuludq ($T0,&QWP(16*0,$base)); # r1*h0 &paddq ($D2,$T2); &pmuludq ($T1,&QWP(16*4,$base)); # s1*h4 &$load ($T2,2); # r2^n &paddq ($D1,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&QWP(16*2,$base)); # r2*h2 &paddq ($D0,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&QWP(16*1,$base)); # r2*h1 &paddq ($D4,$T2); &$load ($T2,6); # s2^n &pmuludq ($T1,&QWP(16*0,$base)); # r2*h0 &paddq ($D3,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&QWP(16*4,$base)); # s2*h4 &paddq ($D2,$T1); &pmuludq ($T0,&QWP(16*3,$base)); # s2*h3 &$load ($T1,3); # r3^n &paddq ($D1,$T2); &movdqa ($T2,$T1); &pmuludq ($T1,&QWP(16*1,$base)); # r3*h1 &paddq ($D0,$T0); &$load ($T0,7); # s3^n &pmuludq ($T2,&QWP(16*0,$base)); # r3*h0 &paddq ($D4,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&QWP(16*4,$base)); # s3*h4 &paddq ($D3,$T2); &movdqa ($T2,$T1); &pmuludq ($T1,&QWP(16*3,$base)); # s3*h3 &paddq ($D2,$T0); &pmuludq ($T2,&QWP(16*2,$base)); # s3*h2 &$load ($T0,4); # r4^n &paddq ($D1,$T1); &$load ($T1,8); # s4^n &pmuludq ($T0,&QWP(16*0,$base)); # r4*h0 &paddq ($D0,$T2); &movdqa ($T2,$T1); &pmuludq ($T1,&QWP(16*4,$base)); # s4*h4 &paddq ($D4,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&QWP(16*1,$base)); # s4*h1 &paddq ($D3,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&QWP(16*2,$base)); # s4*h2 &paddq ($D0,$T2); &pmuludq ($T1,&QWP(16*3,$base)); # s4*h3 &movdqa ($MASK,&QWP(64,"ebx")); &paddq ($D1,$T0); &paddq ($D2,$T1); } &pmuladd (sub { my ($reg,$i)=@_; &movdqa ($reg,&QWP(16*$i,"esp")); },"edx"); sub lazy_reduction { my $extra = shift; ################################################################ # lazy reduction as discussed in "NEON crypto" by D.J. Bernstein # and P. Schwabe # # [(*) see discussion in poly1305-armv4 module] &movdqa ($T0,$D3); &pand ($D3,$MASK); &psrlq ($T0,26); &$extra () if (defined($extra)); &paddq ($T0,$D4); # h3 -> h4 &movdqa ($T1,$D0); &pand ($D0,$MASK); &psrlq ($T1,26); &movdqa ($D4,$T0); &paddq ($T1,$D1); # h0 -> h1 &psrlq ($T0,26); &pand ($D4,$MASK); &movdqa ($D1,$T1); &psrlq ($T1,26); &paddd ($D0,$T0); # favour paddd when # possible, because # paddq is "broken" # on Atom &psllq ($T0,2); &paddq ($T1,$D2); # h1 -> h2 &paddq ($T0,$D0); # h4 -> h0 (*) &pand ($D1,$MASK); &movdqa ($D2,$T1); &psrlq ($T1,26); &pand ($D2,$MASK); &paddd ($T1,$D3); # h2 -> h3 &movdqa ($D0,$T0); &psrlq ($T0,26); &movdqa ($D3,$T1); &psrlq ($T1,26); &pand ($D0,$MASK); &paddd ($D1,$T0); # h0 -> h1 &pand ($D3,$MASK); &paddd ($D4,$T1); # h3 -> h4 } &lazy_reduction (); &dec ("ecx"); &jz (&label("square_break")); &punpcklqdq ($D0,&QWP(16*0,"esp")); # 0:r^1:0:r^2 &punpcklqdq ($D1,&QWP(16*1,"esp")); &punpcklqdq ($D2,&QWP(16*2,"esp")); &punpcklqdq ($D3,&QWP(16*3,"esp")); &punpcklqdq ($D4,&QWP(16*4,"esp")); &jmp (&label("square")); &set_label("square_break"); &psllq ($D0,32); # -> r^3:0:r^4:0 &psllq ($D1,32); &psllq ($D2,32); &psllq ($D3,32); &psllq ($D4,32); &por ($D0,&QWP(16*0,"esp")); # r^3:r^1:r^4:r^2 &por ($D1,&QWP(16*1,"esp")); &por ($D2,&QWP(16*2,"esp")); &por ($D3,&QWP(16*3,"esp")); &por ($D4,&QWP(16*4,"esp")); &pshufd ($D0,$D0,0b10001101); # -> r^1:r^2:r^3:r^4 &pshufd ($D1,$D1,0b10001101); &pshufd ($D2,$D2,0b10001101); &pshufd ($D3,$D3,0b10001101); &pshufd ($D4,$D4,0b10001101); &movdqu (&QWP(16*0,"edi"),$D0); # save the table &movdqu (&QWP(16*1,"edi"),$D1); &movdqu (&QWP(16*2,"edi"),$D2); &movdqu (&QWP(16*3,"edi"),$D3); &movdqu (&QWP(16*4,"edi"),$D4); &movdqa ($T1,$D1); &movdqa ($T0,$D2); &pslld ($T1,2); &pslld ($T0,2); &paddd ($T1,$D1); # *5 &paddd ($T0,$D2); # *5 &movdqu (&QWP(16*5,"edi"),$T1); &movdqu (&QWP(16*6,"edi"),$T0); &movdqa ($T1,$D3); &movdqa ($T0,$D4); &pslld ($T1,2); &pslld ($T0,2); &paddd ($T1,$D3); # *5 &paddd ($T0,$D4); # *5 &movdqu (&QWP(16*7,"edi"),$T1); &movdqu (&QWP(16*8,"edi"),$T0); &mov ("esp","ebp"); &lea ("edi",&DWP(-16*3,"edi")); # size de-optimization &ret (); &function_end_B("_poly1305_init_sse2"); &align (32); &function_begin("_poly1305_blocks_sse2"); &mov ("edi",&wparam(0)); # ctx &mov ("esi",&wparam(1)); # inp &mov ("ecx",&wparam(2)); # len &mov ("eax",&DWP(4*5,"edi")); # is_base2_26 &and ("ecx",-16); &jz (&label("nodata")); &cmp ("ecx",64); &jae (&label("enter_sse2")); &test ("eax","eax"); # is_base2_26? &jz (&label("enter_blocks")); &set_label("enter_sse2",16); &call (&label("pic_point")); &set_label("pic_point"); &blindpop("ebx"); &lea ("ebx",&DWP(&label("const_sse2")."-".&label("pic_point"),"ebx")); &test ("eax","eax"); # is_base2_26? &jnz (&label("base2_26")); &call ("_poly1305_init_sse2"); ################################################# base 2^32 -> base 2^26 &mov ("eax",&DWP(0,"edi")); &mov ("ecx",&DWP(3,"edi")); &mov ("edx",&DWP(6,"edi")); &mov ("esi",&DWP(9,"edi")); &mov ("ebp",&DWP(13,"edi")); &mov (&DWP(4*5,"edi"),1); # is_base2_26 &shr ("ecx",2); &and ("eax",0x3ffffff); &shr ("edx",4); &and ("ecx",0x3ffffff); &shr ("esi",6); &and ("edx",0x3ffffff); &movd ($D0,"eax"); &movd ($D1,"ecx"); &movd ($D2,"edx"); &movd ($D3,"esi"); &movd ($D4,"ebp"); &mov ("esi",&wparam(1)); # [reload] inp &mov ("ecx",&wparam(2)); # [reload] len &jmp (&label("base2_32")); &set_label("base2_26",16); &movd ($D0,&DWP(4*0,"edi")); # load hash value &movd ($D1,&DWP(4*1,"edi")); &movd ($D2,&DWP(4*2,"edi")); &movd ($D3,&DWP(4*3,"edi")); &movd ($D4,&DWP(4*4,"edi")); &movdqa ($MASK,&QWP(64,"ebx")); &set_label("base2_32"); &mov ("eax",&wparam(3)); # padbit &mov ("ebp","esp"); &sub ("esp",16*(5+5+5+9+9)); &and ("esp",-16); &lea ("edi",&DWP(16*3,"edi")); # size optimization &shl ("eax",24); # padbit &test ("ecx",31); &jz (&label("even")); ################################################################ # process single block, with SSE2, because it's still faster # even though half of result is discarded &movdqu ($T1,&QWP(0,"esi")); # input &lea ("esi",&DWP(16,"esi")); &movdqa ($T0,$T1); # -> base 2^26 ... &pand ($T1,$MASK); &paddd ($D0,$T1); # ... and accumulate &movdqa ($T1,$T0); &psrlq ($T0,26); &psrldq ($T1,6); &pand ($T0,$MASK); &paddd ($D1,$T0); &movdqa ($T0,$T1); &psrlq ($T1,4); &pand ($T1,$MASK); &paddd ($D2,$T1); &movdqa ($T1,$T0); &psrlq ($T0,30); &pand ($T0,$MASK); &psrldq ($T1,7); &paddd ($D3,$T0); &movd ($T0,"eax"); # padbit &paddd ($D4,$T1); &movd ($T1,&DWP(16*0+12,"edi")); # r0 &paddd ($D4,$T0); &movdqa (&QWP(16*0,"esp"),$D0); &movdqa (&QWP(16*1,"esp"),$D1); &movdqa (&QWP(16*2,"esp"),$D2); &movdqa (&QWP(16*3,"esp"),$D3); &movdqa (&QWP(16*4,"esp"),$D4); ################################################################ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 &pmuludq ($D0,$T1); # h4*r0 &pmuludq ($D1,$T1); # h3*r0 &pmuludq ($D2,$T1); # h2*r0 &movd ($T0,&DWP(16*1+12,"edi")); # r1 &pmuludq ($D3,$T1); # h1*r0 &pmuludq ($D4,$T1); # h0*r0 &pmuladd (sub { my ($reg,$i)=@_; &movd ($reg,&DWP(16*$i+12,"edi")); }); &lazy_reduction (); &sub ("ecx",16); &jz (&label("done")); &set_label("even"); &lea ("edx",&DWP(16*(5+5+5+9),"esp"));# size optimization &lea ("eax",&DWP(-16*2,"esi")); &sub ("ecx",64); ################################################################ # expand and copy pre-calculated table to stack &movdqu ($T0,&QWP(16*0,"edi")); # r^1:r^2:r^3:r^4 &pshufd ($T1,$T0,0b01000100); # duplicate r^3:r^4 &cmovb ("esi","eax"); &pshufd ($T0,$T0,0b11101110); # duplicate r^1:r^2 &movdqa (&QWP(16*0,"edx"),$T1); &lea ("eax",&DWP(16*10,"esp")); &movdqu ($T1,&QWP(16*1,"edi")); &movdqa (&QWP(16*(0-9),"edx"),$T0); &pshufd ($T0,$T1,0b01000100); &pshufd ($T1,$T1,0b11101110); &movdqa (&QWP(16*1,"edx"),$T0); &movdqu ($T0,&QWP(16*2,"edi")); &movdqa (&QWP(16*(1-9),"edx"),$T1); &pshufd ($T1,$T0,0b01000100); &pshufd ($T0,$T0,0b11101110); &movdqa (&QWP(16*2,"edx"),$T1); &movdqu ($T1,&QWP(16*3,"edi")); &movdqa (&QWP(16*(2-9),"edx"),$T0); &pshufd ($T0,$T1,0b01000100); &pshufd ($T1,$T1,0b11101110); &movdqa (&QWP(16*3,"edx"),$T0); &movdqu ($T0,&QWP(16*4,"edi")); &movdqa (&QWP(16*(3-9),"edx"),$T1); &pshufd ($T1,$T0,0b01000100); &pshufd ($T0,$T0,0b11101110); &movdqa (&QWP(16*4,"edx"),$T1); &movdqu ($T1,&QWP(16*5,"edi")); &movdqa (&QWP(16*(4-9),"edx"),$T0); &pshufd ($T0,$T1,0b01000100); &pshufd ($T1,$T1,0b11101110); &movdqa (&QWP(16*5,"edx"),$T0); &movdqu ($T0,&QWP(16*6,"edi")); &movdqa (&QWP(16*(5-9),"edx"),$T1); &pshufd ($T1,$T0,0b01000100); &pshufd ($T0,$T0,0b11101110); &movdqa (&QWP(16*6,"edx"),$T1); &movdqu ($T1,&QWP(16*7,"edi")); &movdqa (&QWP(16*(6-9),"edx"),$T0); &pshufd ($T0,$T1,0b01000100); &pshufd ($T1,$T1,0b11101110); &movdqa (&QWP(16*7,"edx"),$T0); &movdqu ($T0,&QWP(16*8,"edi")); &movdqa (&QWP(16*(7-9),"edx"),$T1); &pshufd ($T1,$T0,0b01000100); &pshufd ($T0,$T0,0b11101110); &movdqa (&QWP(16*8,"edx"),$T1); &movdqa (&QWP(16*(8-9),"edx"),$T0); sub load_input { my ($inpbase,$offbase)=@_; &movdqu ($T0,&QWP($inpbase+0,"esi")); # load input &movdqu ($T1,&QWP($inpbase+16,"esi")); &lea ("esi",&DWP(16*2,"esi")); &movdqa (&QWP($offbase+16*2,"esp"),$D2); &movdqa (&QWP($offbase+16*3,"esp"),$D3); &movdqa (&QWP($offbase+16*4,"esp"),$D4); &movdqa ($D2,$T0); # splat input &movdqa ($D3,$T1); &psrldq ($D2,6); &psrldq ($D3,6); &movdqa ($D4,$T0); &punpcklqdq ($D2,$D3); # 2:3 &punpckhqdq ($D4,$T1); # 4 &punpcklqdq ($T0,$T1); # 0:1 &movdqa ($D3,$D2); &psrlq ($D2,4); &psrlq ($D3,30); &movdqa ($T1,$T0); &psrlq ($D4,40); # 4 &psrlq ($T1,26); &pand ($T0,$MASK); # 0 &pand ($T1,$MASK); # 1 &pand ($D2,$MASK); # 2 &pand ($D3,$MASK); # 3 &por ($D4,&QWP(0,"ebx")); # padbit, yes, always &movdqa (&QWP($offbase+16*0,"esp"),$D0) if ($offbase); &movdqa (&QWP($offbase+16*1,"esp"),$D1) if ($offbase); } &load_input (16*2,16*5); &jbe (&label("skip_loop")); &jmp (&label("loop")); &set_label("loop",32); ################################################################ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2 # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r # \___________________/ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2 # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r # \___________________/ \____________________/ ################################################################ &movdqa ($T2,&QWP(16*(0-9),"edx")); # r0^2 &movdqa (&QWP(16*1,"eax"),$T1); &movdqa (&QWP(16*2,"eax"),$D2); &movdqa (&QWP(16*3,"eax"),$D3); &movdqa (&QWP(16*4,"eax"),$D4); ################################################################ # d4 = h4*r0 + h0*r4 + h1*r3 + h2*r2 + h3*r1 # d3 = h3*r0 + h0*r3 + h1*r2 + h2*r1 + h4*5*r4 # d2 = h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3 # d1 = h1*r0 + h0*r1 + h2*5*r4 + h3*5*r3 + h4*5*r2 # d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1 &movdqa ($D1,$T0); &pmuludq ($T0,$T2); # h0*r0 &movdqa ($D0,$T1); &pmuludq ($T1,$T2); # h1*r0 &pmuludq ($D2,$T2); # h2*r0 &pmuludq ($D3,$T2); # h3*r0 &pmuludq ($D4,$T2); # h4*r0 sub pmuladd_alt { my $addr = shift; &pmuludq ($D0,&$addr(8)); # h1*s4 &movdqa ($T2,$D1); &pmuludq ($D1,&$addr(1)); # h0*r1 &paddq ($D0,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&$addr(2)); # h0*r2 &paddq ($D1,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&$addr(3)); # h0*r3 &paddq ($D2,$T2); &movdqa ($T2,&QWP(16*1,"eax")); # pull h1 &pmuludq ($T1,&$addr(4)); # h0*r4 &paddq ($D3,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&$addr(1)); # h1*r1 &paddq ($D4,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&$addr(2)); # h1*r2 &paddq ($D2,$T2); &movdqa ($T2,&QWP(16*2,"eax")); # pull h2 &pmuludq ($T1,&$addr(3)); # h1*r3 &paddq ($D3,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&$addr(7)); # h2*s3 &paddq ($D4,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&$addr(8)); # h2*s4 &paddq ($D0,$T2); &movdqa ($T2,$T1); &pmuludq ($T1,&$addr(1)); # h2*r1 &paddq ($D1,$T0); &movdqa ($T0,&QWP(16*3,"eax")); # pull h3 &pmuludq ($T2,&$addr(2)); # h2*r2 &paddq ($D3,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&$addr(6)); # h3*s2 &paddq ($D4,$T2); &movdqa ($T2,$T1); &pmuludq ($T1,&$addr(7)); # h3*s3 &paddq ($D0,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&$addr(8)); # h3*s4 &paddq ($D1,$T1); &movdqa ($T1,&QWP(16*4,"eax")); # pull h4 &pmuludq ($T0,&$addr(1)); # h3*r1 &paddq ($D2,$T2); &movdqa ($T2,$T1); &pmuludq ($T1,&$addr(8)); # h4*s4 &paddq ($D4,$T0); &movdqa ($T0,$T2); &pmuludq ($T2,&$addr(5)); # h4*s1 &paddq ($D3,$T1); &movdqa ($T1,$T0); &pmuludq ($T0,&$addr(6)); # h4*s2 &paddq ($D0,$T2); &movdqa ($MASK,&QWP(64,"ebx")); &pmuludq ($T1,&$addr(7)); # h4*s3 &paddq ($D1,$T0); &paddq ($D2,$T1); } &pmuladd_alt (sub { my $i=shift; &QWP(16*($i-9),"edx"); }); &load_input (-16*2,0); &lea ("eax",&DWP(-16*2,"esi")); &sub ("ecx",64); &paddd ($T0,&QWP(16*(5+0),"esp")); # add hash value &paddd ($T1,&QWP(16*(5+1),"esp")); &paddd ($D2,&QWP(16*(5+2),"esp")); &paddd ($D3,&QWP(16*(5+3),"esp")); &paddd ($D4,&QWP(16*(5+4),"esp")); &cmovb ("esi","eax"); &lea ("eax",&DWP(16*10,"esp")); &movdqa ($T2,&QWP(16*0,"edx")); # r0^4 &movdqa (&QWP(16*1,"esp"),$D1); &movdqa (&QWP(16*1,"eax"),$T1); &movdqa (&QWP(16*2,"eax"),$D2); &movdqa (&QWP(16*3,"eax"),$D3); &movdqa (&QWP(16*4,"eax"),$D4); ################################################################ # d4 += h4*r0 + h0*r4 + h1*r3 + h2*r2 + h3*r1 # d3 += h3*r0 + h0*r3 + h1*r2 + h2*r1 + h4*5*r4 # d2 += h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3 # d1 += h1*r0 + h0*r1 + h2*5*r4 + h3*5*r3 + h4*5*r2 # d0 += h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1 &movdqa ($D1,$T0); &pmuludq ($T0,$T2); # h0*r0 &paddq ($T0,$D0); &movdqa ($D0,$T1); &pmuludq ($T1,$T2); # h1*r0 &pmuludq ($D2,$T2); # h2*r0 &pmuludq ($D3,$T2); # h3*r0 &pmuludq ($D4,$T2); # h4*r0 &paddq ($T1,&QWP(16*1,"esp")); &paddq ($D2,&QWP(16*2,"esp")); &paddq ($D3,&QWP(16*3,"esp")); &paddq ($D4,&QWP(16*4,"esp")); &pmuladd_alt (sub { my $i=shift; &QWP(16*$i,"edx"); }); &lazy_reduction (); &load_input (16*2,16*5); &ja (&label("loop")); &set_label("skip_loop"); ################################################################ # multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1 &pshufd ($T2,&QWP(16*(0-9),"edx"),0x10);# r0^n &add ("ecx",32); &jnz (&label("long_tail")); &paddd ($T0,$D0); # add hash value &paddd ($T1,$D1); &paddd ($D2,&QWP(16*7,"esp")); &paddd ($D3,&QWP(16*8,"esp")); &paddd ($D4,&QWP(16*9,"esp")); &set_label("long_tail"); &movdqa (&QWP(16*0,"eax"),$T0); &movdqa (&QWP(16*1,"eax"),$T1); &movdqa (&QWP(16*2,"eax"),$D2); &movdqa (&QWP(16*3,"eax"),$D3); &movdqa (&QWP(16*4,"eax"),$D4); ################################################################ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 &pmuludq ($T0,$T2); # h0*r0 &pmuludq ($T1,$T2); # h1*r0 &pmuludq ($D2,$T2); # h2*r0 &movdqa ($D0,$T0); &pshufd ($T0,&QWP(16*(1-9),"edx"),0x10);# r1^n &pmuludq ($D3,$T2); # h3*r0 &movdqa ($D1,$T1); &pmuludq ($D4,$T2); # h4*r0 &pmuladd (sub { my ($reg,$i)=@_; &pshufd ($reg,&QWP(16*($i-9),"edx"),0x10); },"eax"); &jz (&label("short_tail")); &load_input (-16*2,0); &pshufd ($T2,&QWP(16*0,"edx"),0x10); # r0^n &paddd ($T0,&QWP(16*5,"esp")); # add hash value &paddd ($T1,&QWP(16*6,"esp")); &paddd ($D2,&QWP(16*7,"esp")); &paddd ($D3,&QWP(16*8,"esp")); &paddd ($D4,&QWP(16*9,"esp")); ################################################################ # multiply inp[0:1] by r^4:r^3 and accumulate &movdqa (&QWP(16*0,"esp"),$T0); &pmuludq ($T0,$T2); # h0*r0 &movdqa (&QWP(16*1,"esp"),$T1); &pmuludq ($T1,$T2); # h1*r0 &paddq ($D0,$T0); &movdqa ($T0,$D2); &pmuludq ($D2,$T2); # h2*r0 &paddq ($D1,$T1); &movdqa ($T1,$D3); &pmuludq ($D3,$T2); # h3*r0 &paddq ($D2,&QWP(16*2,"esp")); &movdqa (&QWP(16*2,"esp"),$T0); &pshufd ($T0,&QWP(16*1,"edx"),0x10); # r1^n &paddq ($D3,&QWP(16*3,"esp")); &movdqa (&QWP(16*3,"esp"),$T1); &movdqa ($T1,$D4); &pmuludq ($D4,$T2); # h4*r0 &paddq ($D4,&QWP(16*4,"esp")); &movdqa (&QWP(16*4,"esp"),$T1); &pmuladd (sub { my ($reg,$i)=@_; &pshufd ($reg,&QWP(16*$i,"edx"),0x10); }); &set_label("short_tail"); ################################################################ # horizontal addition &pshufd ($T1,$D4,0b01001110); &pshufd ($T0,$D3,0b01001110); &paddq ($D4,$T1); &paddq ($D3,$T0); &pshufd ($T1,$D0,0b01001110); &pshufd ($T0,$D1,0b01001110); &paddq ($D0,$T1); &paddq ($D1,$T0); &pshufd ($T1,$D2,0b01001110); #&paddq ($D2,$T1); &lazy_reduction (sub { &paddq ($D2,$T1) }); &set_label("done"); &movd (&DWP(-16*3+4*0,"edi"),$D0); # store hash value &movd (&DWP(-16*3+4*1,"edi"),$D1); &movd (&DWP(-16*3+4*2,"edi"),$D2); &movd (&DWP(-16*3+4*3,"edi"),$D3); &movd (&DWP(-16*3+4*4,"edi"),$D4); &mov ("esp","ebp"); &set_label("nodata"); &function_end("_poly1305_blocks_sse2"); &align (32); &function_begin("_poly1305_emit_sse2"); &mov ("ebp",&wparam(0)); # context &cmp (&DWP(4*5,"ebp"),0); # is_base2_26? &je (&label("enter_emit")); &mov ("eax",&DWP(4*0,"ebp")); # load hash value &mov ("edi",&DWP(4*1,"ebp")); &mov ("ecx",&DWP(4*2,"ebp")); &mov ("edx",&DWP(4*3,"ebp")); &mov ("esi",&DWP(4*4,"ebp")); &mov ("ebx","edi"); # base 2^26 -> base 2^32 &shl ("edi",26); &shr ("ebx",6); &add ("eax","edi"); &mov ("edi","ecx"); &adc ("ebx",0); &shl ("edi",20); &shr ("ecx",12); &add ("ebx","edi"); &mov ("edi","edx"); &adc ("ecx",0); &shl ("edi",14); &shr ("edx",18); &add ("ecx","edi"); &mov ("edi","esi"); &adc ("edx",0); &shl ("edi",8); &shr ("esi",24); &add ("edx","edi"); &adc ("esi",0); # can be partially reduced &mov ("edi","esi"); # final reduction &and ("esi",3); &shr ("edi",2); &lea ("ebp",&DWP(0,"edi","edi",4)); # *5 &mov ("edi",&wparam(1)); # output &add ("eax","ebp"); &mov ("ebp",&wparam(2)); # key &adc ("ebx",0); &adc ("ecx",0); &adc ("edx",0); &adc ("esi",0); &movd ($D0,"eax"); # offload original hash value &add ("eax",5); # compare to modulus &movd ($D1,"ebx"); &adc ("ebx",0); &movd ($D2,"ecx"); &adc ("ecx",0); &movd ($D3,"edx"); &adc ("edx",0); &adc ("esi",0); &shr ("esi",2); # did it carry/borrow? &neg ("esi"); # do we choose (hash-modulus) ... &and ("eax","esi"); &and ("ebx","esi"); &and ("ecx","esi"); &and ("edx","esi"); &mov (&DWP(4*0,"edi"),"eax"); &movd ("eax",$D0); &mov (&DWP(4*1,"edi"),"ebx"); &movd ("ebx",$D1); &mov (&DWP(4*2,"edi"),"ecx"); &movd ("ecx",$D2); &mov (&DWP(4*3,"edi"),"edx"); &movd ("edx",$D3); ¬ ("esi"); # ... or original hash value? &and ("eax","esi"); &and ("ebx","esi"); &or ("eax",&DWP(4*0,"edi")); &and ("ecx","esi"); &or ("ebx",&DWP(4*1,"edi")); &and ("edx","esi"); &or ("ecx",&DWP(4*2,"edi")); &or ("edx",&DWP(4*3,"edi")); &add ("eax",&DWP(4*0,"ebp")); # accumulate key &adc ("ebx",&DWP(4*1,"ebp")); &mov (&DWP(4*0,"edi"),"eax"); &adc ("ecx",&DWP(4*2,"ebp")); &mov (&DWP(4*1,"edi"),"ebx"); &adc ("edx",&DWP(4*3,"ebp")); &mov (&DWP(4*2,"edi"),"ecx"); &mov (&DWP(4*3,"edi"),"edx"); &function_end("_poly1305_emit_sse2"); if ($avx>1) { ######################################################################## # Note that poly1305_init_avx2 operates on %xmm, I could have used # poly1305_init_sse2... &align (32); &function_begin_B("_poly1305_init_avx2"); &vmovdqu ($D4,&QWP(4*6,"edi")); # key base 2^32 &lea ("edi",&DWP(16*3,"edi")); # size optimization &mov ("ebp","esp"); &sub ("esp",16*(9+5)); &and ("esp",-16); #&vpand ($D4,$D4,&QWP(96,"ebx")); # magic mask &vmovdqa ($MASK,&QWP(64,"ebx")); &vpand ($D0,$D4,$MASK); # -> base 2^26 &vpsrlq ($D1,$D4,26); &vpsrldq ($D3,$D4,6); &vpand ($D1,$D1,$MASK); &vpsrlq ($D2,$D3,4) &vpsrlq ($D3,$D3,30); &vpand ($D2,$D2,$MASK); &vpand ($D3,$D3,$MASK); &vpsrldq ($D4,$D4,13); &lea ("edx",&DWP(16*9,"esp")); # size optimization &mov ("ecx",2); &set_label("square"); &vmovdqa (&QWP(16*0,"esp"),$D0); &vmovdqa (&QWP(16*1,"esp"),$D1); &vmovdqa (&QWP(16*2,"esp"),$D2); &vmovdqa (&QWP(16*3,"esp"),$D3); &vmovdqa (&QWP(16*4,"esp"),$D4); &vpslld ($T1,$D1,2); &vpslld ($T0,$D2,2); &vpaddd ($T1,$T1,$D1); # *5 &vpaddd ($T0,$T0,$D2); # *5 &vmovdqa (&QWP(16*5,"esp"),$T1); &vmovdqa (&QWP(16*6,"esp"),$T0); &vpslld ($T1,$D3,2); &vpslld ($T0,$D4,2); &vpaddd ($T1,$T1,$D3); # *5 &vpaddd ($T0,$T0,$D4); # *5 &vmovdqa (&QWP(16*7,"esp"),$T1); &vmovdqa (&QWP(16*8,"esp"),$T0); &vpshufd ($T0,$D0,0b01000100); &vmovdqa ($T1,$D1); &vpshufd ($D1,$D1,0b01000100); &vpshufd ($D2,$D2,0b01000100); &vpshufd ($D3,$D3,0b01000100); &vpshufd ($D4,$D4,0b01000100); &vmovdqa (&QWP(16*0,"edx"),$T0); &vmovdqa (&QWP(16*1,"edx"),$D1); &vmovdqa (&QWP(16*2,"edx"),$D2); &vmovdqa (&QWP(16*3,"edx"),$D3); &vmovdqa (&QWP(16*4,"edx"),$D4); ################################################################ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 &vpmuludq ($D4,$D4,$D0); # h4*r0 &vpmuludq ($D3,$D3,$D0); # h3*r0 &vpmuludq ($D2,$D2,$D0); # h2*r0 &vpmuludq ($D1,$D1,$D0); # h1*r0 &vpmuludq ($D0,$T0,$D0); # h0*r0 &vpmuludq ($T0,$T1,&QWP(16*3,"edx")); # r1*h3 &vpaddq ($D4,$D4,$T0); &vpmuludq ($T2,$T1,&QWP(16*2,"edx")); # r1*h2 &vpaddq ($D3,$D3,$T2); &vpmuludq ($T0,$T1,&QWP(16*1,"edx")); # r1*h1 &vpaddq ($D2,$D2,$T0); &vmovdqa ($T2,&QWP(16*5,"esp")); # s1 &vpmuludq ($T1,$T1,&QWP(16*0,"edx")); # r1*h0 &vpaddq ($D1,$D1,$T1); &vmovdqa ($T0,&QWP(16*2,"esp")); # r2 &vpmuludq ($T2,$T2,&QWP(16*4,"edx")); # s1*h4 &vpaddq ($D0,$D0,$T2); &vpmuludq ($T1,$T0,&QWP(16*2,"edx")); # r2*h2 &vpaddq ($D4,$D4,$T1); &vpmuludq ($T2,$T0,&QWP(16*1,"edx")); # r2*h1 &vpaddq ($D3,$D3,$T2); &vmovdqa ($T1,&QWP(16*6,"esp")); # s2 &vpmuludq ($T0,$T0,&QWP(16*0,"edx")); # r2*h0 &vpaddq ($D2,$D2,$T0); &vpmuludq ($T2,$T1,&QWP(16*4,"edx")); # s2*h4 &vpaddq ($D1,$D1,$T2); &vmovdqa ($T0,&QWP(16*3,"esp")); # r3 &vpmuludq ($T1,$T1,&QWP(16*3,"edx")); # s2*h3 &vpaddq ($D0,$D0,$T1); &vpmuludq ($T2,$T0,&QWP(16*1,"edx")); # r3*h1 &vpaddq ($D4,$D4,$T2); &vmovdqa ($T1,&QWP(16*7,"esp")); # s3 &vpmuludq ($T0,$T0,&QWP(16*0,"edx")); # r3*h0 &vpaddq ($D3,$D3,$T0); &vpmuludq ($T2,$T1,&QWP(16*4,"edx")); # s3*h4 &vpaddq ($D2,$D2,$T2); &vpmuludq ($T0,$T1,&QWP(16*3,"edx")); # s3*h3 &vpaddq ($D1,$D1,$T0); &vmovdqa ($T2,&QWP(16*4,"esp")); # r4 &vpmuludq ($T1,$T1,&QWP(16*2,"edx")); # s3*h2 &vpaddq ($D0,$D0,$T1); &vmovdqa ($T0,&QWP(16*8,"esp")); # s4 &vpmuludq ($T2,$T2,&QWP(16*0,"edx")); # r4*h0 &vpaddq ($D4,$D4,$T2); &vpmuludq ($T1,$T0,&QWP(16*4,"edx")); # s4*h4 &vpaddq ($D3,$D3,$T1); &vpmuludq ($T2,$T0,&QWP(16*1,"edx")); # s4*h1 &vpaddq ($D0,$D0,$T2); &vpmuludq ($T1,$T0,&QWP(16*2,"edx")); # s4*h2 &vpaddq ($D1,$D1,$T1); &vmovdqa ($MASK,&QWP(64,"ebx")); &vpmuludq ($T0,$T0,&QWP(16*3,"edx")); # s4*h3 &vpaddq ($D2,$D2,$T0); ################################################################ # lazy reduction &vpsrlq ($T0,$D3,26); &vpand ($D3,$D3,$MASK); &vpsrlq ($T1,$D0,26); &vpand ($D0,$D0,$MASK); &vpaddq ($D4,$D4,$T0); # h3 -> h4 &vpaddq ($D1,$D1,$T1); # h0 -> h1 &vpsrlq ($T0,$D4,26); &vpand ($D4,$D4,$MASK); &vpsrlq ($T1,$D1,26); &vpand ($D1,$D1,$MASK); &vpaddq ($D2,$D2,$T1); # h1 -> h2 &vpaddd ($D0,$D0,$T0); &vpsllq ($T0,$T0,2); &vpsrlq ($T1,$D2,26); &vpand ($D2,$D2,$MASK); &vpaddd ($D0,$D0,$T0); # h4 -> h0 &vpaddd ($D3,$D3,$T1); # h2 -> h3 &vpsrlq ($T1,$D3,26); &vpsrlq ($T0,$D0,26); &vpand ($D0,$D0,$MASK); &vpand ($D3,$D3,$MASK); &vpaddd ($D1,$D1,$T0); # h0 -> h1 &vpaddd ($D4,$D4,$T1); # h3 -> h4 &dec ("ecx"); &jz (&label("square_break")); &vpunpcklqdq ($D0,$D0,&QWP(16*0,"esp")); # 0:r^1:0:r^2 &vpunpcklqdq ($D1,$D1,&QWP(16*1,"esp")); &vpunpcklqdq ($D2,$D2,&QWP(16*2,"esp")); &vpunpcklqdq ($D3,$D3,&QWP(16*3,"esp")); &vpunpcklqdq ($D4,$D4,&QWP(16*4,"esp")); &jmp (&label("square")); &set_label("square_break"); &vpsllq ($D0,$D0,32); # -> r^3:0:r^4:0 &vpsllq ($D1,$D1,32); &vpsllq ($D2,$D2,32); &vpsllq ($D3,$D3,32); &vpsllq ($D4,$D4,32); &vpor ($D0,$D0,&QWP(16*0,"esp")); # r^3:r^1:r^4:r^2 &vpor ($D1,$D1,&QWP(16*1,"esp")); &vpor ($D2,$D2,&QWP(16*2,"esp")); &vpor ($D3,$D3,&QWP(16*3,"esp")); &vpor ($D4,$D4,&QWP(16*4,"esp")); &vpshufd ($D0,$D0,0b10001101); # -> r^1:r^2:r^3:r^4 &vpshufd ($D1,$D1,0b10001101); &vpshufd ($D2,$D2,0b10001101); &vpshufd ($D3,$D3,0b10001101); &vpshufd ($D4,$D4,0b10001101); &vmovdqu (&QWP(16*0,"edi"),$D0); # save the table &vmovdqu (&QWP(16*1,"edi"),$D1); &vmovdqu (&QWP(16*2,"edi"),$D2); &vmovdqu (&QWP(16*3,"edi"),$D3); &vmovdqu (&QWP(16*4,"edi"),$D4); &vpslld ($T1,$D1,2); &vpslld ($T0,$D2,2); &vpaddd ($T1,$T1,$D1); # *5 &vpaddd ($T0,$T0,$D2); # *5 &vmovdqu (&QWP(16*5,"edi"),$T1); &vmovdqu (&QWP(16*6,"edi"),$T0); &vpslld ($T1,$D3,2); &vpslld ($T0,$D4,2); &vpaddd ($T1,$T1,$D3); # *5 &vpaddd ($T0,$T0,$D4); # *5 &vmovdqu (&QWP(16*7,"edi"),$T1); &vmovdqu (&QWP(16*8,"edi"),$T0); &mov ("esp","ebp"); &lea ("edi",&DWP(-16*3,"edi")); # size de-optimization &ret (); &function_end_B("_poly1305_init_avx2"); ######################################################################## # now it's time to switch to %ymm my ($D0,$D1,$D2,$D3,$D4,$T0,$T1,$T2)=map("ymm$_",(0..7)); my $MASK=$T2; sub X { my $reg=shift; $reg=~s/^ymm/xmm/; $reg; } &align (32); &function_begin("_poly1305_blocks_avx2"); &mov ("edi",&wparam(0)); # ctx &mov ("esi",&wparam(1)); # inp &mov ("ecx",&wparam(2)); # len &mov ("eax",&DWP(4*5,"edi")); # is_base2_26 &and ("ecx",-16); &jz (&label("nodata")); &cmp ("ecx",64); &jae (&label("enter_avx2")); &test ("eax","eax"); # is_base2_26? &jz (&label("enter_blocks")); &set_label("enter_avx2"); &vzeroupper (); &call (&label("pic_point")); &set_label("pic_point"); &blindpop("ebx"); &lea ("ebx",&DWP(&label("const_sse2")."-".&label("pic_point"),"ebx")); &test ("eax","eax"); # is_base2_26? &jnz (&label("base2_26")); &call ("_poly1305_init_avx2"); ################################################# base 2^32 -> base 2^26 &mov ("eax",&DWP(0,"edi")); &mov ("ecx",&DWP(3,"edi")); &mov ("edx",&DWP(6,"edi")); &mov ("esi",&DWP(9,"edi")); &mov ("ebp",&DWP(13,"edi")); &shr ("ecx",2); &and ("eax",0x3ffffff); &shr ("edx",4); &and ("ecx",0x3ffffff); &shr ("esi",6); &and ("edx",0x3ffffff); &mov (&DWP(4*0,"edi"),"eax"); &mov (&DWP(4*1,"edi"),"ecx"); &mov (&DWP(4*2,"edi"),"edx"); &mov (&DWP(4*3,"edi"),"esi"); &mov (&DWP(4*4,"edi"),"ebp"); &mov (&DWP(4*5,"edi"),1); # is_base2_26 &mov ("esi",&wparam(1)); # [reload] inp &mov ("ecx",&wparam(2)); # [reload] len &set_label("base2_26"); &mov ("eax",&wparam(3)); # padbit &mov ("ebp","esp"); &sub ("esp",32*(5+9)); &and ("esp",-512); # ensure that frame # doesn't cross page # boundary, which is # essential for # misaligned 32-byte # loads ################################################################ # expand and copy pre-calculated table to stack &vmovdqu (&X($D0),&QWP(16*(3+0),"edi")); &lea ("edx",&DWP(32*5+128,"esp")); # +128 size optimization &vmovdqu (&X($D1),&QWP(16*(3+1),"edi")); &vmovdqu (&X($D2),&QWP(16*(3+2),"edi")); &vmovdqu (&X($D3),&QWP(16*(3+3),"edi")); &vmovdqu (&X($D4),&QWP(16*(3+4),"edi")); &lea ("edi",&DWP(16*3,"edi")); # size optimization &vpermq ($D0,$D0,0b01000000); # 00001234 -> 12343434 &vpermq ($D1,$D1,0b01000000); &vpermq ($D2,$D2,0b01000000); &vpermq ($D3,$D3,0b01000000); &vpermq ($D4,$D4,0b01000000); &vpshufd ($D0,$D0,0b11001000); # 12343434 -> 14243444 &vpshufd ($D1,$D1,0b11001000); &vpshufd ($D2,$D2,0b11001000); &vpshufd ($D3,$D3,0b11001000); &vpshufd ($D4,$D4,0b11001000); &vmovdqa (&QWP(32*0-128,"edx"),$D0); &vmovdqu (&X($D0),&QWP(16*5,"edi")); &vmovdqa (&QWP(32*1-128,"edx"),$D1); &vmovdqu (&X($D1),&QWP(16*6,"edi")); &vmovdqa (&QWP(32*2-128,"edx"),$D2); &vmovdqu (&X($D2),&QWP(16*7,"edi")); &vmovdqa (&QWP(32*3-128,"edx"),$D3); &vmovdqu (&X($D3),&QWP(16*8,"edi")); &vmovdqa (&QWP(32*4-128,"edx"),$D4); &vpermq ($D0,$D0,0b01000000); &vpermq ($D1,$D1,0b01000000); &vpermq ($D2,$D2,0b01000000); &vpermq ($D3,$D3,0b01000000); &vpshufd ($D0,$D0,0b11001000); &vpshufd ($D1,$D1,0b11001000); &vpshufd ($D2,$D2,0b11001000); &vpshufd ($D3,$D3,0b11001000); &vmovdqa (&QWP(32*5-128,"edx"),$D0); &vmovd (&X($D0),&DWP(-16*3+4*0,"edi"));# load hash value &vmovdqa (&QWP(32*6-128,"edx"),$D1); &vmovd (&X($D1),&DWP(-16*3+4*1,"edi")); &vmovdqa (&QWP(32*7-128,"edx"),$D2); &vmovd (&X($D2),&DWP(-16*3+4*2,"edi")); &vmovdqa (&QWP(32*8-128,"edx"),$D3); &vmovd (&X($D3),&DWP(-16*3+4*3,"edi")); &vmovd (&X($D4),&DWP(-16*3+4*4,"edi")); &vmovdqa ($MASK,&QWP(64,"ebx")); &neg ("eax"); # padbit &test ("ecx",63); &jz (&label("even")); &mov ("edx","ecx"); &and ("ecx",-64); &and ("edx",63); &vmovdqu (&X($T0),&QWP(16*0,"esi")); &cmp ("edx",32); &jb (&label("one")); &vmovdqu (&X($T1),&QWP(16*1,"esi")); &je (&label("two")); &vinserti128 ($T0,$T0,&QWP(16*2,"esi"),1); &lea ("esi",&DWP(16*3,"esi")); &lea ("ebx",&DWP(8,"ebx")); # three padbits &lea ("edx",&DWP(32*5+128+8,"esp")); # --:r^1:r^2:r^3 (*) &jmp (&label("tail")); &set_label("two"); &lea ("esi",&DWP(16*2,"esi")); &lea ("ebx",&DWP(16,"ebx")); # two padbits &lea ("edx",&DWP(32*5+128+16,"esp"));# --:--:r^1:r^2 (*) &jmp (&label("tail")); &set_label("one"); &lea ("esi",&DWP(16*1,"esi")); &vpxor ($T1,$T1,$T1); &lea ("ebx",&DWP(32,"ebx","eax",8)); # one or no padbits &lea ("edx",&DWP(32*5+128+24,"esp"));# --:--:--:r^1 (*) &jmp (&label("tail")); # (*) spots marked with '--' are data from next table entry, but they # are multiplied by 0 and therefore rendered insignificant &set_label("even",32); &vmovdqu (&X($T0),&QWP(16*0,"esi")); # load input &vmovdqu (&X($T1),&QWP(16*1,"esi")); &vinserti128 ($T0,$T0,&QWP(16*2,"esi"),1); &vinserti128 ($T1,$T1,&QWP(16*3,"esi"),1); &lea ("esi",&DWP(16*4,"esi")); &sub ("ecx",64); &jz (&label("tail")); &set_label("loop"); ################################################################ # ((inp[0]*r^4+r[4])*r^4+r[8])*r^4 # ((inp[1]*r^4+r[5])*r^4+r[9])*r^3 # ((inp[2]*r^4+r[6])*r^4+r[10])*r^2 # ((inp[3]*r^4+r[7])*r^4+r[11])*r^1 # \________/ \_______/ ################################################################ sub vsplat_input { &vmovdqa (&QWP(32*2,"esp"),$D2); &vpsrldq ($D2,$T0,6); # splat input &vmovdqa (&QWP(32*0,"esp"),$D0); &vpsrldq ($D0,$T1,6); &vmovdqa (&QWP(32*1,"esp"),$D1); &vpunpckhqdq ($D1,$T0,$T1); # 4 &vpunpcklqdq ($T0,$T0,$T1); # 0:1 &vpunpcklqdq ($D2,$D2,$D0); # 2:3 &vpsrlq ($D0,$D2,30); &vpsrlq ($D2,$D2,4); &vpsrlq ($T1,$T0,26); &vpsrlq ($D1,$D1,40); # 4 &vpand ($D2,$D2,$MASK); # 2 &vpand ($T0,$T0,$MASK); # 0 &vpand ($T1,$T1,$MASK); # 1 &vpand ($D0,$D0,$MASK); # 3 (*) &vpor ($D1,$D1,&QWP(0,"ebx")); # padbit, yes, always # (*) note that output is counterintuitive, inp[3:4] is # returned in $D1-2, while $D3-4 are preserved; } &vsplat_input (); sub vpmuladd { my $addr = shift; &vpaddq ($D2,$D2,&QWP(32*2,"esp")); # add hash value &vpaddq ($T0,$T0,&QWP(32*0,"esp")); &vpaddq ($T1,$T1,&QWP(32*1,"esp")); &vpaddq ($D0,$D0,$D3); &vpaddq ($D1,$D1,$D4); ################################################################ # d3 = h2*r1 + h0*r3 + h1*r2 + h3*r0 + h4*5*r4 # d4 = h2*r2 + h0*r4 + h1*r3 + h3*r1 + h4*r0 # d0 = h2*5*r3 + h0*r0 + h1*5*r4 + h3*5*r2 + h4*5*r1 # d1 = h2*5*r4 + h0*r1 + h1*r0 + h3*5*r3 + h4*5*r2 # d2 = h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3 &vpmuludq ($D3,$D2,&$addr(1)); # d3 = h2*r1 &vmovdqa (QWP(32*1,"esp"),$T1); &vpmuludq ($D4,$D2,&$addr(2)); # d4 = h2*r2 &vmovdqa (QWP(32*3,"esp"),$D0); &vpmuludq ($D0,$D2,&$addr(7)); # d0 = h2*s3 &vmovdqa (QWP(32*4,"esp"),$D1); &vpmuludq ($D1,$D2,&$addr(8)); # d1 = h2*s4 &vpmuludq ($D2,$D2,&$addr(0)); # d2 = h2*r0 &vpmuludq ($T2,$T0,&$addr(3)); # h0*r3 &vpaddq ($D3,$D3,$T2); # d3 += h0*r3 &vpmuludq ($T1,$T0,&$addr(4)); # h0*r4 &vpaddq ($D4,$D4,$T1); # d4 + h0*r4 &vpmuludq ($T2,$T0,&$addr(0)); # h0*r0 &vpaddq ($D0,$D0,$T2); # d0 + h0*r0 &vmovdqa ($T2,&QWP(32*1,"esp")); # h1 &vpmuludq ($T1,$T0,&$addr(1)); # h0*r1 &vpaddq ($D1,$D1,$T1); # d1 += h0*r1 &vpmuludq ($T0,$T0,&$addr(2)); # h0*r2 &vpaddq ($D2,$D2,$T0); # d2 += h0*r2 &vpmuludq ($T1,$T2,&$addr(2)); # h1*r2 &vpaddq ($D3,$D3,$T1); # d3 += h1*r2 &vpmuludq ($T0,$T2,&$addr(3)); # h1*r3 &vpaddq ($D4,$D4,$T0); # d4 += h1*r3 &vpmuludq ($T1,$T2,&$addr(8)); # h1*s4 &vpaddq ($D0,$D0,$T1); # d0 += h1*s4 &vmovdqa ($T1,&QWP(32*3,"esp")); # h3 &vpmuludq ($T0,$T2,&$addr(0)); # h1*r0 &vpaddq ($D1,$D1,$T0); # d1 += h1*r0 &vpmuludq ($T2,$T2,&$addr(1)); # h1*r1 &vpaddq ($D2,$D2,$T2); # d2 += h1*r1 &vpmuludq ($T0,$T1,&$addr(0)); # h3*r0 &vpaddq ($D3,$D3,$T0); # d3 += h3*r0 &vpmuludq ($T2,$T1,&$addr(1)); # h3*r1 &vpaddq ($D4,$D4,$T2); # d4 += h3*r1 &vpmuludq ($T0,$T1,&$addr(6)); # h3*s2 &vpaddq ($D0,$D0,$T0); # d0 += h3*s2 &vmovdqa ($T0,&QWP(32*4,"esp")); # h4 &vpmuludq ($T2,$T1,&$addr(7)); # h3*s3 &vpaddq ($D1,$D1,$T2); # d1+= h3*s3 &vpmuludq ($T1,$T1,&$addr(8)); # h3*s4 &vpaddq ($D2,$D2,$T1); # d2 += h3*s4 &vpmuludq ($T2,$T0,&$addr(8)); # h4*s4 &vpaddq ($D3,$D3,$T2); # d3 += h4*s4 &vpmuludq ($T1,$T0,&$addr(5)); # h4*s1 &vpaddq ($D0,$D0,$T1); # d0 += h4*s1 &vpmuludq ($T2,$T0,&$addr(0)); # h4*r0 &vpaddq ($D4,$D4,$T2); # d4 += h4*r0 &vmovdqa ($MASK,&QWP(64,"ebx")); &vpmuludq ($T1,$T0,&$addr(6)); # h4*s2 &vpaddq ($D1,$D1,$T1); # d1 += h4*s2 &vpmuludq ($T0,$T0,&$addr(7)); # h4*s3 &vpaddq ($D2,$D2,$T0); # d2 += h4*s3 } &vpmuladd (sub { my $i=shift; &QWP(32*$i-128,"edx"); }); sub vlazy_reduction { ################################################################ # lazy reduction &vpsrlq ($T0,$D3,26); &vpand ($D3,$D3,$MASK); &vpsrlq ($T1,$D0,26); &vpand ($D0,$D0,$MASK); &vpaddq ($D4,$D4,$T0); # h3 -> h4 &vpaddq ($D1,$D1,$T1); # h0 -> h1 &vpsrlq ($T0,$D4,26); &vpand ($D4,$D4,$MASK); &vpsrlq ($T1,$D1,26); &vpand ($D1,$D1,$MASK); &vpaddq ($D2,$D2,$T1); # h1 -> h2 &vpaddq ($D0,$D0,$T0); &vpsllq ($T0,$T0,2); &vpsrlq ($T1,$D2,26); &vpand ($D2,$D2,$MASK); &vpaddq ($D0,$D0,$T0); # h4 -> h0 &vpaddq ($D3,$D3,$T1); # h2 -> h3 &vpsrlq ($T1,$D3,26); &vpsrlq ($T0,$D0,26); &vpand ($D0,$D0,$MASK); &vpand ($D3,$D3,$MASK); &vpaddq ($D1,$D1,$T0); # h0 -> h1 &vpaddq ($D4,$D4,$T1); # h3 -> h4 } &vlazy_reduction(); &vmovdqu (&X($T0),&QWP(16*0,"esi")); # load input &vmovdqu (&X($T1),&QWP(16*1,"esi")); &vinserti128 ($T0,$T0,&QWP(16*2,"esi"),1); &vinserti128 ($T1,$T1,&QWP(16*3,"esi"),1); &lea ("esi",&DWP(16*4,"esi")); &sub ("ecx",64); &jnz (&label("loop")); &set_label("tail"); &vsplat_input (); &and ("ebx",-64); # restore pointer &vpmuladd (sub { my $i=shift; &QWP(4+32*$i-128,"edx"); }); ################################################################ # horizontal addition &vpsrldq ($T0,$D4,8); &vpsrldq ($T1,$D3,8); &vpaddq ($D4,$D4,$T0); &vpsrldq ($T0,$D0,8); &vpaddq ($D3,$D3,$T1); &vpsrldq ($T1,$D1,8); &vpaddq ($D0,$D0,$T0); &vpsrldq ($T0,$D2,8); &vpaddq ($D1,$D1,$T1); &vpermq ($T1,$D4,2); # keep folding &vpaddq ($D2,$D2,$T0); &vpermq ($T0,$D3,2); &vpaddq ($D4,$D4,$T1); &vpermq ($T1,$D0,2); &vpaddq ($D3,$D3,$T0); &vpermq ($T0,$D1,2); &vpaddq ($D0,$D0,$T1); &vpermq ($T1,$D2,2); &vpaddq ($D1,$D1,$T0); &vpaddq ($D2,$D2,$T1); &vlazy_reduction(); &cmp ("ecx",0); &je (&label("done")); ################################################################ # clear all but single word &vpshufd (&X($D0),&X($D0),0b11111100); &lea ("edx",&DWP(32*5+128,"esp")); # restore pointer &vpshufd (&X($D1),&X($D1),0b11111100); &vpshufd (&X($D2),&X($D2),0b11111100); &vpshufd (&X($D3),&X($D3),0b11111100); &vpshufd (&X($D4),&X($D4),0b11111100); &jmp (&label("even")); &set_label("done",16); &vmovd (&DWP(-16*3+4*0,"edi"),&X($D0));# store hash value &vmovd (&DWP(-16*3+4*1,"edi"),&X($D1)); &vmovd (&DWP(-16*3+4*2,"edi"),&X($D2)); &vmovd (&DWP(-16*3+4*3,"edi"),&X($D3)); &vmovd (&DWP(-16*3+4*4,"edi"),&X($D4)); &vzeroupper (); &mov ("esp","ebp"); &set_label("nodata"); &function_end("_poly1305_blocks_avx2"); } &set_label("const_sse2",64); &data_word(1<<24,0, 1<<24,0, 1<<24,0, 1<<24,0); &data_word(0,0, 0,0, 0,0, 0,0); &data_word(0x03ffffff,0,0x03ffffff,0, 0x03ffffff,0, 0x03ffffff,0); &data_word(0x0fffffff,0x0ffffffc,0x0ffffffc,0x0ffffffc); } &asciz ("Poly1305 for x86, CRYPTOGAMS by "); &align (4); &asm_finish(); close STDOUT or die "error closing STDOUT: $!"; tboot-1.10.5/tboot/common/poly1305/poly1305.c0000644000000000000000000004034414210363175016435 0ustar 00000000000000/* * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include #include "poly1305.h" extern void OPENSSL_cleanse(void *ptr, size_t len); extern uint64_t OPENSSL_ia32_cpuid(unsigned int *); extern unsigned int OPENSSL_ia32cap_P[4]; void OPENSSL_cpuid_setup(void) { uint64_t vec; vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P); OPENSSL_ia32cap_P[0] = (unsigned int)vec | (1 << 10); OPENSSL_ia32cap_P[1] = (unsigned int)(vec >> 32); } size_t Poly1305_ctx_size(void) { return sizeof(struct poly1305_context); } /* pick 32-bit unsigned integer in little endian order */ static unsigned int U8TOU32(const unsigned char *p) { return (((unsigned int)(p[0] & 0xff)) | ((unsigned int)(p[1] & 0xff) << 8) | ((unsigned int)(p[2] & 0xff) << 16) | ((unsigned int)(p[3] & 0xff) << 24)); } /* * Implementations can be classified by amount of significant bits in * words making up the multi-precision value, or in other words radix * or base of numerical representation, e.g. base 2^64, base 2^32, * base 2^26. Complementary characteristic is how wide is the result of * multiplication of pair of digits, e.g. it would take 128 bits to * accommodate multiplication result in base 2^64 case. These are used * interchangeably. To describe implementation that is. But interface * is designed to isolate this so that low-level primitives implemented * in assembly can be self-contained/self-coherent. */ #ifndef POLY1305_ASM /* * Even though there is __int128 reference implementation targeting * 64-bit platforms provided below, it's not obvious that it's optimal * choice for every one of them. Depending on instruction set overall * amount of instructions can be comparable to one in __int64 * implementation. Amount of multiplication instructions would be lower, * but not necessarily overall. And in out-of-order execution context, * it is the latter that can be crucial... * * On related note. Poly1305 author, D. J. Bernstein, discusses and * provides floating-point implementations of the algorithm in question. * It made a lot of sense by the time of introduction, because most * then-modern processors didn't have pipelined integer multiplier. * [Not to mention that some had non-constant timing for integer * multiplications.] Floating-point instructions on the other hand could * be issued every cycle, which allowed to achieve better performance. * Nowadays, with SIMD and/or out-or-order execution, shared or * even emulated FPU, it's more complicated, and floating-point * implementation is not necessarily optimal choice in every situation, * rather contrary... * * */ typedef unsigned int u32; /* * poly1305_blocks processes a multiple of POLY1305_BLOCK_SIZE blocks * of |inp| no longer than |len|. Behaviour for |len| not divisible by * block size is unspecified in general case, even though in reference * implementation the trailing chunk is simply ignored. Per algorithm * specification, every input block, complete or last partial, is to be * padded with a bit past most significant byte. The latter kind is then * padded with zeros till block size. This last partial block padding * is caller(*)'s responsibility, and because of this the last partial * block is always processed with separate call with |len| set to * POLY1305_BLOCK_SIZE and |padbit| to 0. In all other cases |padbit| * should be set to 1 to perform implicit padding with 128th bit. * poly1305_blocks does not actually check for this constraint though, * it's caller(*)'s responsibility to comply. * * (*) In the context "caller" is not application code, but higher * level Poly1305_* from this very module, so that quirks are * handled locally. */ static void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, u32 padbit); /* * Type-agnostic "rip-off" from constant_time.h */ # define CONSTANT_TIME_CARRY(a,b) ( \ (a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1) \ ) # if (defined(__SIZEOF_INT128__) && __SIZEOF_INT128__==16) && \ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__==8) typedef unsigned long u64; typedef __uint128_t u128; typedef struct { u64 h[3]; u64 r[2]; } poly1305_internal; /* pick 32-bit unsigned integer in little endian order */ static u64 U8TOU64(const unsigned char *p) { return (((u64)(p[0] & 0xff)) | ((u64)(p[1] & 0xff) << 8) | ((u64)(p[2] & 0xff) << 16) | ((u64)(p[3] & 0xff) << 24) | ((u64)(p[4] & 0xff) << 32) | ((u64)(p[5] & 0xff) << 40) | ((u64)(p[6] & 0xff) << 48) | ((u64)(p[7] & 0xff) << 56)); } /* store a 32-bit unsigned integer in little endian */ static void U64TO8(unsigned char *p, u64 v) { p[0] = (unsigned char)((v) & 0xff); p[1] = (unsigned char)((v >> 8) & 0xff); p[2] = (unsigned char)((v >> 16) & 0xff); p[3] = (unsigned char)((v >> 24) & 0xff); p[4] = (unsigned char)((v >> 32) & 0xff); p[5] = (unsigned char)((v >> 40) & 0xff); p[6] = (unsigned char)((v >> 48) & 0xff); p[7] = (unsigned char)((v >> 56) & 0xff); } static void poly1305_init(void *ctx, const unsigned char key[16]) { poly1305_internal *st = (poly1305_internal *) ctx; /* h = 0 */ st->h[0] = 0; st->h[1] = 0; st->h[2] = 0; /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ st->r[0] = U8TOU64(&key[0]) & 0x0ffffffc0fffffff; st->r[1] = U8TOU64(&key[8]) & 0x0ffffffc0ffffffc; } static void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, u32 padbit) { poly1305_internal *st = (poly1305_internal *)ctx; u64 r0, r1; u64 s1; u64 h0, h1, h2, c; u128 d0, d1; r0 = st->r[0]; r1 = st->r[1]; s1 = r1 + (r1 >> 2); h0 = st->h[0]; h1 = st->h[1]; h2 = st->h[2]; while (len >= POLY1305_BLOCK_SIZE) { /* h += m[i] */ h0 = (u64)(d0 = (u128)h0 + U8TOU64(inp + 0)); h1 = (u64)(d1 = (u128)h1 + (d0 >> 64) + U8TOU64(inp + 8)); /* * padbit can be zero only when original len was * POLY1306_BLOCK_SIZE, but we don't check */ h2 += (u64)(d1 >> 64) + padbit; /* h *= r "%" p, where "%" stands for "partial remainder" */ d0 = ((u128)h0 * r0) + ((u128)h1 * s1); d1 = ((u128)h0 * r1) + ((u128)h1 * r0) + (h2 * s1); h2 = (h2 * r0); /* last reduction step: */ /* a) h2:h0 = h2<<128 + d1<<64 + d0 */ h0 = (u64)d0; h1 = (u64)(d1 += d0 >> 64); h2 += (u64)(d1 >> 64); /* b) (h2:h0 += (h2:h0>>130) * 5) %= 2^130 */ c = (h2 >> 2) + (h2 & ~3UL); h2 &= 3; h0 += c; h1 += (c = CONSTANT_TIME_CARRY(h0,c)); h2 += CONSTANT_TIME_CARRY(h1,c); /* * Occasional overflows to 3rd bit of h2 are taken care of * "naturally". If after this point we end up at the top of * this loop, then the overflow bit will be accounted for * in next iteration. If we end up in poly1305_emit, then * comparison to modulus below will still count as "carry * into 131st bit", so that properly reduced value will be * picked in conditional move. */ inp += POLY1305_BLOCK_SIZE; len -= POLY1305_BLOCK_SIZE; } st->h[0] = h0; st->h[1] = h1; st->h[2] = h2; } static void poly1305_emit(void *ctx, unsigned char mac[16], const u32 nonce[4]) { poly1305_internal *st = (poly1305_internal *) ctx; u64 h0, h1, h2; u64 g0, g1, g2; u128 t; u64 mask; h0 = st->h[0]; h1 = st->h[1]; h2 = st->h[2]; /* compare to modulus by computing h + -p */ g0 = (u64)(t = (u128)h0 + 5); g1 = (u64)(t = (u128)h1 + (t >> 64)); g2 = h2 + (u64)(t >> 64); /* if there was carry into 131st bit, h1:h0 = g1:g0 */ mask = 0 - (g2 >> 2); g0 &= mask; g1 &= mask; mask = ~mask; h0 = (h0 & mask) | g0; h1 = (h1 & mask) | g1; /* mac = (h + nonce) % (2^128) */ h0 = (u64)(t = (u128)h0 + nonce[0] + ((u64)nonce[1]<<32)); h1 = (u64)(t = (u128)h1 + nonce[2] + ((u64)nonce[3]<<32) + (t >> 64)); U64TO8(mac + 0, h0); U64TO8(mac + 8, h1); } # else # if defined(_WIN32) && !defined(__MINGW32__) typedef unsigned __int64 u64; # elif defined(__arch64__) typedef unsigned long u64; # else typedef unsigned long long u64; # endif typedef struct { u32 h[5]; u32 r[4]; } poly1305_internal; /* store a 32-bit unsigned integer in little endian */ static void U32TO8(unsigned char *p, unsigned int v) { p[0] = (unsigned char)((v) & 0xff); p[1] = (unsigned char)((v >> 8) & 0xff); p[2] = (unsigned char)((v >> 16) & 0xff); p[3] = (unsigned char)((v >> 24) & 0xff); } static void poly1305_init(void *ctx, const unsigned char key[16]) { poly1305_internal *st = (poly1305_internal *) ctx; /* h = 0 */ st->h[0] = 0; st->h[1] = 0; st->h[2] = 0; st->h[3] = 0; st->h[4] = 0; /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ st->r[0] = U8TOU32(&key[0]) & 0x0fffffff; st->r[1] = U8TOU32(&key[4]) & 0x0ffffffc; st->r[2] = U8TOU32(&key[8]) & 0x0ffffffc; st->r[3] = U8TOU32(&key[12]) & 0x0ffffffc; } static void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, u32 padbit) { poly1305_internal *st = (poly1305_internal *)ctx; u32 r0, r1, r2, r3; u32 s1, s2, s3; u32 h0, h1, h2, h3, h4, c; u64 d0, d1, d2, d3; r0 = st->r[0]; r1 = st->r[1]; r2 = st->r[2]; r3 = st->r[3]; s1 = r1 + (r1 >> 2); s2 = r2 + (r2 >> 2); s3 = r3 + (r3 >> 2); h0 = st->h[0]; h1 = st->h[1]; h2 = st->h[2]; h3 = st->h[3]; h4 = st->h[4]; while (len >= POLY1305_BLOCK_SIZE) { /* h += m[i] */ h0 = (u32)(d0 = (u64)h0 + U8TOU32(inp + 0)); h1 = (u32)(d1 = (u64)h1 + (d0 >> 32) + U8TOU32(inp + 4)); h2 = (u32)(d2 = (u64)h2 + (d1 >> 32) + U8TOU32(inp + 8)); h3 = (u32)(d3 = (u64)h3 + (d2 >> 32) + U8TOU32(inp + 12)); h4 += (u32)(d3 >> 32) + padbit; /* h *= r "%" p, where "%" stands for "partial remainder" */ d0 = ((u64)h0 * r0) + ((u64)h1 * s3) + ((u64)h2 * s2) + ((u64)h3 * s1); d1 = ((u64)h0 * r1) + ((u64)h1 * r0) + ((u64)h2 * s3) + ((u64)h3 * s2) + (h4 * s1); d2 = ((u64)h0 * r2) + ((u64)h1 * r1) + ((u64)h2 * r0) + ((u64)h3 * s3) + (h4 * s2); d3 = ((u64)h0 * r3) + ((u64)h1 * r2) + ((u64)h2 * r1) + ((u64)h3 * r0) + (h4 * s3); h4 = (h4 * r0); /* last reduction step: */ /* a) h4:h0 = h4<<128 + d3<<96 + d2<<64 + d1<<32 + d0 */ h0 = (u32)d0; h1 = (u32)(d1 += d0 >> 32); h2 = (u32)(d2 += d1 >> 32); h3 = (u32)(d3 += d2 >> 32); h4 += (u32)(d3 >> 32); /* b) (h4:h0 += (h4:h0>>130) * 5) %= 2^130 */ c = (h4 >> 2) + (h4 & ~3U); h4 &= 3; h0 += c; h1 += (c = CONSTANT_TIME_CARRY(h0,c)); h2 += (c = CONSTANT_TIME_CARRY(h1,c)); h3 += (c = CONSTANT_TIME_CARRY(h2,c)); h4 += CONSTANT_TIME_CARRY(h3,c); /* * Occasional overflows to 3rd bit of h4 are taken care of * "naturally". If after this point we end up at the top of * this loop, then the overflow bit will be accounted for * in next iteration. If we end up in poly1305_emit, then * comparison to modulus below will still count as "carry * into 131st bit", so that properly reduced value will be * picked in conditional move. */ inp += POLY1305_BLOCK_SIZE; len -= POLY1305_BLOCK_SIZE; } st->h[0] = h0; st->h[1] = h1; st->h[2] = h2; st->h[3] = h3; st->h[4] = h4; } static void poly1305_emit(void *ctx, unsigned char mac[16], const u32 nonce[4]) { poly1305_internal *st = (poly1305_internal *) ctx; u32 h0, h1, h2, h3, h4; u32 g0, g1, g2, g3, g4; u64 t; u32 mask; h0 = st->h[0]; h1 = st->h[1]; h2 = st->h[2]; h3 = st->h[3]; h4 = st->h[4]; /* compare to modulus by computing h + -p */ g0 = (u32)(t = (u64)h0 + 5); g1 = (u32)(t = (u64)h1 + (t >> 32)); g2 = (u32)(t = (u64)h2 + (t >> 32)); g3 = (u32)(t = (u64)h3 + (t >> 32)); g4 = h4 + (u32)(t >> 32); /* if there was carry into 131st bit, h3:h0 = g3:g0 */ mask = 0 - (g4 >> 2); g0 &= mask; g1 &= mask; g2 &= mask; g3 &= mask; mask = ~mask; h0 = (h0 & mask) | g0; h1 = (h1 & mask) | g1; h2 = (h2 & mask) | g2; h3 = (h3 & mask) | g3; /* mac = (h + nonce) % (2^128) */ h0 = (u32)(t = (u64)h0 + nonce[0]); h1 = (u32)(t = (u64)h1 + (t >> 32) + nonce[1]); h2 = (u32)(t = (u64)h2 + (t >> 32) + nonce[2]); h3 = (u32)(t = (u64)h3 + (t >> 32) + nonce[3]); U32TO8(mac + 0, h0); U32TO8(mac + 4, h1); U32TO8(mac + 8, h2); U32TO8(mac + 12, h3); } # endif #else int poly1305_init(void *ctx, const unsigned char key[16], void *func); void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, unsigned int padbit); void poly1305_emit(void *ctx, unsigned char mac[16], const unsigned int nonce[4]); #endif void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32]) { OPENSSL_cpuid_setup(); ctx->nonce[0] = U8TOU32(&key[16]); ctx->nonce[1] = U8TOU32(&key[20]); ctx->nonce[2] = U8TOU32(&key[24]); ctx->nonce[3] = U8TOU32(&key[28]); #ifndef POLY1305_ASM poly1305_init(ctx->opaque, key); #else /* * Unlike reference poly1305_init assembly counterpart is expected * to return a value: non-zero if it initializes ctx->func, and zero * otherwise. Latter is to simplify assembly in cases when there no * multiple code paths to switch between. */ if (!poly1305_init(ctx->opaque, key, &ctx->func)) { ctx->func.blocks = poly1305_blocks; ctx->func.emit = poly1305_emit; } #endif ctx->num = 0; } #ifdef POLY1305_ASM /* * This "eclipses" poly1305_blocks and poly1305_emit, but it's * conscious choice imposed by -Wshadow compiler warnings. */ # define poly1305_blocks (*poly1305_blocks_p) # define poly1305_emit (*poly1305_emit_p) #endif void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len) { #ifdef POLY1305_ASM /* * As documented, poly1305_blocks is never called with input * longer than single block and padbit argument set to 0. This * property is fluently used in assembly modules to optimize * padbit handling on loop boundary. */ poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks; #endif size_t rem, num; if ((num = ctx->num)) { rem = POLY1305_BLOCK_SIZE - num; if (len >= rem) { tb_memcpy(ctx->data + num, inp, rem); poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1); inp += rem; len -= rem; } else { /* Still not enough data to process a block. */ tb_memcpy(ctx->data + num, inp, len); ctx->num = num + len; return; } } rem = len % POLY1305_BLOCK_SIZE; len -= rem; if (len >= POLY1305_BLOCK_SIZE) { poly1305_blocks(ctx->opaque, inp, len, 1); inp += len; } if (rem) tb_memcpy(ctx->data, inp, rem); ctx->num = rem; } void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16]) { #ifdef POLY1305_ASM poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks; poly1305_emit_f poly1305_emit_p = ctx->func.emit; #endif size_t num; if ((num = ctx->num)) { ctx->data[num++] = 1; /* pad bit */ while (num < POLY1305_BLOCK_SIZE) ctx->data[num++] = 0; poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0); } poly1305_emit(ctx->opaque, mac, ctx->nonce); /* zero out the state */ OPENSSL_cleanse(ctx, sizeof(*ctx)); } tboot-1.10.5/tboot/common/poly1305/x86asm.pl0000644000000000000000000001600414210363175016454 0ustar 00000000000000#! /usr/bin/env perl # Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html # require 'x86asm.pl'; # &asm_init([,$i386only]); # &function_begin("foo"); # ... # &function_end("foo"); # &asm_finish $out=(); $i386=0; # AUTOLOAD is this context has quite unpleasant side effect, namely # that typos in function calls effectively go to assembler output, # but on the pros side we don't have to implement one subroutine per # each opcode... sub ::AUTOLOAD { my $opcode = $AUTOLOAD; die "more than 4 arguments passed to $opcode" if ($#_>3); $opcode =~ s/.*:://; if ($opcode =~ /^push/) { $stack+=4; } elsif ($opcode =~ /^pop/) { $stack-=4; } &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD"; } sub ::emit { my $opcode=shift; if ($#_==-1) { push(@out,"\t$opcode\n"); } else { push(@out,"\t$opcode\t".join(',',@_)."\n"); } } sub ::LB { $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'"; $1."l"; } sub ::HB { $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'"; $1."h"; } sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); } sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); } sub ::blindpop { &pop($_[0]); $stack+=4; } sub ::wparam { &DWP($stack+4*$_[0],"esp"); } sub ::swtmp { &DWP(4*$_[0],"esp"); } sub ::bswap { if ($i386) # emulate bswap for i386 { &comment("bswap @_"); &xchg(&HB(@_),&LB(@_)); &ror (@_,16); &xchg(&HB(@_),&LB(@_)); } else { &generic("bswap",@_); } } # These are made-up opcodes introduced over the years essentially # by ignorance, just alias them to real ones... sub ::movb { &mov(@_); } sub ::xorb { &xor(@_); } sub ::rotl { &rol(@_); } sub ::rotr { &ror(@_); } sub ::exch { &xchg(@_); } sub ::halt { &hlt; } sub ::movz { &movzx(@_); } sub ::pushf { &pushfd; } sub ::popf { &popfd; } # 3 argument instructions sub ::movq { my($p1,$p2,$optimize)=@_; if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/) # movq between mmx registers can sink Intel CPUs { &::pshufw($p1,$p2,0xe4); } else { &::generic("movq",@_); } } # SSE>2 instructions my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3, "esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 ); sub ::pextrd { my($dst,$src,$imm)=@_; if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/) { &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); } else { &::generic("pextrd",@_); } } sub ::pinsrd { my($dst,$src,$imm)=@_; if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/) { &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); } else { &::generic("pinsrd",@_); } } sub ::pshufb { my($dst,$src)=@_; if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) { &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); } else { &::generic("pshufb",@_); } } sub ::palignr { my($dst,$src,$imm)=@_; if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) { &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); } else { &::generic("palignr",@_); } } sub ::pclmulqdq { my($dst,$src,$imm)=@_; if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) { &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); } else { &::generic("pclmulqdq",@_); } } sub ::rdrand { my ($dst)=@_; if ($dst =~ /(e[a-dsd][ixp])/) { &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); } else { &::generic("rdrand",@_); } } sub ::rdseed { my ($dst)=@_; if ($dst =~ /(e[a-dsd][ixp])/) { &::data_byte(0x0f,0xc7,0xf8|$regrm{$dst}); } else { &::generic("rdrand",@_); } } sub rxb { local *opcode=shift; my ($dst,$src1,$src2,$rxb)=@_; $rxb|=0x7<<5; $rxb&=~(0x04<<5) if($dst>=8); $rxb&=~(0x01<<5) if($src1>=8); $rxb&=~(0x02<<5) if($src2>=8); push @opcode,$rxb; } sub ::vprotd { my $args=join(',',@_); if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/) { my @opcode=(0x8f); rxb(\@opcode,$1,$2,-1,0x08); push @opcode,0x78,0xc2; push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M my $c=$3; push @opcode,$c=~/^0/?oct($c):$c; &::data_byte(@opcode); } else { &::generic("vprotd",@_); } } sub ::endbranch { &::data_byte(0xf3,0x0f,0x1e,0xfb); } # label management $lbdecor="L"; # local label decoration, set by package $label="000"; sub ::islabel # see is argument is a known label { my $i; foreach $i (values %label) { return $i if ($i eq $_[0]); } $label{$_[0]}; # can be undef } sub ::label # instantiate a function-scope label { if (!defined($label{$_[0]})) { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; } $label{$_[0]}; } sub ::LABEL # instantiate a file-scope label { $label{$_[0]}=$_[1] if (!defined($label{$_[0]})); $label{$_[0]}; } sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); } sub ::set_label_B { push(@out,"@_:\n"); } sub ::set_label { my $label=&::label($_[0]); &::align($_[1]) if ($_[1]>1); &::set_label_B($label); $label; } sub ::wipe_labels # wipes function-scope labels { foreach $i (keys %label) { delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); } } # subroutine management sub ::function_begin { &function_begin_B(@_); $stack=4; &push("ebp"); &push("ebx"); &push("esi"); &push("edi"); } sub ::function_end { &pop("edi"); &pop("esi"); &pop("ebx"); &pop("ebp"); &ret(); &function_end_B(@_); $stack=0; &wipe_labels(); } sub ::function_end_A { &pop("edi"); &pop("esi"); &pop("ebx"); &pop("ebp"); &ret(); $stack+=16; # readjust esp as if we didn't pop anything } sub ::asciz { my @str=unpack("C*",shift); push @str,0; while ($#str>15) { &data_byte(@str[0..15]); foreach (0..15) { shift @str; } } &data_byte(@str) if (@str); } sub ::asm_finish { &file_end(); print @out; } sub ::asm_init { my ($type,$cpu)=@_; $i386=$cpu; $elf=$cpp=$coff=$aout=$macosx=$win32=$mwerks=$android=0; if (($type eq "elf")) { $elf=1; require "x86gas.pl"; } elsif (($type eq "elf-1")) { $elf=-1; require "x86gas.pl"; } elsif (($type eq "a\.out")) { $aout=1; require "x86gas.pl"; } elsif (($type eq "coff" or $type eq "gaswin")) { $coff=1; require "x86gas.pl"; } elsif (($type eq "win32n")) { $win32=1; require "x86nasm.pl"; } elsif (($type eq "win32")) { $win32=1; require "x86masm.pl"; } elsif (($type eq "macosx")) { $aout=1; $macosx=1; require "x86gas.pl"; } elsif (($type eq "android")) { $elf=1; $android=1; require "x86gas.pl"; } else { print STDERR <<"EOF"; Pick one target type from elf - Linux, FreeBSD, Solaris x86, etc. a.out - DJGPP, elder OpenBSD, etc. coff - GAS/COFF such as Win32 targets win32n - Windows 95/Windows NT NASM format macosx - Mac OS X EOF exit(1); } $pic=0; for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); } &file(); } sub ::hidden {} 1; tboot-1.10.5/tboot/common/poly1305/x86cpuid.pl0000644000000000000000000003041614210363175017003 0ustar 00000000000000#! /usr/bin/env perl # Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; push(@INC,"${dir}","${dir}."); require "x86asm.pl"; $output = pop and open STDOUT,">$output"; &asm_init($ARGV[0]); for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &function_begin("OPENSSL_ia32_cpuid"); &xor ("edx","edx"); &pushf (); &pop ("eax"); &mov ("ecx","eax"); &xor ("eax",1<<21); &push ("eax"); &popf (); &pushf (); &pop ("eax"); &xor ("ecx","eax"); &xor ("eax","eax"); &mov ("esi",&wparam(0)); &mov (&DWP(8,"esi"),"eax"); # clear extended feature flags &bt ("ecx",21); &jnc (&label("nocpuid")); &cpuid (); &mov ("edi","eax"); # max value for standard query level &xor ("eax","eax"); &cmp ("ebx",0x756e6547); # "Genu" &setne (&LB("eax")); &mov ("ebp","eax"); &cmp ("edx",0x49656e69); # "ineI" &setne (&LB("eax")); &or ("ebp","eax"); &cmp ("ecx",0x6c65746e); # "ntel" &setne (&LB("eax")); &or ("ebp","eax"); # 0 indicates Intel CPU &jz (&label("intel")); &cmp ("ebx",0x68747541); # "Auth" &setne (&LB("eax")); &mov ("esi","eax"); &cmp ("edx",0x69746E65); # "enti" &setne (&LB("eax")); &or ("esi","eax"); &cmp ("ecx",0x444D4163); # "cAMD" &setne (&LB("eax")); &or ("esi","eax"); # 0 indicates AMD CPU &jnz (&label("intel")); # AMD specific &mov ("eax",0x80000000); &cpuid (); &cmp ("eax",0x80000001); &jb (&label("intel")); &mov ("esi","eax"); &mov ("eax",0x80000001); &cpuid (); &or ("ebp","ecx"); &and ("ebp",1<<11|1); # isolate XOP bit &cmp ("esi",0x80000008); &jb (&label("intel")); &mov ("eax",0x80000008); &cpuid (); &movz ("esi",&LB("ecx")); # number of cores - 1 &inc ("esi"); # number of cores &mov ("eax",1); &xor ("ecx","ecx"); &cpuid (); &bt ("edx",28); &jnc (&label("generic")); &shr ("ebx",16); &and ("ebx",0xff); &cmp ("ebx","esi"); &ja (&label("generic")); &and ("edx",0xefffffff); # clear hyper-threading bit &jmp (&label("generic")); &set_label("intel"); &cmp ("edi",4); &mov ("esi",-1); &jb (&label("nocacheinfo")); &mov ("eax",4); &mov ("ecx",0); # query L1D &cpuid (); &mov ("esi","eax"); &shr ("esi",14); &and ("esi",0xfff); # number of cores -1 per L1D &set_label("nocacheinfo"); &mov ("eax",1); &xor ("ecx","ecx"); &cpuid (); &and ("edx",0xbfefffff); # force reserved bits #20, #30 to 0 &cmp ("ebp",0); &jne (&label("notintel")); &or ("edx",1<<30); # set reserved bit#30 on Intel CPUs &and (&HB("eax"),15); # family ID &cmp (&HB("eax"),15); # P4? &jne (&label("notintel")); &or ("edx",1<<20); # set reserved bit#20 to engage RC4_CHAR &set_label("notintel"); &bt ("edx",28); # test hyper-threading bit &jnc (&label("generic")); &and ("edx",0xefffffff); &cmp ("esi",0); &je (&label("generic")); &or ("edx",0x10000000); &shr ("ebx",16); &cmp (&LB("ebx"),1); &ja (&label("generic")); &and ("edx",0xefffffff); # clear hyper-threading bit if not &set_label("generic"); &and ("ebp",1<<11); # isolate AMD XOP flag &and ("ecx",0xfffff7ff); # force 11th bit to 0 &mov ("esi","edx"); # %ebp:%esi is copy of %ecx:%edx &or ("ebp","ecx"); # merge AMD XOP flag &cmp ("edi",7); &mov ("edi",&wparam(0)); &jb (&label("no_extended_info")); &mov ("eax",7); &xor ("ecx","ecx"); &cpuid (); &mov (&DWP(8,"edi"),"ebx"); # save extended feature flag &set_label("no_extended_info"); &bt ("ebp",27); # check OSXSAVE bit &jnc (&label("clear_avx")); &xor ("ecx","ecx"); &data_byte(0x0f,0x01,0xd0); # xgetbv &and ("eax",6); &cmp ("eax",6); &je (&label("done")); &cmp ("eax",2); &je (&label("clear_avx")); &set_label("clear_xmm"); &and ("ebp",0xfdfffffd); # clear AESNI and PCLMULQDQ bits &and ("esi",0xfeffffff); # clear FXSR &set_label("clear_avx"); &and ("ebp",0xefffe7ff); # clear AVX, FMA and AMD XOP bits &and (&DWP(8,"edi"),0xffffffdf); # clear AVX2 &set_label("done"); &mov ("eax","esi"); &mov ("edx","ebp"); &set_label("nocpuid"); &function_end("OPENSSL_ia32_cpuid"); &external_label("OPENSSL_ia32cap_P"); &function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); &xor ("eax","eax"); &xor ("edx","edx"); &picmeup("ecx","OPENSSL_ia32cap_P"); &bt (&DWP(0,"ecx"),4); &jnc (&label("notsc")); &rdtsc (); &set_label("notsc"); &ret (); &function_end_B("OPENSSL_rdtsc"); # This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host], # but it's safe to call it on any [supported] 32-bit platform... # Just check for [non-]zero return value... &function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); &picmeup("ecx","OPENSSL_ia32cap_P"); &bt (&DWP(0,"ecx"),4); &jnc (&label("nohalt")); # no TSC &data_word(0x9058900e); # push %cs; pop %eax &and ("eax",3); &jnz (&label("nohalt")); # not enough privileges &pushf (); &pop ("eax"); &bt ("eax",9); &jnc (&label("nohalt")); # interrupts are disabled &rdtsc (); &push ("edx"); &push ("eax"); &halt (); &rdtsc (); &sub ("eax",&DWP(0,"esp")); &sbb ("edx",&DWP(4,"esp")); &add ("esp",8); &ret (); &set_label("nohalt"); &xor ("eax","eax"); &xor ("edx","edx"); &ret (); &function_end_B("OPENSSL_instrument_halt"); # Essentially there is only one use for this function. Under DJGPP: # # #include # ... # i=OPENSSL_far_spin(_dos_ds,0x46c); # ... # to obtain the number of spins till closest timer interrupt. &function_begin_B("OPENSSL_far_spin"); &pushf (); &pop ("eax"); &bt ("eax",9); &jnc (&label("nospin")); # interrupts are disabled &mov ("eax",&DWP(4,"esp")); &mov ("ecx",&DWP(8,"esp")); &data_word (0x90d88e1e); # push %ds, mov %eax,%ds &xor ("eax","eax"); &mov ("edx",&DWP(0,"ecx")); &jmp (&label("spin")); &align (16); &set_label("spin"); &inc ("eax"); &cmp ("edx",&DWP(0,"ecx")); &je (&label("spin")); &data_word (0x1f909090); # pop %ds &ret (); &set_label("nospin"); &xor ("eax","eax"); &xor ("edx","edx"); &ret (); &function_end_B("OPENSSL_far_spin"); &function_begin_B("OPENSSL_wipe_cpu","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); &xor ("eax","eax"); &xor ("edx","edx"); &picmeup("ecx","OPENSSL_ia32cap_P"); &mov ("ecx",&DWP(0,"ecx")); &bt (&DWP(0,"ecx"),1); &jnc (&label("no_x87")); if ($sse2) { &and ("ecx",1<<26|1<<24); # check SSE2 and FXSR bits &cmp ("ecx",1<<26|1<<24); &jne (&label("no_sse2")); &pxor ("xmm0","xmm0"); &pxor ("xmm1","xmm1"); &pxor ("xmm2","xmm2"); &pxor ("xmm3","xmm3"); &pxor ("xmm4","xmm4"); &pxor ("xmm5","xmm5"); &pxor ("xmm6","xmm6"); &pxor ("xmm7","xmm7"); &set_label("no_sse2"); } # just a bunch of fldz to zap the fp/mm bank followed by finit... &data_word(0xeed9eed9,0xeed9eed9,0xeed9eed9,0xeed9eed9,0x90e3db9b); &set_label("no_x87"); &lea ("eax",&DWP(4,"esp")); &ret (); &function_end_B("OPENSSL_wipe_cpu"); &function_begin_B("OPENSSL_atomic_add"); &mov ("edx",&DWP(4,"esp")); # fetch the pointer, 1st arg &mov ("ecx",&DWP(8,"esp")); # fetch the increment, 2nd arg &push ("ebx"); &nop (); &mov ("eax",&DWP(0,"edx")); &set_label("spin"); &lea ("ebx",&DWP(0,"eax","ecx")); &nop (); &data_word(0x1ab10ff0); # lock; cmpxchg %ebx,(%edx) # %eax is involved and is always reloaded &jne (&label("spin")); &mov ("eax","ebx"); # OpenSSL expects the new value &pop ("ebx"); &ret (); &function_end_B("OPENSSL_atomic_add"); &function_begin_B("OPENSSL_cleanse"); &mov ("edx",&wparam(0)); &mov ("ecx",&wparam(1)); &xor ("eax","eax"); &cmp ("ecx",7); &jae (&label("lot")); &cmp ("ecx",0); &je (&label("ret")); &set_label("little"); &mov (&BP(0,"edx"),"al"); &sub ("ecx",1); &lea ("edx",&DWP(1,"edx")); &jnz (&label("little")); &set_label("ret"); &ret (); &set_label("lot",16); &test ("edx",3); &jz (&label("aligned")); &mov (&BP(0,"edx"),"al"); &lea ("ecx",&DWP(-1,"ecx")); &lea ("edx",&DWP(1,"edx")); &jmp (&label("lot")); &set_label("aligned"); &mov (&DWP(0,"edx"),"eax"); &lea ("ecx",&DWP(-4,"ecx")); &test ("ecx",-4); &lea ("edx",&DWP(4,"edx")); &jnz (&label("aligned")); &cmp ("ecx",0); &jne (&label("little")); &ret (); &function_end_B("OPENSSL_cleanse"); &function_begin_B("CRYPTO_memcmp"); &push ("esi"); &push ("edi"); &mov ("esi",&wparam(0)); &mov ("edi",&wparam(1)); &mov ("ecx",&wparam(2)); &xor ("eax","eax"); &xor ("edx","edx"); &cmp ("ecx",0); &je (&label("no_data")); &set_label("loop"); &mov ("dl",&BP(0,"esi")); &lea ("esi",&DWP(1,"esi")); &xor ("dl",&BP(0,"edi")); &lea ("edi",&DWP(1,"edi")); &or ("al","dl"); &dec ("ecx"); &jnz (&label("loop")); &neg ("eax"); &shr ("eax",31); &set_label("no_data"); &pop ("edi"); &pop ("esi"); &ret (); &function_end_B("CRYPTO_memcmp"); { my $lasttick = "esi"; my $lastdiff = "ebx"; my $out = "edi"; my $cnt = "ecx"; my $max = "ebp"; &function_begin("OPENSSL_instrument_bus"); &mov ("eax",0); if ($sse2) { &picmeup("edx","OPENSSL_ia32cap_P"); &bt (&DWP(0,"edx"),4); &jnc (&label("nogo")); # no TSC &bt (&DWP(0,"edx"),19); &jnc (&label("nogo")); # no CLFLUSH &mov ($out,&wparam(0)); # load arguments &mov ($cnt,&wparam(1)); # collect 1st tick &rdtsc (); &mov ($lasttick,"eax"); # lasttick = tick &mov ($lastdiff,0); # lastdiff = 0 &clflush(&DWP(0,$out)); &data_byte(0xf0); # lock &add (&DWP(0,$out),$lastdiff); &jmp (&label("loop")); &set_label("loop",16); &rdtsc (); &mov ("edx","eax"); # put aside tick (yes, I neglect edx) &sub ("eax",$lasttick); # diff &mov ($lasttick,"edx"); # lasttick = tick &mov ($lastdiff,"eax"); # lastdiff = diff &clflush(&DWP(0,$out)); &data_byte(0xf0); # lock &add (&DWP(0,$out),"eax"); # accumulate diff &lea ($out,&DWP(4,$out)); # ++$out &sub ($cnt,1); # --$cnt &jnz (&label("loop")); &mov ("eax",&wparam(1)); &set_label("nogo"); } &function_end("OPENSSL_instrument_bus"); &function_begin("OPENSSL_instrument_bus2"); &mov ("eax",0); if ($sse2) { &picmeup("edx","OPENSSL_ia32cap_P"); &bt (&DWP(0,"edx"),4); &jnc (&label("nogo")); # no TSC &bt (&DWP(0,"edx"),19); &jnc (&label("nogo")); # no CLFLUSH &mov ($out,&wparam(0)); # load arguments &mov ($cnt,&wparam(1)); &mov ($max,&wparam(2)); &rdtsc (); # collect 1st tick &mov ($lasttick,"eax"); # lasttick = tick &mov ($lastdiff,0); # lastdiff = 0 &clflush(&DWP(0,$out)); &data_byte(0xf0); # lock &add (&DWP(0,$out),$lastdiff); &rdtsc (); # collect 1st diff &mov ("edx","eax"); # put aside tick (yes, I neglect edx) &sub ("eax",$lasttick); # diff &mov ($lasttick,"edx"); # lasttick = tick &mov ($lastdiff,"eax"); # lastdiff = diff &jmp (&label("loop2")); &set_label("loop2",16); &clflush(&DWP(0,$out)); &data_byte(0xf0); # lock &add (&DWP(0,$out),"eax"); # accumulate diff &sub ($max,1); &jz (&label("done2")); &rdtsc (); &mov ("edx","eax"); # put aside tick (yes, I neglect edx) &sub ("eax",$lasttick); # diff &mov ($lasttick,"edx"); # lasttick = tick &cmp ("eax",$lastdiff); &mov ($lastdiff,"eax"); # lastdiff = diff &mov ("edx",0); &setne ("dl"); &sub ($cnt,"edx"); # conditional --$cnt &lea ($out,&DWP(0,$out,"edx",4)); # conditional ++$out &jnz (&label("loop2")); &set_label("done2"); &mov ("eax",&wparam(1)); &sub ("eax",$cnt); &set_label("nogo"); } &function_end("OPENSSL_instrument_bus2"); } sub gen_random { my $rdop = shift; &function_begin_B("OPENSSL_ia32_${rdop}_bytes"); &push ("edi"); &push ("ebx"); &xor ("eax","eax"); # return value &mov ("edi",&wparam(0)); &mov ("ebx",&wparam(1)); &cmp ("ebx",0); &je (&label("done")); &mov ("ecx",8); &set_label("loop"); &${rdop}("edx"); &jc (&label("break")); &loop (&label("loop")); &jmp (&label("done")); &set_label("break",16); &cmp ("ebx",4); &jb (&label("tail")); &mov (&DWP(0,"edi"),"edx"); &lea ("edi",&DWP(4,"edi")); &add ("eax",4); &sub ("ebx",4); &jz (&label("done")); &mov ("ecx",8); &jmp (&label("loop")); &set_label("tail",16); &mov (&BP(0,"edi"),"dl"); &lea ("edi",&DWP(1,"edi")); &inc ("eax"); &shr ("edx",8); &dec ("ebx"); &jnz (&label("tail")); &set_label("done"); &xor ("edx","edx"); # Clear random value from registers &pop ("ebx"); &pop ("edi"); &ret (); &function_end_B("OPENSSL_ia32_${rdop}_bytes"); } &gen_random("rdrand"); &gen_random("rdseed"); # .init will not work in TBOOT, this function is called in Poly1305_Init # &initseg("OPENSSL_cpuid_setup"); &hidden("OPENSSL_cpuid_setup"); &hidden("OPENSSL_ia32cap_P"); &asm_finish(); close STDOUT or die "error closing STDOUT: $!"; tboot-1.10.5/tboot/common/poly1305/x86gas.pl0000644000000000000000000001504214210363175016447 0ustar 00000000000000#! /usr/bin/env perl # Copyright 2007-2016 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html package x86gas; *out=\@::out; $::lbdecor=$::aout?"L":".L"; # local label decoration $nmdecor=($::aout or $::coff)?"_":""; # external name decoration $initseg=""; $align=16; $align=log($align)/log(2) if ($::aout); $com_start="#" if ($::aout or $::coff); sub opsize() { my $reg=shift; if ($reg =~ m/^%e/o) { "l"; } elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; } elsif ($reg =~ m/^%[yxm]/o) { undef; } else { "w"; } } # swap arguments; # expand opcode with size suffix; # prefix numeric constants with $; sub ::generic { my($opcode,@arg)=@_; my($suffix,$dst,$src); @arg=reverse(@arg); for (@arg) { s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o; # gp registers s/^([xy]?mm[0-7])$/%$1/o; # xmm/mmx registers s/^(\-?[0-9]+)$/\$$1/o; # constants s/^(\-?0x[0-9a-f]+)$/\$$1/o; # constants } $dst = $arg[$#arg] if ($#arg>=0); $src = $arg[$#arg-1] if ($#arg>=1); if ($dst =~ m/^%/o) { $suffix=&opsize($dst); } elsif ($src =~ m/^%/o) { $suffix=&opsize($src); } else { $suffix="l"; } undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o); if ($#_==0) { &::emit($opcode); } elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o) { &::emit($opcode,@arg); } else { &::emit($opcode.$suffix,@arg);} 1; } # # opcodes not covered by ::generic above, mostly inconsistent namings... # sub ::movzx { &::movzb(@_); } sub ::pushfd { &::pushfl; } sub ::popfd { &::popfl; } sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); } sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); } sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); } sub ::call_ptr { &::generic("call","*$_[0]"); } sub ::jmp_ptr { &::generic("jmp","*$_[0]"); } *::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386); sub ::DWP { my($addr,$reg1,$reg2,$idx)=@_; my $ret=""; if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; } $addr =~ s/^\s+//; # prepend global references with optional underscore $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige; $reg1 = "%$reg1" if ($reg1); $reg2 = "%$reg2" if ($reg2); $ret .= $addr if (($addr ne "") && ($addr ne 0)); if ($reg2) { $idx!= 0 or $idx=1; $ret .= "($reg1,$reg2,$idx)"; } elsif ($reg1) { $ret .= "($reg1)"; } $ret; } sub ::QWP { &::DWP(@_); } sub ::BP { &::DWP(@_); } sub ::WP { &::DWP(@_); } sub ::BC { @_; } sub ::DWC { @_; } sub ::file { push(@out,".text\n"); } sub ::function_begin_B { my $func=shift; my $global=($func !~ /^_/); my $begin="${::lbdecor}_${func}_begin"; &::LABEL($func,$global?"$begin":"$nmdecor$func"); $func=$nmdecor.$func; push(@out,".globl\t$func\n") if ($global); if ($::coff) { push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); } elsif (($::aout and !$::pic) or $::macosx) { } else { push(@out,".type $func,\@function\n"); } push(@out,".align\t$align\n"); push(@out,"$func:\n"); push(@out,"$begin:\n") if ($global); &::endbranch(); $::stack=4; } sub ::function_end_B { my $func=shift; push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf); $::stack=0; &::wipe_labels(); } sub ::comment { if (!defined($com_start) or $::elf) { # Regarding $::elf above... # GNU and SVR4 as'es use different comment delimiters, push(@out,"\n"); # so we just skip ELF comments... return; } foreach (@_) { if (/^\s*$/) { push(@out,"\n"); } else { push(@out,"\t$com_start $_ $com_end\n"); } } } sub ::external_label { foreach(@_) { &::LABEL($_,$nmdecor.$_); } } sub ::public_label { push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); } sub ::file_end { if ($::macosx) { if (%non_lazy_ptr) { push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); foreach $i (keys %non_lazy_ptr) { push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n"); } } } if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) { my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16"; if ($::macosx) { push (@out,"$tmp,2\n"); } elsif ($::elf) { push (@out,"$tmp,4\n"); } else { push (@out,"$tmp\n"); } } push(@out,$initseg) if ($initseg); if ($::elf) { push(@out," .section \".note.gnu.property\", \"a\" .p2align 2 .long 1f - 0f .long 4f - 1f .long 5 0: .asciz \"GNU\" 1: .p2align 2 .long 0xc0000002 .long 3f - 2f 2: .long 3 3: .p2align 2 4: "); } } sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); } sub ::data_short{ push(@out,".value\t".join(',',@_)."\n"); } sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); } sub ::align { my $val=$_[0]; if ($::aout) { $val=int(log($val)/log(2)); $val.=",0x90"; } push(@out,".align\t$val\n"); } sub ::picmeup { my($dst,$sym,$base,$reflabel)=@_; if (($::pic && ($::elf || $::aout)) || $::macosx) { if (!defined($base)) { &::call(&::label("PIC_me_up")); &::set_label("PIC_me_up"); &::blindpop($dst); $base=$dst; $reflabel=&::label("PIC_me_up"); } if ($::macosx) { my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr"); &::mov($dst,&::DWP("$indirect-$reflabel",$base)); $non_lazy_ptr{"$nmdecor$sym"}=$indirect; } elsif ($sym eq "OPENSSL_ia32cap_P" && $::elf>0) { &::lea($dst,&::DWP("$sym-$reflabel",$base)); } else { &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]", $base)); &::mov($dst,&::DWP("$sym\@GOT",$dst)); } } else { &::lea($dst,&::DWP($sym)); } } sub ::initseg { my $f=$nmdecor.shift; if ($::android) { $initseg.=<<___; .section .init_array .align 4 .long $f ___ } elsif ($::elf) { $initseg.=<<___; .section .init call $f ___ } elsif ($::coff) { $initseg.=<<___; # applies to both Cygwin and Mingw .section .ctors .long $f ___ } elsif ($::macosx) { $initseg.=<<___; .mod_init_func .align 2 .long $f ___ } elsif ($::aout) { my $ctor="${nmdecor}_GLOBAL_\$I\$$f"; $initseg.=".text\n"; $initseg.=".type $ctor,\@function\n" if ($::pic); $initseg.=<<___; # OpenBSD way... .globl $ctor .align 2 $ctor: jmp $f ___ } } sub ::dataseg { push(@out,".data\n"); } *::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf); 1; tboot-1.10.5/tboot/common/printk.c0000644000000000000000000000765714210363175015166 0ustar 00000000000000/* * printk.c: printk() output fn and helpers * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #include #include uint8_t g_log_level = TBOOT_LOG_LEVEL_ALL; uint8_t g_log_targets = TBOOT_LOG_TARGET_SERIAL | TBOOT_LOG_TARGET_VGA; static struct mutex print_lock; void printk_init(bool force_vga_off) { mtx_init(&print_lock); /* parse loglvl from string to int */ get_tboot_loglvl(); /* parse logging targets */ get_tboot_log_targets(); /* parse serial settings */ if ( !get_tboot_serial() ) g_log_targets &= ~TBOOT_LOG_TARGET_SERIAL; if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY ) memlog_init(); if ( g_log_targets & TBOOT_LOG_TARGET_SERIAL ) serial_init(); if ( !force_vga_off && (g_log_targets & TBOOT_LOG_TARGET_VGA) ) { vga_init(); get_tboot_vga_delay(); /* parse vga delay time */ } } void printk_disable_vga(void) { g_log_targets &= ~TBOOT_LOG_TARGET_VGA; } void printk_flush(void) { if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY ) { memlog_compress(0); } } #define WRITE_LOGS(s, n) \ do { \ if (g_log_targets & TBOOT_LOG_TARGET_MEMORY) memlog_write(s, n); \ if (g_log_targets & TBOOT_LOG_TARGET_SERIAL) serial_write(s, n); \ if (g_log_targets & TBOOT_LOG_TARGET_VGA) vga_write(s, n); \ } while (0) void printk(const char *fmt, ...) { char buf[256]; char *pbuf = buf; int n; va_list ap; uint8_t log_level; static bool last_line_cr = true; tb_memset(buf, '\0', sizeof(buf)); va_start(ap, fmt); n = tb_vscnprintf(buf, sizeof(buf), fmt, ap); log_level = get_loglvl_prefix(&pbuf, &n); if ( !(g_log_level & log_level) ) goto exit; mtx_enter(&print_lock); /* prepend "TBOOT: " if the last line that was printed ended with a '\n' */ if ( last_line_cr ) WRITE_LOGS("TBOOT: ", 8); last_line_cr = (n > 0 && (*(pbuf+n-1) == '\n')); WRITE_LOGS(pbuf, n); mtx_leave(&print_lock); exit: va_end(ap); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/sha1.c0000644000000000000000000002241314210363175014476 0ustar 00000000000000/*$KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the 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 PROJECT 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 PROJECT 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. */ /* * Portions copyright (c) 2010, Intel Corporation */ /* * From: FreeBSD sys/crypto/sha1.c */ /* * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) * based on: http://csrc.nist.gov/fips/fip180-1.txt * implemented by Jun-ichiro itojun Itoh */ #include #include #include #include #define BIG_ENDIAN \ (!(__x86_64__ || __i386__ || _M_IX86 || _M_X64 || __ARMEL__ || __MIPSEL__)) #define LITTLE_ENDIAN !BIG_ENDIAN /* constant table */ static uint32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; #define K(t) _K[(t) / 20] #define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) #define F1(b, c, d) (((b) ^ (c)) ^ (d)) #define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) #define F3(b, c, d) (((b) ^ (c)) ^ (d)) #define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) #define H(n) (ctxt->h.b32[(n)]) #define COUNT (ctxt->count) #define BCOUNT (ctxt->c.b64[0] / 8) #define W(n) (ctxt->m.b32[(n)]) #define PUTBYTE(x){\ ctxt->m.b8[(COUNT % 64)] = (x);\ COUNT++;\ COUNT %= 64;\ ctxt->c.b64[0] += 8;\ if (COUNT % 64 == 0)\ sha1_step(ctxt);\ } #define PUTPAD(x){\ ctxt->m.b8[(COUNT % 64)] = (x);\ COUNT++;\ COUNT %= 64;\ if (COUNT % 64 == 0)\ sha1_step(ctxt);\ } static void sha1_step(struct sha1_ctxt *ctxt) { uint32_t a, b, c, d, e; size_t t, s; uint32_t tmp; #if LITTLE_ENDIAN struct sha1_ctxt tctxt; tb_memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64); ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; #endif a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); for (t = 0; t < 20; t++) { s = t & 0x0f; if (t >= 16){ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); } tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } for (t = 20; t < 40; t++) { s = t & 0x0f; W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } for (t = 40; t < 60; t++) { s = t & 0x0f; W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } for (t = 60; t < 80; t++) { s = t & 0x0f; W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } H(0) = H(0) + a; H(1) = H(1) + b; H(2) = H(2) + c; H(3) = H(3) + d; H(4) = H(4) + e; tb_memset(&ctxt->m.b8[0],0, 64); } /*------------------------------------------------------------*/ void sha1_init(struct sha1_ctxt *ctxt) { tb_memset(ctxt,0, sizeof(struct sha1_ctxt)); H(0) = 0x67452301; H(1) = 0xefcdab89; H(2) = 0x98badcfe; H(3) = 0x10325476; H(4) = 0xc3d2e1f0; } void sha1_pad(struct sha1_ctxt *ctxt) { size_t padlen; /*pad length in bytes*/ size_t padstart; PUTPAD(0x80); padstart = COUNT % 64; padlen = 64 - padstart; if (padlen < 8) { tb_memset(&ctxt->m.b8[padstart],0, padlen); COUNT += padlen; COUNT %= 64; sha1_step(ctxt); padstart = COUNT % 64; /* should be 0 */ padlen = 64 - padstart; /* should be 64 */ } tb_memset(&ctxt->m.b8[padstart],0, padlen - 8); COUNT += (padlen - 8); COUNT %= 64; #if BIG_ENDIAN PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); #else PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); #endif } void sha1_loop(struct sha1_ctxt *ctxt,const uint8_t *input,size_t len) { size_t gaplen; size_t gapstart; size_t off; size_t copysiz; off = 0; while (off < len) { gapstart = COUNT % 64; gaplen = 64 - gapstart; copysiz = (gaplen < len - off) ? gaplen : len - off; tb_memcpy(&ctxt->m.b8[gapstart],&input[off], copysiz); COUNT += copysiz; COUNT %= 64; ctxt->c.b64[0] += copysiz * 8; if (COUNT % 64 == 0) sha1_step(ctxt); off += copysiz; } } void sha1_result(struct sha1_ctxt *ctxt,unsigned char *digest0) { uint8_t *digest; digest = (uint8_t *)digest0; sha1_pad(ctxt); #if BIG_ENDIAN tb_memcpy(digest, &ctxt->h.b8[0],20); #else digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; #endif } int sha1_buffer(const unsigned char *buffer, size_t len, unsigned char md[SHA_DIGEST_LENGTH]) { SHA_CTX c; if (md == NULL) return 1; SHA1_Init(&c); SHA1_Update(&c,buffer,len); SHA1_Final(md,&c); return 0; } tboot-1.10.5/tboot/common/sha256.c0000644000000000000000000002254714210363175014662 0ustar 00000000000000/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. */ #include #include #include #include /* Various logical functions */ #define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) \ | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) \ & 0xFFFFFFFFUL) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) RORc((x),(n)) #define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) /* compress 512-bits */ static int sha256_compress(hash_state * md, unsigned char *buf) { u32 S[8], W[64], t0, t1; int i; /* copy state into S */ for (i = 0; i < 8; i++) { S[i] = md->sha256.state[i]; } /* copy the state into 512-bits into W[0..15] */ for (i = 0; i < 16; i++) { LOAD32H(W[i], buf + (4*i)); } /* fill W[16..63] */ for (i = 16; i < 64; i++) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i,ki) \ t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); #undef RND /* feedback */ for (i = 0; i < 8; i++) { md->sha256.state[i] = md->sha256.state[i] + S[i]; } return 0; } int sha256_process(hash_state * md, const unsigned char *in, u32 inlen) { unsigned long n; int err; if (md == NULL || in == NULL) return -1; if (md->sha256.curlen > sizeof(md->sha256.buf)) return -1; while (inlen > 0) { if (md->sha256.curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { if ((err = sha256_compress(md, (unsigned char *)in)) != 0) { return err; } md->sha256.length += SHA256_BLOCK_SIZE * 8; in += SHA256_BLOCK_SIZE; inlen -= SHA256_BLOCK_SIZE; } else { n = MIN(inlen, (SHA256_BLOCK_SIZE - md->sha256.curlen)); tb_memcpy(md->sha256.buf + md->sha256.curlen, in, (size_t)n); md->sha256.curlen += n; in += n; inlen -= n; if (md->sha256.curlen == SHA256_BLOCK_SIZE) { if ((err = sha256_compress(md, md->sha256.buf)) != 0) { return err; } md->sha256.length += 8*SHA256_BLOCK_SIZE; md->sha256.curlen = 0; } } } return 0; } /** Initialize the hash state @param md The hash state you wish to initialize @return CRYPT_OK if successful */ int sha256_init(hash_state * md) { if (md == NULL) return -1; md->sha256.curlen = 0; md->sha256.length = 0; md->sha256.state[0] = 0x6A09E667UL; md->sha256.state[1] = 0xBB67AE85UL; md->sha256.state[2] = 0x3C6EF372UL; md->sha256.state[3] = 0xA54FF53AUL; md->sha256.state[4] = 0x510E527FUL; md->sha256.state[5] = 0x9B05688CUL; md->sha256.state[6] = 0x1F83D9ABUL; md->sha256.state[7] = 0x5BE0CD19UL; return 0; } /** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (32 bytes) @return 0 if successful */ int sha256_done(hash_state * md, unsigned char *out) { int i; if (md == NULL || out == NULL) return -1; if (md->sha256.curlen >= sizeof(md->sha256.buf)) return -1; /* increase the length of the message */ md->sha256.length += md->sha256.curlen * 8; /* append the '1' bit */ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80; /* if the length is currently above 56 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->sha256.curlen > 56) { while (md->sha256.curlen < 64) { md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; } sha256_compress(md, md->sha256.buf); md->sha256.curlen = 0; } /* pad upto 56 bytes of zeroes */ while (md->sha256.curlen < 56) { md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->sha256.length, md->sha256.buf+56); sha256_compress(md, md->sha256.buf); /* copy output */ for (i = 0; i < 8; i++) { STORE32H(md->sha256.state[i], out+(4*i)); } return 0; } int sha256_buffer(const unsigned char *buffer, size_t len, unsigned char hash[32]) { hash_state md; int ret = 0; ret |= sha256_init(&md); ret |= sha256_process(&md, buffer, len); ret |= sha256_done(&md, hash); return ret; } tboot-1.10.5/tboot/common/sha384.c0000644000000000000000000000331414210363175014653 0ustar 00000000000000/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. */ #include #include /** Initialize the hash state @param md The hash state you wish to initialize @return CRYPT_OK if successful */ int sha384_init(hash_state * md) { if (md == NULL) { return -1; } md->sha512.curlen = 0; md->sha512.length = 0; md->sha512.state[0] = CONST64(0xcbbb9d5dc1059ed8); md->sha512.state[1] = CONST64(0x629a292a367cd507); md->sha512.state[2] = CONST64(0x9159015a3070dd17); md->sha512.state[3] = CONST64(0x152fecd8f70e5939); md->sha512.state[4] = CONST64(0x67332667ffc00b31); md->sha512.state[5] = CONST64(0x8eb44a8768581511); md->sha512.state[6] = CONST64(0xdb0c2e0d64f98fa7); md->sha512.state[7] = CONST64(0x47b5481dbefa4fa4); return 0; } /** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (48 bytes) @return CRYPT_OK if successful */ int sha384_done(hash_state * md, unsigned char *out) { unsigned char buf[64]; if (md == NULL || out == NULL) { return -1; } if (md->sha512.curlen >= sizeof(md->sha512.buf)) { return -1; } sha512_done(md, buf); tb_memcpy(out, buf, 48); return 0; } int sha384_buffer(const unsigned char *buffer, size_t len, unsigned char hash[48]) { hash_state md; int ret = 0; ret |= sha384_init(&md); ret |= sha384_process(&md, buffer, len); ret |= sha384_done(&md, hash); return ret; }tboot-1.10.5/tboot/common/sha512.c0000644000000000000000000002075614210363175014655 0ustar 00000000000000/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. */ #include #include /* the K array */ static const u64 K[80] = { CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) }; /* Various logical functions */ #define ROR64c(x, y) \ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((u64)(y)&CONST64(63))) | \ ((x)<<(((u64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF)) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) ROR64c(x, n) #define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((u64)n)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) /* compress 1024-bits */ static int sha512_compress(hash_state * md, const unsigned char *buf) { u64 S[8], W[80], t0, t1; int i; /* copy state into S */ for (i = 0; i < 8; i++) { S[i] = md->sha512.state[i]; } /* copy the state into 1024-bits into W[0..15] */ for (i = 0; i < 16; i++) { LOAD64H(W[i], buf + (8*i)); } /* fill W[16..79] */ for (i = 16; i < 80; i++) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i) \ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; for (i = 0; i < 80; i += 8) { RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); } /* feedback */ for (i = 0; i < 8; i++) { md->sha512.state[i] = md->sha512.state[i] + S[i]; } return 0; } /** Initialize the hash state @param md The hash state you wish to initialize @return CRYPT_OK if successful */ int sha512_init(hash_state * md) { if (md == NULL) { return -1; } md->sha512.curlen = 0; md->sha512.length = 0; md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); md->sha512.state[4] = CONST64(0x510e527fade682d1); md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); md->sha512.state[7] = CONST64(0x5be0cd19137e2179); return 0; } /** Process a block of memory though the hash @param md The hash state @param in The data to hash @param inlen The length of the data (octets) @return 0 if successful */ int sha512_process(hash_state * md, const unsigned char *in, u32 inlen) { unsigned long n; int err; if (md == NULL || in == NULL) { return -1; } if (md->sha512.curlen > sizeof(md->sha512.buf)) { return -1; } if ((md->sha512.length + inlen) < md->sha512.length) { return -1; } while (inlen > 0) { if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCK_SIZE) { if ((err = sha512_compress (md, in)) != 0) { return err; } md->sha512.length += SHA512_BLOCK_SIZE * 8; in += SHA512_BLOCK_SIZE; inlen -= SHA512_BLOCK_SIZE; } else { n = MIN(inlen, (SHA512_BLOCK_SIZE - md->sha512.curlen)); tb_memcpy(md->sha512.buf + md->sha512.curlen, in, (size_t)n); md->sha512.curlen += n; in += n; inlen -= n; if (md->sha512.curlen == SHA512_BLOCK_SIZE) { if ((err = sha512_compress (md, md->sha512.buf)) != 0) { return err; } md->sha512.length += 8*SHA512_BLOCK_SIZE; md->sha512.curlen = 0; } } } return 0; } /** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (64 bytes) @return CRYPT_OK if successful */ int sha512_done(hash_state * md, unsigned char *out) { int i; if (md == NULL || out == NULL) { return -1; } if (md->sha512.curlen >= sizeof(md->sha512.buf)) { return -1; } /* increase the length of the message */ md->sha512.length += md->sha512.curlen * CONST64(8); /* append the '1' bit */ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->sha512.curlen > 112) { while (md->sha512.curlen < 128) { md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; } sha512_compress(md, md->sha512.buf); md->sha512.curlen = 0; } /* pad upto 120 bytes of zeroes * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ while (md->sha512.curlen < 120) { md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->sha512.length, md->sha512.buf+120); sha512_compress(md, md->sha512.buf); /* copy output */ for (i = 0; i < 8; i++) { STORE64H(md->sha512.state[i], out+(8*i)); } return 0; } int sha512_buffer(const unsigned char *buffer, size_t len, unsigned char hash[64]) { hash_state md; int ret = 0; ret |= sha512_init(&md); ret |= sha512_process(&md, buffer, len); ret |= sha512_done(&md, hash); return ret; }tboot-1.10.5/tboot/common/shutdown.S0000644000000000000000000000756714210363175015512 0ustar 00000000000000/* * shutdown.S: assembly extry points for shutdown * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ compat_mode_entry: /* Disable PCID */ movl %cr4, %eax andl $~CR4_PCIDE, %eax movl %eax, %cr4 /* Disable paging and therefore leave 64 bit mode. */ movl %cr0, %eax andl $~CR0_PG, %eax movl %eax, %cr0 /* Clear MSR_EFER[LME], disabling long mode */ movl $MSR_EFER,%ecx rdmsr btcl $_EFER_LME,%eax wrmsr jmp 1f 1: /* fall through to shutdown_entry32 */ shutdown_entry32: /* restore tboot context */ lgdt %cs:gdt_descr mov $(ds_sel),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%fs mov %ecx,%gs mov %ecx,%ss ljmp $(cs_sel),$(1f) 1: leal bsp_stack,%esp # default to BSP stack # BSP has separate stack (above) movl $MSR_APICBASE,%ecx rdmsr andl $APICBASE_BSP,%eax jnz 3f # get initial APIC ID for this processor mov $0x01, %eax xor %ebx, %ebx cpuid shr $24, %ebx # set stack as id-based offset from AP stack base # "truncate" if too big so that we at least have a stack # (even if shared with another AP) cmp $NR_CPUS, %ebx jl 2f mov $NR_CPUS-1, %ebx 2: mov $AP_STACK_SIZE, %eax mul %ebx mov $ap_stacks, %ecx sub %eax, %ecx mov %ecx, %esp 3: /* Reset EFLAGS (subsumes CLI and CLD). */ pushl $0x0 popf /* Load IDT */ lidt idt_descr /* disable paging */ mov %cr0, %eax and $~CR0_PG, %eax mov %eax, %cr0 jmp 1f 1: /* clear cr4 except for SMXE */ mov $0x4000, %eax mov %eax, %cr4 /* true shutdown work for tboot */ call shutdown ud2 /* * unified (32b/64b) shutdown entry point */ ENTRY(shutdown_entry) .code64 cli wbinvd movl $MSR_EFER,%ecx rdmsr bt $_EFER_LME,%eax jnc shutdown_entry32 lgdt gdt_descr(%rip) mov $(ds_sel),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%fs mov %ecx,%gs mov %ecx,%ss 1: /* Jump to low identity mapping in compatibility mode. */ ljmp *compatibility_mode_far(%rip) ud2 compatibility_mode_far: .long compat_mode_entry .word cs_sel .code32 tboot-1.10.5/tboot/common/strcmp.c0000644000000000000000000000375714210363175015164 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* * From: FreeBSD sys/libkern/strcmp.c */ #include /* * Compare strings. */ int tb_strcmp(s1, s2) register const char *s1, *s2; { if (s1 == NULL || s2 == NULL) return(-1); if (s1 == s2) return(0); while (*s1 == *s2++) if (*s1++ == 0) return (0); return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); } tboot-1.10.5/tboot/common/strlen.c0000644000000000000000000000341614210363175015153 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* * From: FreeBSD sys/libkern/strlen.c */ #include size_t tb_strlen(str) const char *str; { register const char *s; if (str == NULL) return 0; for (s = str; *s; ++s); return(s - str); } tboot-1.10.5/tboot/common/strncmp.c0000644000000000000000000000371314210363175015332 0ustar 00000000000000/*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* * From: FreeBSD sys/libkern/strncmp.c */ #include int tb_strncmp(s1, s2, n) register const char *s1, *s2; register size_t n; { if (s1 == NULL || s2 == NULL) return(-1); if (n == 0 || s1 == s2) return (0); do { if (*s1 != *s2++) return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); if (*s1++ == 0) break; } while (--n != 0); return (0); } tboot-1.10.5/tboot/common/strncpy.c0000644000000000000000000000424714210363175015351 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. */ /* * From: FreeBSD sys/libkern/strncpy.c */ #include /* * Copy src to dst, truncating or null-padding to always copy n bytes. * Return dst. */ char *tb_strncpy(char * __restrict dst, const char * __restrict src, size_t n) { if (dst == NULL || src == NULL) return NULL; if (n != 0) { register char *d = dst; register const char *s = src; do { if ((*d++ = *s++) == 0) { /* NUL pad the remaining n-1 bytes */ while (--n != 0) *d++ = 0; break; } } while (--n != 0); } return (dst); } tboot-1.10.5/tboot/common/strtoul.c0000644000000000000000000000617414210363175015364 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * * From: @(#)strtoul.c 8.1 (Berkeley) 6/4/93 */ /* $FreeBSD: src/sys/libkern/strtoul.c,v 1.6.32.1 2010/02/10 00:26:20 kensmith Exp $ */ #include #include #define ULONG_MAX 0xFFFFFFFFUL /* * Convert a string to an unsigned long integer. * * Ignores `locale' stuff. Assumes that the upper and lower case * alphabets and digits are each contiguous. */ unsigned long tb_strtoul(const char *nptr, char **endptr, int base) { const char *s = nptr; unsigned long acc; unsigned char c; unsigned long cutoff; int neg = 0, any, cutlim; if (nptr == NULL) return ULONG_MAX; /* * See strtol for comments as to the logic used. */ do { c = *s++; } while (isspace(c)); if (c == '-') { neg = 1; c = *s++; } else if (c == '+') c = *s++; if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; s += 2; base = 16; } if (base == 0) base = c == '0' ? 8 : 10; cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; for (acc = 0, any = 0;; c = *s++) { if (isdigit(c)) c -= '0'; else if (isalpha(c)) c -= isupper(c) ? 'A' - 10 : 'a' - 10; else break; if (c >= base) break; if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) any = -1; else { any = 1; acc *= base; acc += c; } } if (any < 0) { acc = ULONG_MAX; } else if (neg) acc = -acc; if (endptr != 0) *((const char **)endptr) = any ? s - 1 : nptr; return (acc); } tboot-1.10.5/tboot/common/tb_error.c0000644000000000000000000001454314210363175015465 0ustar 00000000000000/* * tb_error.c: support functions for tb_error_t type * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TB_LAUNCH_ERR_IDX 0x20000002 /* launch error index */ static bool no_err_idx; /* * print_tb_error_msg * * print tb policy error message * */ void print_tb_error_msg(tb_error_t error) { switch( error ) { case TB_ERR_NONE: printk(TBOOT_INFO"succeeded.\n"); break; case TB_ERR_FIXED: printk(TBOOT_INFO"previous error has been fixed.\n"); break; case TB_ERR_GENERIC: printk(TBOOT_WARN"non-fatal generic error.\n"); break; case TB_ERR_TPM_NOT_READY: printk(TBOOT_WARN"TPM not ready.\n"); break; case TB_ERR_SMX_NOT_SUPPORTED: printk(TBOOT_WARN"SMX not supported.\n"); break; case TB_ERR_VMX_NOT_SUPPORTED: printk(TBOOT_ERR"VMX not supported.\n"); break; case TB_ERR_VTD_NOT_SUPPORTED: printk(TBOOT_ERR"DMAR table not found. Check if Vt-D is enabled in BIOS.\n"); break; case TB_ERR_TXT_NOT_SUPPORTED: printk(TBOOT_ERR"TXT not supported.\n"); break; case TB_ERR_MODULES_NOT_IN_POLICY: printk(TBOOT_ERR"modules in mbi but not in policy.\n"); break; case TB_ERR_MODULE_VERIFICATION_FAILED: printk(TBOOT_ERR"verifying module against policy failed.\n"); break; case TB_ERR_POLICY_INVALID: printk(TBOOT_ERR"policy invalid.\n"); break; case TB_ERR_POLICY_NOT_PRESENT: printk(TBOOT_WARN"no policy in TPM NV.\n"); break; case TB_ERR_SINIT_NOT_PRESENT: printk(TBOOT_WARN"SINIT ACM not provided.\n"); break; case TB_ERR_ACMOD_VERIFY_FAILED: printk(TBOOT_WARN"verifying AC module failed.\n"); break; case TB_ERR_POST_LAUNCH_VERIFICATION: printk(TBOOT_ERR"verification of post-launch failed.\n"); break; case TB_ERR_S3_INTEGRITY: printk(TBOOT_ERR"creation or verification of S3 measurements failed.\n"); break; case TB_ERR_FATAL: printk(TBOOT_ERR"generic fatal error.\n"); break; case TB_ERR_NV_VERIFICATION_FAILED: printk(TBOOT_ERR"verifying nv against policy failed.\n"); break; case TB_ERR_PREV_TXT_ERROR: printk(TBOOT_ERR"previous measured launch had errors, skipping measured launch...\n"); break; default: printk(TBOOT_ERR"unknown error (%d).\n", error); break; } } /* * read_tb_error_code * * read error code from TPM NV (TB_LAUNCH_ERR_IDX) * */ bool read_tb_error_code(tb_error_t *error) { uint32_t size = sizeof(tb_error_t); struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); if ( error == NULL ) { printk(TBOOT_ERR"Error: error pointer is zero.\n"); return false; } tb_memset(error, 0, size); if ( get_tboot_ignore_prev_err() ) return true; /* read! */ if ( !tpm_fp->nv_read(tpm, 0, tpm->tb_err_index, 0, (uint8_t *)error, &size) ) { printk(TBOOT_WARN"Error: read TPM error: 0x%x.\n", tpm->error); no_err_idx = true; return false; } no_err_idx = false; return true; } /* * write_tb_error_code * * write error code into TPM NV (TB_LAUNCH_ERR_IDX) * */ bool write_tb_error_code(tb_error_t error) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); if ( get_tboot_ignore_prev_err() ) return true; if ( !tpm || !tpm_fp || no_err_idx ) return false; if ( !tpm_fp->nv_write(tpm, tpm->cur_loc, tpm->tb_err_index, 0, (uint8_t *)&error, sizeof(tb_error_t)) ) { printk(TBOOT_WARN"Error: write TPM error: 0x%x.\n", tpm->error); no_err_idx = true; return false; } return true; } /* * was_last_boot_error * false: no error; true: error */ bool was_last_boot_error(void) { tb_error_t error; txt_errorcode_t txt_err; /* check TB_LAUNCH_ERR_IDX */ if ( read_tb_error_code(&error) ) { if ( error != TB_ERR_FIXED && error != TB_ERR_NONE ) return true; } /* check TXT.ERRORCODE */ txt_err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); if ( txt_err.valid && txt_err.type > 0 ) return true; return false; } tboot-1.10.5/tboot/common/tboot.c0000644000000000000000000005766214210363175015007 0ustar 00000000000000/* * tboot.c: main entry point and "generic" routines for measured launch * support * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern void _prot_to_real(uint32_t dist_addr); extern bool set_policy(void); extern void verify_all_modules(loader_ctx *lctx); extern void verify_all_nvindices(void); extern void apply_policy(tb_error_t error); extern void verify_IA32_se_svn_status(const acm_hdr_t *acm_hdr); void s3_launch(void); extern __data u32 handle2048; extern __data tpm_contextsave_out tpm2_context_saved; /* counter timeout for waiting for all APs to exit guests */ #define AP_GUEST_EXIT_TIMEOUT 0x01000000 extern long s3_flag; extern char s3_wakeup_16[]; extern char s3_wakeup_end[]; extern atomic_t ap_wfs_count; extern struct mutex ap_lock; /* loader context struct saved so that post_launch() can use it */ __data loader_ctx g_loader_ctx = { NULL, 0 }; __data loader_ctx *g_ldr_ctx = &g_loader_ctx; __data uint32_t g_mb_orig_size = 0; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; /* * caution: must make sure the total wakeup entry code length * (s3_wakeup_end - s3_wakeup_16) can fit into one page. */ static __data uint8_t g_saved_s3_wakeup_page[PAGE_SIZE]; unsigned long get_tboot_mem_end(void) { return PAGE_UP((unsigned long)&_end); } static tb_error_t verify_platform(void) { return txt_verify_platform(); } static bool is_launched(void) { if ( supports_txt() == TB_ERR_NONE ) return txt_is_launched(); else return false; } static bool prepare_cpu(void) { return txt_prepare_cpu(); } static void copy_s3_wakeup_entry(void) { if ( s3_wakeup_end - s3_wakeup_16 > PAGE_SIZE ) { printk(TBOOT_ERR"S3 entry is too large to be copied into one page!\n"); return; } /* backup target address space first */ tb_memcpy(g_saved_s3_wakeup_page, (void *)TBOOT_S3_WAKEUP_ADDR, s3_wakeup_end - s3_wakeup_16); /* copy s3 entry into target mem */ tb_memcpy((void *)TBOOT_S3_WAKEUP_ADDR, s3_wakeup_16, s3_wakeup_end - s3_wakeup_16); } static void restore_saved_s3_wakeup_page(void) { /* restore saved page */ tb_memcpy((void *)TBOOT_S3_WAKEUP_ADDR, g_saved_s3_wakeup_page, s3_wakeup_end - s3_wakeup_16); } static inline void print_tboot_shared(const tboot_shared_t *tboot_shared) { printk(TBOOT_DETA"tboot_shared data:\n"); printk(TBOOT_DETA"\t version: %d\n", tboot_shared->version); printk(TBOOT_DETA"\t log_addr: 0x%08x\n", tboot_shared->log_addr); printk(TBOOT_DETA"\t shutdown_entry: 0x%08x\n", tboot_shared->shutdown_entry); printk(TBOOT_DETA"\t shutdown_type: %d\n", tboot_shared->shutdown_type); printk(TBOOT_DETA"\t tboot_base: 0x%08x\n", tboot_shared->tboot_base); printk(TBOOT_DETA"\t tboot_size: 0x%x\n", tboot_shared->tboot_size); printk(TBOOT_DETA"\t num_in_wfs: %u\n", tboot_shared->num_in_wfs); printk(TBOOT_DETA"\t flags: 0x%8.8x\n", tboot_shared->flags); printk(TBOOT_DETA"\t ap_wake_addr: 0x%08x\n", (uint32_t)tboot_shared->ap_wake_addr); printk(TBOOT_DETA"\t ap_wake_trigger: %u\n", tboot_shared->ap_wake_trigger); } static void post_launch(void) { uint64_t base, size; tb_error_t err; struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); extern tboot_log_t *g_log; extern void shutdown_entry(void); printk(TBOOT_INFO"measured launch succeeded\n"); /* init MLE/kernel shared data page early, .num_in_wfs used in ap wakeup*/ _tboot_shared.num_in_wfs = 0; txt_post_launch(); /* backup DMAR table */ if ( get_tboot_save_vtd() ) vtd_save_dmar_table(); if ( s3_flag ) s3_launch(); /* remove all TXT sinit acm modules before verifying modules */ remove_txt_modules(g_ldr_ctx); /* * verify e820 table and adjust it to protect our memory regions */ /* marked mem regions used by TXT (heap, SINIT, etc.) as E820_RESERVED */ err = txt_protect_mem_regions(); apply_policy(err); /* ensure all modules are in RAM */ if ( !verify_modules(g_ldr_ctx) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* verify that tboot is in valid RAM (i.e. E820_RAM) */ base = (uint64_t)TBOOT_BASE_ADDR; size = (uint64_t)((unsigned long)&_end - base); printk(TBOOT_INFO"verifying tboot and its page table (%Lx - %Lx) in e820 table\n\t", base, (base + size - 1)); if ( e820_check_region(base, size) != E820_RAM ) { printk(TBOOT_ERR": failed.\n"); apply_policy(TB_ERR_FATAL); } else printk(TBOOT_INFO": succeeded.\n"); /* protect ourselves, MLE page table, and MLE/kernel shared page */ base = (uint64_t)TBOOT_BASE_ADDR; size = (uint64_t)get_tboot_mem_end() - base; uint32_t mem_type = is_kernel_linux() ? E820_RESERVED : E820_UNUSABLE; printk(TBOOT_INFO"protecting tboot (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, mem_type) ) apply_policy(TB_ERR_FATAL); if (!efi_memmap_reserve(base, size)) { apply_policy(TB_ERR_FATAL); } /* * verify modules against policy */ verify_all_modules(g_ldr_ctx); /* * verify nv indices against policy */ if ( (tpm->major == TPM12_VER_MAJOR) && get_tboot_measure_nv() ) verify_all_nvindices(); /* * seal hashes of modules and VL policy to current value of PCR17 & 18 */ if ( !seal_pre_k_state() ) apply_policy(TB_ERR_S3_INTEGRITY); if ( tpm->major == TPM20_VER_MAJOR ) { tpm_fp->context_save(tpm, tpm->cur_loc, handle2048, &tpm2_context_saved); } /* * init MLE/kernel shared data page */ tb_memset(&_tboot_shared, 0, PAGE_SIZE); _tboot_shared.uuid = (uuid_t)TBOOT_SHARED_UUID; _tboot_shared.version = 6; _tboot_shared.log_addr = (uint32_t)g_log; _tboot_shared.shutdown_entry = (uint32_t)shutdown_entry; _tboot_shared.tboot_base = (uint32_t)&_start; _tboot_shared.tboot_size = (uint32_t)&_end - (uint32_t)&_start; uint32_t key_size = sizeof(_tboot_shared.s3_key); if ( !tpm_fp->get_random(tpm, 2, _tboot_shared.s3_key, &key_size) || key_size != sizeof(_tboot_shared.s3_key) ) apply_policy(TB_ERR_S3_INTEGRITY); _tboot_shared.num_in_wfs = atomic_read(&ap_wfs_count); if ( use_mwait() ) { _tboot_shared.flags |= TB_FLAG_AP_WAKE_SUPPORT; _tboot_shared.ap_wake_trigger = AP_WAKE_TRIGGER_DEF; } else if ( get_tboot_mwait() ) { printk(TBOOT_ERR"ap_wake_mwait specified but the CPU doesn't support it.\n"); } print_tboot_shared(&_tboot_shared); launch_kernel(true); apply_policy(TB_ERR_FATAL); } void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec) { printk(TBOOT_INFO"cpu %u waking up, SIPI vector=%x\n", cpuid, sipi_vec); /* change to real mode and then jump to SIPI vector */ _prot_to_real(sipi_vec); } #define ICR_LOW 0x300 void startup_rlps(void) { uint32_t rlp_count = ((cpuid_ecx(1) >> 16) & 0xff) - 1; uint32_t apicbase = (uint32_t)rdmsr(MSR_APICBASE) & 0xfffffffffffff000; if ( rlp_count == 0 ) return; /* send init ipi to all rlp -- Dest Shorthand: 11, Delivery Mode: 101 */ writel(apicbase + ICR_LOW, 0xc0500); } void launch_racm(void) { tb_error_t err; /* bsp check & tpm check done by caller */ /* SMX must be supported */ if ( !(cpuid_ecx(1) & CPUID_X86_FEATURE_SMX) ) apply_policy(TB_ERR_SMX_NOT_SUPPORTED); /* Enable SMX */ write_cr4(read_cr4() | CR4_SMXE); /* prepare cpu */ if ( !prepare_cpu() ) apply_policy(TB_ERR_FATAL); /* prepare tpm */ if ( !prepare_tpm() ) apply_policy(TB_ERR_TPM_NOT_READY); /* Place RLPs in Wait for SIPI state */ startup_rlps(); /* Verify loader context */ if ( !verify_loader_context(g_ldr_ctx) ) apply_policy(TB_ERR_FATAL); /* load racm */ err = txt_launch_racm(g_ldr_ctx); apply_policy(err); } static void shutdown_system(uint32_t); void check_racm_result(void) { txt_get_racm_error(); shutdown_system(TB_SHUTDOWN_HALT); } void begin_launch(void *addr, uint32_t magic) { tb_error_t err; if (g_ldr_ctx->type == 0) determine_loader_type(addr, magic); /* on pre-SENTER boot, copy command line to buffer in tboot image (so that it will be measured); buffer must be 0 -filled */ if ( !is_launched() && !s3_flag ) { const char *cmdline_orig = get_cmdline(g_ldr_ctx); const char *cmdline = NULL; if (cmdline_orig){ // cmdline = skip_filename(cmdline_orig); cmdline = cmdline_orig; } tb_memset(g_cmdline, '\0', sizeof(g_cmdline)); if (cmdline) tb_strncpy(g_cmdline, cmdline, sizeof(g_cmdline)-1); } /* always parse cmdline */ tboot_parse_cmdline(); /* initialize all logging targets */ if ((is_launched() && get_framebuffer_info(g_ldr_ctx) != NULL) || s3_flag) { /* * We are using framebuffer method for printing VGA logs. It does not * when PMRs are programmed, so in post-launch we have to disable VGA * logging. */ printk_init(true); } else { printk_init(false); } printk(TBOOT_INFO"*********************** TBOOT ***********************\n"); printk(TBOOT_INFO" %s\n", TBOOT_CHANGESET); printk(TBOOT_INFO"*****************************************************\n"); printk(TBOOT_INFO"command line: %s\n", g_cmdline); /* if telled to check revocation acm result, go with simplified path */ if ( get_tboot_call_racm_check() ) check_racm_result(); /* never return */ if (is_launched()) printk(TBOOT_INFO"SINIT ACM successfully returned...\n"); if ( s3_flag ) printk(TBOOT_INFO"Resume from S3...\n"); /* RLM scaffolding if (g_ldr_ctx->type == 2) print_loader_ctx(g_ldr_ctx); */ /* clear resume vector on S3 resume so any resets will not use it */ if ( !is_launched() && s3_flag ) set_s3_resume_vector(&_tboot_shared.acpi_sinfo, 0); /* we should only be executing on the BSP */ if ( !(rdmsr(MSR_APICBASE) & APICBASE_BSP) ) { printk(TBOOT_INFO"entry processor is not BSP\n"); apply_policy(TB_ERR_FATAL); } printk(TBOOT_INFO"BSP is cpu %u\n", get_apicid()); /* make copy of e820 map that we will use and adjust */ if ( !s3_flag ) { if ( !copy_e820_map(g_ldr_ctx) ) apply_policy(TB_ERR_FATAL); if (efi_memmap_copy(g_ldr_ctx)) { if (get_tboot_dump_memmap()) { printk(TBOOT_INFO"Original EFI memory map:\n"); efi_memmap_dump(); } } } /* we need to make sure this is a (TXT-) capable platform before using */ /* any of the features, incl. those required to check if the environment */ /* has already been launched */ if (g_sinit == NULL) { find_platform_sinit_module(g_ldr_ctx, (void **)&g_sinit, NULL); /* check if it is newer than BIOS provided version, then copy it to BIOS reserved region */ g_sinit = copy_sinit(g_sinit); if (g_sinit == NULL) apply_policy(TB_ERR_SINIT_NOT_PRESENT); if (!verify_acmod(g_sinit)) apply_policy(TB_ERR_ACMOD_VERIFY_FAILED); } /* make TPM ready for measured launch */ if (!tpm_detect()) apply_policy(TB_ERR_TPM_NOT_READY); /* verify SE enablement status */ verify_IA32_se_svn_status(g_sinit); /* read tboot verified launch control policy from TPM-NV (will use default if none in TPM-NV) */ err = set_policy(); apply_policy(err); /* if telled to call revocation acm, go with simplified path */ if ( get_tboot_call_racm() ) launch_racm(); /* never return */ /* need to verify that platform supports TXT before we can check error */ /* (this includes TPM support) */ err = supports_txt(); apply_policy(err); /* print any errors on last boot, which must be from TXT launch */ txt_display_errors(); if (txt_has_error() && get_tboot_ignore_prev_err() == false) { apply_policy(TB_ERR_PREV_TXT_ERROR); } /* need to verify that platform can perform measured launch */ err = verify_platform(); apply_policy(err); /* ensure there are modules */ if ( !s3_flag && !verify_loader_context(g_ldr_ctx) ) apply_policy(TB_ERR_FATAL); /* this is being called post-measured launch */ if ( is_launched() ){ printk(TBOOT_INFO"Post_launch started ...\n"); post_launch(); } /* make the CPU ready for measured launch */ if ( !prepare_cpu() ) apply_policy(TB_ERR_FATAL); /* do s3 launch directly, if is a s3 resume */ if ( s3_flag ) { if ( !prepare_tpm() ) apply_policy(TB_ERR_TPM_NOT_READY); txt_s3_launch_environment(); printk(TBOOT_ERR"we should never get here\n"); apply_policy(TB_ERR_FATAL); } /* check for error from previous boot */ printk(TBOOT_INFO"checking previous errors on the last boot.\n\t"); if ( was_last_boot_error() ) printk(TBOOT_INFO"last boot has error.\n"); else printk(TBOOT_INFO"last boot has no error.\n"); if ( !prepare_tpm() ) apply_policy(TB_ERR_TPM_NOT_READY); /* launch the measured environment */ err = txt_launch_environment(g_ldr_ctx); apply_policy(err); } void s3_launch(void) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); /* restore backed-up s3 wakeup page */ restore_saved_s3_wakeup_page(); /* load saved tpm2 context for unseal */ if ( tpm->major == TPM20_VER_MAJOR ) { tpm_fp->context_flush(tpm, tpm->cur_loc, handle2048); tpm_fp->context_load(tpm, tpm->cur_loc, &tpm2_context_saved, &handle2048); } /* remove DMAR table if necessary */ if ( get_tboot_save_vtd() ) vtd_remove_dmar_table(); if ( !is_launched() ) apply_policy(TB_ERR_S3_INTEGRITY); else { /* this is being called post-measured launch */ /* verify saved hash integrity and re-extend PCRs */ if ( !verify_integrity() ) apply_policy(TB_ERR_S3_INTEGRITY); } print_tboot_shared(&_tboot_shared); if (g_tpm_family != TPM_IF_20_CRB ) { if (!release_locality(tpm->cur_loc)) printk(TBOOT_ERR"Release TPM FIFO locality %d failed \n", tpm->cur_loc); } else { if (!tpm_relinquish_locality_crb(tpm->cur_loc)) printk(TBOOT_ERR"Relinquish TPM CRB locality %d failed \n", tpm->cur_loc); } /* (optionally) pause when transferring kernel resume */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); _prot_to_real(g_post_k_s3_state.kernel_s3_resume_vector); } static void shutdown_system(uint32_t shutdown_type) { static const char *types[] = { "TB_SHUTDOWN_REBOOT", "TB_SHUTDOWN_S5", "TB_SHUTDOWN_S4", "TB_SHUTDOWN_S3", "TB_SHUTDOWN_HALT" }; char type[32]; if ( shutdown_type >= ARRAY_SIZE(types) ) tb_snprintf(type, sizeof(type), "unknown: %u", shutdown_type); else { tb_strncpy(type, types[shutdown_type], sizeof(type)); type[sizeof(type) - 1] = '\0'; } printk(TBOOT_INFO"shutdown_system() called for shutdown_type: %s\n", type); switch( shutdown_type ) { case TB_SHUTDOWN_S3: copy_s3_wakeup_entry(); /* write our S3 resume vector to ACPI resume addr */ set_s3_resume_vector(&_tboot_shared.acpi_sinfo, TBOOT_S3_WAKEUP_ADDR); /* fall through for rest of Sx handling */ /* FALLTHROUGH */ case TB_SHUTDOWN_S4: case TB_SHUTDOWN_S5: machine_sleep(&_tboot_shared.acpi_sinfo); /* if machine_sleep() fails, fall through to reset */ /* FALLTHROUGH */ case TB_SHUTDOWN_REBOOT: if ( txt_is_powercycle_required() ) { /* powercycle by writing 0x0a+0x0e to port 0xcf9 */ /* (supported by all TXT-capable chipsets) */ outb(0xcf9, 0x0a); outb(0xcf9, 0x0e); } else { /* soft reset by writing 0xfe to keyboard reset vector 0x64 */ /* BIOSes (that are not performing some special operation, */ /* such as update) will turn this into a platform reset as */ /* expected. */ outb(0x64, 0xfe); /* fall back to soft reset by writing 0x06 to port 0xcf9 */ /* (supported by all TXT-capable chipsets) */ outb(0xcf9, 0x06); } /* FALLTHROUGH */ case TB_SHUTDOWN_HALT: default: while ( true ) halt(); } } void shutdown(void) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); /* wait-for-sipi only invoked for APs, so skip all BSP shutdown code */ if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_WFS ) { atomic_inc(&ap_wfs_count); _tboot_shared.ap_wake_trigger = 0; mtx_enter(&ap_lock); printk(TBOOT_INFO"shutdown(): TB_SHUTDOWN_WFS\n"); if ( use_mwait() ) ap_wait(get_apicid()); else handle_init_sipi_sipi(get_apicid()); apply_policy(TB_ERR_FATAL); } printk(TBOOT_INFO"wait until all APs ready for txt shutdown\n"); while( atomic_read(&_tboot_shared.num_in_wfs) < atomic_read(&ap_wfs_count) ) cpu_relax(); /* ensure localities 0, 1 are inactive (in case kernel used them) */ /* request TPM current locality to be active */ if (g_tpm_family != TPM_IF_20_CRB ) { if (!release_locality(0)) printk(TBOOT_ERR"Release TPM FIFO locality 0 failed \n"); if (!release_locality(1)) printk(TBOOT_ERR"Release TPM FIFO locality 1 failed \n"); if (!tpm_wait_cmd_ready(tpm->cur_loc)) printk(TBOOT_ERR"Request TPM FIFO locality %d failed \n", tpm->cur_loc); } else { if (!tpm_relinquish_locality_crb(0)) printk(TBOOT_ERR"Release TPM CRB locality 0 failed \n"); if (!tpm_relinquish_locality_crb(1)) printk(TBOOT_ERR"Release TPM CRB locality 1 failed \n"); if (!tpm_request_locality_crb(tpm->cur_loc)) printk(TBOOT_ERR"Request TPM CRB locality %d failed \n", tpm->cur_loc); } if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_S3 ) { /* restore DMAR table if needed */ if ( get_tboot_save_vtd() ) vtd_restore_dmar_table(); if ( tpm->major == TPM20_VER_MAJOR ) { tpm_fp->context_flush(tpm, tpm->cur_loc, handle2048); tpm_fp->context_load(tpm, tpm->cur_loc, &tpm2_context_saved, &handle2048); } /* save kernel/VMM resume vector for sealing */ g_post_k_s3_state.kernel_s3_resume_vector = _tboot_shared.acpi_sinfo.kernel_s3_resume_vector; /* create and seal memory integrity measurement */ if ( !seal_post_k_state() ) apply_policy(TB_ERR_S3_INTEGRITY); /* OK to leave key in memory on failure since if user cared they would have policy that doesn't continue for TB_ERR_S3_INTEGRITY error */ else /* wipe S3 key from memory now that it is sealed */ tb_memset(_tboot_shared.s3_key, 0, sizeof(_tboot_shared.s3_key)); } /* cap dynamic PCRs extended as part of launch (17, 18, ...) */ if ( is_launched() ) { /* cap PCRs to ensure no follow-on code can access sealed data */ if (!tpm_fp->cap_pcrs(tpm, tpm->cur_loc, -1)) { printk(TBOOT_ERR"failed to cap PCRs\n"); apply_policy(TB_ERR_FATAL); } /* have TPM save static PCRs (in case VMM/kernel didn't) */ /* per TCG spec, TPM can invalidate saved state if any other TPM operation is performed afterwards--so do this last */ if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_S3 ) { if (tpm_fp->save_state(tpm, tpm->cur_loc) != 0) { printk(TBOOT_ERR"failed to save TPM state\n"); } } /* scrub any secrets by clearing their memory, then flush cache */ /* we don't have any secrets to scrub, however */ ; /* in mwait "mode", APs will be in MONITOR/MWAIT and can be left there */ if ( !use_mwait() ) { /* force APs to exit mini-guests if any are in and wait until */ /* all are out before shutting down TXT */ printk(TBOOT_INFO"waiting for APs (%u) to exit guests...\n", atomic_read(&ap_wfs_count)); force_aps_exit(); uint32_t timeout = AP_GUEST_EXIT_TIMEOUT; do { if ( timeout % 0x8000 == 0 ) printk(TBOOT_INFO"."); else cpu_relax(); if ( timeout % 0x200000 == 0 ) printk(TBOOT_INFO"\n"); timeout--; } while ( ( atomic_read(&ap_wfs_count) > 0 ) && timeout > 0 ); printk(TBOOT_INFO"\n"); if ( timeout == 0 ) printk(TBOOT_INFO"AP guest exit loop timed-out\n"); else printk(TBOOT_INFO"all APs exited guests\n"); } else { /* reset ap_wfs_count to avoid tboot hash changing in S3 case */ atomic_set(&ap_wfs_count, 0); } /* turn off TXT (GETSEC[SEXIT]) */ txt_shutdown(); } /* machine shutdown */ shutdown_system(_tboot_shared.shutdown_type); } void handle_exception(void) { printk(TBOOT_INFO"received exception; shutting down...\n"); _tboot_shared.shutdown_type = TB_SHUTDOWN_REBOOT; shutdown(); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/tboot.lds.x0000644000000000000000000000162414210363175015600 0ustar 00000000000000/* ld script to make i386 Linux kernel * Written by Martin Mares * Modified for i386 Xen by Keir Fraser * Modified for tboot by Joseph Cihula */ #include #undef ENTRY #undef ALIGN OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(start) PHDRS { text PT_LOAD ; } SECTIONS { . = TBOOT_BASE_ADDR; /* 0x800000 */ .text : { *(.tboot_multiboot_header) . = ALIGN(4096); *(.mlept) _mle_start = .; /* beginning of MLE pages */ *(.text) *(.fixup) *(.gnu.warning) *(.comment) } :text = 0x9090 .rodata : { *(.rodata) *(.rodata.*) } . = ALIGN(4096); _mle_end = .; /* end of MLE pages */ .data : { /* Data */ *(.data) *(.tboot_shared) CONSTRUCTORS } . = ALIGN(4096); __bss_start = .; /* BSS */ .bss : { *(.bss.stack_aligned) *(.bss.page_aligned) *(.bss) } _end = . ; } tboot-1.10.5/tboot/common/tpm.c0000644000000000000000000006712414210363175014452 0ustar 00000000000000/* * tpm.c: TPM-related support functions * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include __data uint8_t g_tpm_ver = TPM_VER_UNKNOWN; __data struct tpm_if g_tpm = { .cur_loc = 0, .timeout.timeout_a = TIMEOUT_A, .timeout.timeout_b = TIMEOUT_B, .timeout.timeout_c = TIMEOUT_C, .timeout.timeout_d = TIMEOUT_D, }; u16 tboot_alg_list[] = {TB_HALG_SHA1, TB_HALG_SHA256, TB_HALG_SHA384, TB_HALG_SHA512}; const uint8_t tboot_alg_list_count = ARRAY_SIZE(tboot_alg_list); /* Global variables for TPM status register */ static tpm20_reg_sts_t g_reg_sts, *g_reg_sts_20 = &g_reg_sts; static tpm12_reg_sts_t *g_reg_sts_12 = (tpm12_reg_sts_t *)&g_reg_sts; uint8_t g_tpm_family = 0; /* TPM_DATA_FIFO_x */ #define TPM_REG_DATA_FIFO 0x24 typedef union { uint8_t _raw[1]; /* 1-byte reg */ } tpm_reg_data_fifo_t; typedef union { uint8_t _raw[1]; } tpm_reg_data_crb_t; #define TPM_ACTIVE_LOCALITY_TIME_OUT \ (TIMEOUT_UNIT *get_tpm()->timeout.timeout_a) /* according to spec */ #define TPM_CMD_READY_TIME_OUT \ (TIMEOUT_UNIT *get_tpm()->timeout.timeout_b) /* according to spec */ #define TPM_CMD_WRITE_TIME_OUT \ (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ #define TPM_DATA_AVAIL_TIME_OUT \ (TIMEOUT_UNIT *get_tpm()->timeout.timeout_c) /* let it long enough */ #define TPM_RSP_READ_TIME_OUT \ (TIMEOUT_UNIT *get_tpm()->timeout.timeout_d) /* let it long enough */ #define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 #define read_tpm_sts_reg(locality) { \ if ( g_tpm_family == 0 ) \ read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ else \ read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ } #define write_tpm_sts_reg(locality) { \ if ( g_tpm_family == 0 ) \ write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \ else \ write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \ } static void tpm_send_cmd_ready_status(uint32_t locality) { /* write 1 to TPM_STS_x.commandReady to let TPM enter ready state */ tb_memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts)); g_reg_sts.command_ready = 1; write_tpm_sts_reg(locality); } static bool tpm_send_cmd_ready_status_crb(uint32_t locality) { tpm_reg_ctrl_request_t reg_ctrl_request; tpm_reg_ctrl_sts_t reg_ctrl_sts; read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"1. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); printk(TBOOT_INFO"1. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); #endif if ( reg_ctrl_sts.tpmidle == 1) { tb_memset(®_ctrl_request,0,sizeof(reg_ctrl_request)); reg_ctrl_request.cmdReady = 1; write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); return true; } tb_memset(®_ctrl_request,0,sizeof(reg_ctrl_request)); reg_ctrl_request.goIdle = 1; write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); uint32_t i = 0; do { read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); if ( reg_ctrl_request.goIdle == 0) break; else { cpu_relax(); read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); #ifdef TPM_TRACE printk(TBOOT_INFO"1. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle); printk(TBOOT_INFO"1. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady); #endif } i++; } while ( i <= TPM_DATA_AVAIL_TIME_OUT); if ( i > TPM_DATA_AVAIL_TIME_OUT ) { printk(TBOOT_ERR"TPM: reg_ctrl_request.goidle timeout!\n"); return false; } read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); printk(TBOOT_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); #endif tb_memset(®_ctrl_request,0,sizeof(reg_ctrl_request)); reg_ctrl_request.cmdReady = 1; write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); #ifdef TPM_TRACE printk(TBOOT_INFO"2. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle); printk(TBOOT_INFO"2. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady); #endif read_tpm_reg(locality, TPM_CRB_CTRL_STS, ®_ctrl_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle); printk(TBOOT_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts); #endif return true; } static bool tpm_check_cmd_ready_status_crb(uint32_t locality) { tpm_reg_ctrl_request_t reg_ctrl_request; read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); #ifdef TPM_TRACE printk(TBOOT_INFO"3. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle); printk(TBOOT_INFO"3. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady); #endif if ( reg_ctrl_request.cmdReady == 0) return true; else return false; } static bool tpm_check_cmd_ready_status(uint32_t locality) { read_tpm_sts_reg(locality); #ifdef TPM_TRACE printk(TBOOT_INFO"."); #endif return g_reg_sts.command_ready; } static void tpm_print_status_register(void) { if ( g_tpm_family == 0 ) { printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x\n", (uint32_t)g_reg_sts_12->_raw[0], (uint32_t)g_reg_sts_12->_raw[1], (uint32_t)g_reg_sts_12->_raw[2]); } else { printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x %02x\n", (uint32_t)g_reg_sts_20->_raw[0], (uint32_t)g_reg_sts_20->_raw[1], (uint32_t)g_reg_sts_20->_raw[2], (uint32_t)g_reg_sts_20->_raw[3]); } } static u16 tpm_get_burst_count(uint32_t locality) { read_tpm_sts_reg(locality); return g_reg_sts.burst_count; } static bool tpm_check_expect_status(uint32_t locality) { read_tpm_sts_reg(locality); #ifdef TPM_TRACE printk(TBOOT_INFO"Wait on Expect = 0, Status register %02x\n", g_reg_sts._raw[0]); #endif return g_reg_sts.sts_valid == 1 && g_reg_sts.expect == 0; } static bool tpm_check_da_status(uint32_t locality) { read_tpm_sts_reg(locality); #ifdef TPM_TRACE printk(TBOOT_INFO"Waiting for DA Flag, Status register %02x\n", g_reg_sts._raw[0]); #endif return g_reg_sts.sts_valid == 1 && g_reg_sts.data_avail == 1; } static void tpm_execute_cmd(uint32_t locality) { tb_memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts)); g_reg_sts.tpm_go = 1; write_tpm_sts_reg(locality); } bool tpm_validate_locality(uint32_t locality) { uint32_t i; tpm_reg_access_t reg_acc; for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) { /* * TCG spec defines reg_acc.tpm_reg_valid_sts bit to indicate whether * other bits of access reg are valid.( but this bit will also be 1 * while this locality is not available, so check seize bit too) * It also defines that reading reg_acc.seize should always return 0 */ read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); if ( reg_acc.tpm_reg_valid_sts == 1 && reg_acc.seize == 0) return true; cpu_relax(); } if ( i <= 0 ) printk(TBOOT_ERR"TPM: tpm_validate_locality timeout\n"); return false; } bool tpm_validate_locality_crb(uint32_t locality) { uint32_t i; tpm_reg_loc_state_t reg_loc_state; for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) { /* * Platfrom Tpm Profile for TPM 2.0 SPEC */ read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); if ( reg_loc_state.tpm_reg_valid_sts == 1 && reg_loc_state.loc_assigned == 1 && reg_loc_state.active_locality == locality) { printk(TBOOT_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", reg_loc_state._raw[0]); return true; } cpu_relax(); } printk(TBOOT_ERR"TPM: tpm_validate_locality_crb timeout\n"); printk(TBOOT_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", reg_loc_state._raw[0]); return false; } bool tpm_wait_cmd_ready(uint32_t locality) { uint32_t i; tpm_reg_access_t reg_acc; #if 0 /* some tpms doesn't always return 1 for reg_acc.tpm_reg_valid_sts */ /* and this bit was checked in tpm_validate_locality() already, */ /* so safe to skip the check here */ /* ensure the contents of the ACCESS register are valid */ read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); #ifdef TPM_TRACE printk(TBOOT_INFO"TPM: Access reg content: 0x%02x\n", (uint32_t)reg_acc._raw[0]); #endif if ( reg_acc.tpm_reg_valid_sts == 0 ) { printk(TBOOT_ERR"TPM: Access reg not valid\n"); return false; } #endif /* request access to the TPM from locality N */ reg_acc._raw[0] = 0; reg_acc.request_use = 1; write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); i = 0; do { read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); if ( reg_acc.active_locality == 1 ) break; else cpu_relax(); i++; } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) { printk(TBOOT_ERR"TPM: FIFO_INF access reg request use timeout\n"); return false; } /* ensure the TPM is ready to accept a command */ #ifdef TPM_TRACE printk(TBOOT_INFO"TPM: wait for cmd ready \n"); #endif i = 0; do { tpm_send_cmd_ready_status(locality); cpu_relax(); /* then see if it has */ if ( tpm_check_cmd_ready_status(locality) ) break; else cpu_relax(); i++; } while ( i <= TPM_CMD_READY_TIME_OUT ); #ifdef TPM_TRACE printk(TBOOT_INFO"\n"); #endif if ( i > TPM_CMD_READY_TIME_OUT ) { tpm_print_status_register(); printk(TBOOT_INFO"TPM: tpm timeout for command_ready\n"); goto RelinquishControl; } return true; RelinquishControl: /* deactivate current locality */ reg_acc._raw[0] = 0; reg_acc.active_locality = 1; write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); return false; } static bool tpm_wait_cmd_ready_crb(uint32_t locality) { uint32_t i; /* ensure the TPM is ready to accept a command */ #ifdef TPM_TRACE printk(TBOOT_INFO"TPM: wait for cmd ready \n"); #endif tpm_send_cmd_ready_status_crb(locality); i = 0; do { if ( tpm_check_cmd_ready_status_crb(locality) ) break; else cpu_relax(); i++; } while ( i <= TPM_CMD_READY_TIME_OUT ); if ( i > TPM_CMD_READY_TIME_OUT ) { //tpm_print_status_register(); printk(TBOOT_INFO"TPM: tpm timeout for command_ready\n"); goto RelinquishControl; } return true; RelinquishControl: /* deactivate current locality */ //tpm_reg_loc_ctrl_t reg_loc_ctrl; //reg_loc_ctrl._raw[0] = 0; //reg_loc_ctrl.relinquish = 1; //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); return false; } bool tpm_submit_cmd(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size) { u32 i, rsp_size, offset; u16 row_size; tpm_reg_access_t reg_acc; bool ret = true; if ( locality >= TPM_NR_LOCALITIES ) { printk(TBOOT_WARN"TPM: Invalid locality for tpm_write_cmd_fifo()\n"); return false; } if ( in == NULL || out == NULL || out_size == NULL ) { printk(TBOOT_WARN"TPM: Invalid parameter for tpm_write_cmd_fifo()\n"); return false; } if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) { printk(TBOOT_WARN"TPM: in/out buf size must be larger than 10 bytes\n"); return false; } if ( !tpm_validate_locality(locality) ) { printk(TBOOT_WARN"TPM: Locality %d is not open\n", locality); return false; } if ( !tpm_wait_cmd_ready(locality) ) return false; #ifdef TPM_TRACE { printk(TBOOT_DETA"TPM: cmd size = 0x%x\nTPM: cmd content: ", in_size); print_hex("TPM: \t", in, in_size); } #endif /* write the command to the TPM FIFO */ offset = 0; do { i = 0; do { /* find out how many bytes the TPM can accept in a row */ row_size = tpm_get_burst_count(locality); if ( row_size > 0 ) break; else cpu_relax(); i++; } while ( i <= TPM_CMD_WRITE_TIME_OUT ); if ( i > TPM_CMD_WRITE_TIME_OUT ) { printk(TBOOT_ERR"TPM: write cmd timeout\n"); ret = false; goto RelinquishControl; } for ( ; row_size > 0 && offset < in_size; row_size--, offset++ ) write_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&in[offset]); } while ( offset < in_size ); i = 0; do { if ( tpm_check_expect_status(locality) ) break; else cpu_relax(); i++; } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); if ( i > TPM_DATA_AVAIL_TIME_OUT ) { printk(TBOOT_ERR"TPM: wait for expect becoming 0 timeout\n"); ret = false; goto RelinquishControl; } /* command has been written to the TPM, it is time to execute it. */ tpm_execute_cmd(locality); /* check for data available */ i = 0; do { if ( tpm_check_da_status(locality) ) break; else cpu_relax(); i++; } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); if ( i > TPM_DATA_AVAIL_TIME_OUT ) { printk(TBOOT_ERR"TPM: wait for data available timeout\n"); ret = false; goto RelinquishControl; } rsp_size = 0; offset = 0; do { /* find out how many bytes the TPM returned in a row */ i = 0; do { row_size = tpm_get_burst_count(locality); if ( row_size > 0 ) break; else cpu_relax(); i++; } while ( i <= TPM_RSP_READ_TIME_OUT ); if ( i > TPM_RSP_READ_TIME_OUT ) { printk(TBOOT_ERR"TPM: read rsp timeout\n"); ret = false; goto RelinquishControl; } for ( ; row_size > 0 && offset < *out_size; row_size--, offset++ ) { if ( offset < *out_size ) read_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&out[offset]); else { /* discard the responded bytes exceeding out buf size */ tpm_reg_data_fifo_t discard; read_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&discard); } /* get outgoing data size */ if ( offset == RSP_RST_OFFSET - 1 ) { reverse_copy(&rsp_size, &out[RSP_SIZE_OFFSET], sizeof(rsp_size)); } } } while ( offset < RSP_RST_OFFSET || (offset < rsp_size && offset < *out_size) ); *out_size = (*out_size > rsp_size) ? rsp_size : *out_size; #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: response size = %d\n", *out_size); printk(TBOOT_DETA"TPM: response content: "); print_hex("TPM: \t", out, *out_size); } #endif tpm_send_cmd_ready_status(locality); RelinquishControl: /* deactivate current locality */ reg_acc._raw[0] = 0; reg_acc.active_locality = 1; write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); return ret; } bool tpm_submit_cmd_crb(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size) { uint32_t i; bool ret = true; //tpm_reg_loc_ctrl_t reg_loc_ctrl; tpm_reg_ctrl_start_t start; tpm_reg_ctrl_cmdsize_t CmdSize; tpm_reg_ctrl_cmdaddr_t CmdAddr; tpm_reg_ctrl_rspsize_t RspSize; tpm_reg_ctrl_rspaddr_t RspAddr; uint32_t tpm_crb_data_buffer_base; if ( locality >= TPM_NR_LOCALITIES ) { printk(TBOOT_WARN"TPM: Invalid locality for tpm_submit_cmd_crb()\n"); return false; } if ( in == NULL || out == NULL || out_size == NULL ) { printk(TBOOT_WARN"TPM: Invalid parameter for tpm_submit_cmd_crb()\n"); return false; } if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) { printk(TBOOT_WARN"TPM: in/out buf size must be larger than 10 bytes\n"); return false; } if ( !tpm_validate_locality_crb(locality) ) { printk(TBOOT_WARN"TPM: CRB Interface Locality %d is not open\n", locality); return false; } if ( !tpm_wait_cmd_ready_crb(locality) ) { printk(TBOOT_WARN"TPM: tpm_wait_cmd_read_crb failed\n"); return false; } #ifdef TPM_TRACE { printk(TBOOT_DETA"TPM: Before submit, cmd size = 0x%x\nTPM: Before submit, cmd content: ", in_size); print_hex("TPM: \t", in, in_size); } #endif /* write the command to the TPM CRB buffer 01-04-2016 */ //copy *in and size to crb buffer CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; CmdAddr.cmdhaddr = 0; RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; CmdSize.cmdsize = TPMCRBBUF_LEN; RspSize.rspsize = TPMCRBBUF_LEN; tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER; #ifdef TPM_TRACE printk(TBOOT_INFO"CmdAddr.cmdladdr is 0x%x\n",CmdAddr.cmdladdr); printk(TBOOT_INFO"CmdAddr.cmdhaddr is 0x%x\n",CmdAddr.cmdhaddr); printk(TBOOT_INFO"CmdSize.cmdsize is 0x%x\n",CmdSize.cmdsize); printk(TBOOT_INFO"RspAddr.rspaddr is 0x%Lx\n",RspAddr.rspaddr); printk(TBOOT_INFO"RspSize.rspsize is 0x%x\n",RspSize.rspsize); #endif write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr); write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize); write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr); write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize); // write the command to the buffer for ( i = 0 ; i< in_size; i++ ) { write_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&in[i]); //tpm_crb_data_buffer_base++; } /* command has been written to the TPM, it is time to execute it. */ start.start = 1; write_tpm_reg(locality, TPM_CRB_CTRL_START, &start); //read_tpm_reg(locality, TPM_CRB_CTRL_START, &start); printk(TBOOT_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); /* check for data available */ i = 0; do { read_tpm_reg(locality, TPM_CRB_CTRL_START, &start); //printk(TBOOT_INFO"tpm_ctrl_start.start is 0x%x\n",start.start); if ( start.start == 0 ) break; else cpu_relax(); i++; } while ( i <= TPM_DATA_AVAIL_TIME_OUT ); if ( i > TPM_DATA_AVAIL_TIME_OUT ) { printk(TBOOT_ERR"TPM: wait for data available timeout\n"); ret = false; goto RelinquishControl; } tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER; for ( i = 0 ; i< *out_size; i++ ) { read_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&out[i]); //tpm_crb_data_buffer_base++; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: After cmd submit, response size = 0x%x\n", *out_size); printk(TBOOT_DETA"TPM: After cmd submit, response content: "); print_hex("TPM: \t", out, *out_size); } #endif //tpm_send_cmd_ready_status_crb(locality); RelinquishControl: /* deactivate current locality */ // reg_loc_ctrl._raw[0] = 0; //reg_loc_ctrl.relinquish = 1; //write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); return ret; } bool release_locality(uint32_t locality) { uint32_t i; #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: releasing locality %u\n", locality); #endif if ( !tpm_validate_locality(locality) ) return true; tpm_reg_access_t reg_acc; read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); if ( reg_acc.active_locality == 0 ) return true; /* make inactive by writing a 1 */ reg_acc._raw[0] = 0; reg_acc.active_locality = 1; write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); i = 0; do { read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); if ( reg_acc.active_locality == 0 ) return true; else cpu_relax(); i++; } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); printk(TBOOT_INFO"TPM: access reg release locality timeout\n"); return false; } bool tpm_relinquish_locality_crb(uint32_t locality) { uint32_t i; tpm_reg_loc_state_t reg_loc_state; tpm_reg_loc_ctrl_t reg_loc_ctrl; #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: releasing CRB_INF locality %u\n", locality); #endif if ( !tpm_validate_locality_crb(locality) ) return true; read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); if ( reg_loc_state.loc_assigned == 0 ) return true; /* make inactive by writing a 1 */ tb_memset(®_loc_ctrl,0,sizeof(reg_loc_ctrl)); reg_loc_ctrl.relinquish = 1; write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); i = 0; do { read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); if ( reg_loc_state.loc_assigned == 0 ) return true; else cpu_relax(); i++; } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT ); printk(TBOOT_INFO"TPM: CRB_INF release locality timeout\n"); return false; } bool is_tpm_crb(void) { tpm_crb_interface_id_t crb_interface; read_tpm_reg(0, TPM_INTERFACE_ID, &crb_interface); if (crb_interface.interface_type == TPM_INTERFACE_ID_CRB ) { printk(TBOOT_INFO"TPM: PTP CRB interface is active...\n"); if (g_tpm_family != TPM_IF_20_CRB ) g_tpm_family = TPM_IF_20_CRB; return true; } if (crb_interface.interface_type == TPM_INTERFACE_ID_FIFO_20) { printk(TBOOT_INFO"TPM: TPM 2.0 FIFO interface is active...\n"); if (g_tpm_family != TPM_IF_20_FIFO) g_tpm_family = TPM_IF_20_FIFO; } return false; } bool prepare_tpm(void) { /* * must ensure TPM_ACCESS_0.activeLocality bit is clear * (: locality is not active) */ if ( is_tpm_crb() ) { return tpm_relinquish_locality_crb(0); } else { return release_locality(0); } } bool tpm_request_locality_crb(uint32_t locality){ uint32_t i; tpm_reg_loc_state_t reg_loc_state; tpm_reg_loc_ctrl_t reg_loc_ctrl; /* request access to the TPM from locality N */ tb_memset(®_loc_ctrl,0,sizeof(reg_loc_ctrl)); reg_loc_ctrl.requestAccess = 1; write_tpm_reg(locality, TPM_REG_LOC_CTRL, ®_loc_ctrl); i = 0; do { read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_loc_state); if ( reg_loc_state.active_locality == locality && reg_loc_state.loc_assigned == 1) break; else cpu_relax(); i++; } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT); if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) { printk(TBOOT_ERR"TPM: access loc request use timeout\n"); return false; } return true; } bool tpm_workaround_crb(void) { tpm_reg_ctrl_cmdsize_t CmdSize; tpm_reg_ctrl_cmdaddr_t CmdAddr; tpm_reg_ctrl_rspsize_t RspSize; tpm_reg_ctrl_rspaddr_t RspAddr; u32 locality = 0; if (!tpm_request_locality_crb(locality)) return false; CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; CmdAddr.cmdhaddr = 0; RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER; CmdSize.cmdsize = TPMCRBBUF_LEN; RspSize.rspsize = TPMCRBBUF_LEN; write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr); write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize); write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr); write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize); return true; } bool tpm_detect(void) { struct tpm_if *tpm = get_tpm(); /* Don't leave tpm as NULL */ const struct tpm_if_fp *tpm_fp; if (is_tpm_crb()) { printk(TBOOT_INFO"TPM: This is Intel PTT, TPM Family 0x%d\n", g_tpm_family); if (!txt_is_launched()) { if ( tpm_validate_locality_crb(0) ) printk(TBOOT_INFO"TPM: CRB_INF Locality 0 is open\n"); else { printk(TBOOT_INFO"TPM: CRB_INF request access to Locality 0...\n"); if (!tpm_request_locality_crb(0)) { printk(TBOOT_ERR"TPM: CRB_INF Locality 0 request failed...\n"); return false; } } } else { if ( tpm_validate_locality_crb(2) ) printk(TBOOT_INFO"TPM: CRB_INF Locality 2 is open\n"); else { printk(TBOOT_INFO"TPM: CRB_INF request access to Locality 2...\n"); if (!tpm_request_locality_crb(2)) { printk(TBOOT_ERR"TPM: CRB_INF Locality 2 request failed...\n"); return false; } } } } else { g_tpm_ver = TPM_VER_12; tpm_fp = get_tpm_fp(); /* Don't leave tpm_fp as NULL */ if ( tpm_validate_locality(0) ) printk(TBOOT_INFO"TPM: FIFO_INF Locality 0 is open\n"); else { printk(TBOOT_ERR"TPM: FIFO_INF Locality 0 is not open\n"); return false; } /* determine TPM family from command check */ if ( tpm_fp->check() ) { g_tpm_family = TPM_IF_12; printk(TBOOT_INFO"TPM: discrete TPM1.2 Family 0x%d\n", g_tpm_family); } else { g_tpm_family = TPM_IF_20_FIFO; printk(TBOOT_INFO"TPM: discrete TPM2.0 Family 0x%d\n", g_tpm_family); } } if (g_tpm_family == TPM_IF_12) g_tpm_ver = TPM_VER_12; if (g_tpm_family == TPM_IF_20_FIFO) g_tpm_ver = TPM_VER_20; if (g_tpm_family == TPM_IF_20_CRB) g_tpm_ver = TPM_VER_20; tpm_fp = get_tpm_fp(); return tpm_fp->init(tpm); } void tpm_print(struct tpm_if *ti) { if ( ti == NULL ) return; printk(TBOOT_INFO"TPM attribute:\n"); printk(TBOOT_INFO"\t extend policy: %d\n", ti->extpol); printk(TBOOT_INFO"\t current alg id: 0x%x\n", ti->cur_alg); printk(TBOOT_INFO"\t timeout values: A: %u, B: %u, C: %u, D: %u\n", ti->timeout.timeout_a, ti->timeout.timeout_b, ti->timeout.timeout_c, ti->timeout.timeout_d); } struct tpm_if *get_tpm(void) { return &g_tpm; } const struct tpm_if_fp *get_tpm_fp(void) { if ( g_tpm_ver == TPM_VER_12 ) return &tpm_12_if_fp; else if ( g_tpm_ver == TPM_VER_20) return &tpm_20_if_fp; return NULL; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/tpm_12.c0000644000000000000000000020354114210363175014747 0ustar 00000000000000/* * tpm_12.c: TPM1.2-related support functions * * Copyright (c) 2006-2013, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include /* * return code: * The TPM has five types of return code. One indicates successful operation * and four indicate failure. * TPM_SUCCESS (00000000) indicates successful execution. * The failure reports are: * TPM defined fatal errors (00000001 to 000003FF) * vendor defined fatal errors (00000400 to 000007FF) * TPM defined non-fatal errors (00000800 to 00000BFF) * vendor defined non-fatal errors (00000C00 to 00000FFF). * Here only give definitions for a few commonly used return code. */ #define TPM_BASE 0x00000000 #define TPM_NON_FATAL 0x00000800 #define TPM_SUCCESS TPM_BASE #define TPM_BADINDEX (TPM_BASE + 2) #define TPM_BAD_PARAMETER (TPM_BASE + 3) #define TPM_DEACTIVATED (TPM_BASE + 6) #define TPM_DISABLED (TPM_BASE + 7) #define TPM_FAIL (TPM_BASE + 9) #define TPM_BAD_ORDINAL (TPM_BASE + 10) #define TPM_NOSPACE (TPM_BASE + 17) #define TPM_NOTRESETABLE (TPM_BASE + 50) #define TPM_NOTLOCAL (TPM_BASE + 51) #define TPM_BAD_LOCALITY (TPM_BASE + 61) #define TPM_READ_ONLY (TPM_BASE + 62) #define TPM_NOT_FULLWRITE (TPM_BASE + 70) #define TPM_RETRY (TPM_BASE + TPM_NON_FATAL) typedef uint8_t tpm_locality_selection_t; #define TPM_LOC_ZERO 0x01 #define TPM_LOC_ONE 0x02 #define TPM_LOC_TWO 0x04 #define TPM_LOC_THREE 0x08 #define TPM_LOC_FOUR 0x10 #define TPM_LOC_RSVD 0xE0 /* ~5 secs are required for Infineon that requires this, so leave some extra */ #define MAX_SAVESTATE_RETRIES 60 #define TPM_TAG_RQU_COMMAND 0x00C1 #define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 #define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 #define TPM_ORD_PCR_EXTEND 0x00000014 #define TPM_ORD_PCR_READ 0x00000015 #define TPM_ORD_PCR_RESET 0x000000C8 #define TPM_ORD_NV_READ_VALUE 0x000000CF #define TPM_ORD_NV_WRITE_VALUE 0x000000CD #define TPM_ORD_GET_CAPABILITY 0x00000065 #define TPM_ORD_SEAL 0x00000017 #define TPM_ORD_UNSEAL 0x00000018 #define TPM_ORD_OSAP 0x0000000B #define TPM_ORD_OIAP 0x0000000A #define TPM_ORD_SAVE_STATE 0x00000098 #define TPM_ORD_GET_RANDOM 0x00000046 #define TPM_TAG_PCR_INFO_LONG 0x0006 #define TPM_TAG_STORED_DATA12 0x0016 /* * specified as minimum cmd buffer size should be supported by all 1.2 TPM * device in the TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf */ #define TPM_CMD_SIZE_MAX 768 #define TPM_RSP_SIZE_MAX 768 /* * The _tpm12_submit_cmd function comes with 2 global buffers: cmd_buf & rsp_buf. * Before calling, caller should fill cmd arguements into cmd_buf via * WRAPPER_IN_BUF macro. After calling, caller should fetch result from * rsp_buffer via WRAPPER_OUT_BUF macro. * cmd_buf content: * 0 1 2 3 4 5 6 7 8 9 10 ... * ------------------------------------------------------------- * | TAG | SIZE | ORDINAL | arguments ... * ------------------------------------------------------------- * rsp_buf content: * 0 1 2 3 4 5 6 7 8 9 10 ... * ------------------------------------------------------------- * | TAG | SIZE | RETURN CODE | other data ... * ------------------------------------------------------------- * * locality : TPM locality (0 - 4) * tag : The TPM command tag * cmd : The TPM command ordinal * arg_size : Size of argument data. * out_size : IN/OUT paramter. The IN is the expected size of out data; * the OUT is the size of output data within out buffer. * The out_size MUST NOT be NULL. * return : TPM_SUCCESS for success, for other error code, refer to the .h */ static uint8_t cmd_buf[TPM_CMD_SIZE_MAX]; static uint8_t rsp_buf[TPM_RSP_SIZE_MAX]; #define WRAPPER_IN_BUF (cmd_buf + CMD_HEAD_SIZE) #define WRAPPER_OUT_BUF (rsp_buf + RSP_HEAD_SIZE) #define WRAPPER_IN_MAX_SIZE (TPM_CMD_SIZE_MAX - CMD_HEAD_SIZE) #define WRAPPER_OUT_MAX_SIZE (TPM_RSP_SIZE_MAX - RSP_HEAD_SIZE) static uint32_t _tpm12_submit_cmd(uint32_t locality, uint16_t tag, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) { uint32_t ret; uint32_t cmd_size, rsp_size = 0; if ( out_size == NULL ) { printk(TBOOT_WARN"TPM: invalid param for _tpm12_submit_cmd()\n"); return TPM_BAD_PARAMETER; } /* * real cmd size should add 10 more bytes: * 2 bytes for tag * 4 bytes for size * 4 bytes for ordinal */ cmd_size = CMD_HEAD_SIZE + arg_size; if ( cmd_size > TPM_CMD_SIZE_MAX ) { printk(TBOOT_WARN"TPM: cmd exceeds the max supported size.\n"); return TPM_BAD_PARAMETER; } /* copy tag, size & ordinal into buf in a reversed byte order */ reverse_copy(cmd_buf, &tag, sizeof(tag)); reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); reverse_copy(cmd_buf + CMD_CC_OFFSET, &cmd, sizeof(cmd)); rsp_size = RSP_HEAD_SIZE + *out_size; rsp_size = (rsp_size > TPM_RSP_SIZE_MAX) ? TPM_RSP_SIZE_MAX: rsp_size; if ( !tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size) ) return TPM_FAIL; /* * should subtract 10 bytes from real response size: * 2 bytes for tag * 4 bytes for size * 4 bytes for return code */ rsp_size -= (rsp_size > RSP_HEAD_SIZE) ? RSP_HEAD_SIZE : rsp_size; reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(uint32_t)); if ( ret != TPM_SUCCESS ) return ret; if ( *out_size == 0 || rsp_size == 0 ) *out_size = 0; else *out_size = (rsp_size < *out_size) ? rsp_size : *out_size; return ret; } static inline uint32_t tpm12_submit_cmd(uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) { return _tpm12_submit_cmd(locality, TPM_TAG_RQU_COMMAND, cmd, arg_size, out_size); } static inline uint32_t tpm12_submit_cmd_auth1(uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) { return _tpm12_submit_cmd(locality, TPM_TAG_RQU_AUTH1_COMMAND, cmd, arg_size, out_size); } static inline uint32_t tpm12_submit_cmd_auth2(uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size) { return _tpm12_submit_cmd(locality, TPM_TAG_RQU_AUTH2_COMMAND, cmd, arg_size, out_size); } typedef struct __packed { uint8_t digest[SHA1_LENGTH]; } tpm12_digest_t; #define TPM_NR_PCRS 24 static bool tpm12_pcr_read(struct tpm_if *ti, uint32_t locality, uint32_t pcr, tpm_pcr_value_t *out) { uint32_t ret, out_size = sizeof(*out); if ( out == NULL || pcr >= TPM_NR_PCRS) { ti->error = TPM_BAD_PARAMETER; return false; } /* copy pcr into buf in reversed byte order */ reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr)); ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_READ, sizeof(pcr), &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: Pcr %d Read return value = %08X\n", pcr, ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: Pcr %d Read return value = %08X\n", pcr, ret); ti->error = ret; return false; } if ( out_size > sizeof(*out) ) out_size = sizeof(*out); tb_memcpy((void *)out, WRAPPER_OUT_BUF, out_size); #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, ((tpm12_digest_t *)out)->digest, out_size); } #endif return true; } static bool _tpm12_pcr_extend(struct tpm_if *ti, uint32_t locality, uint32_t pcr, const tpm_digest_t* in) { uint32_t ret, in_size = 0, out_size = 0; if ( ti == NULL ) return false; if ( in == NULL || pcr >= TPM_NR_PCRS){ ti->error = TPM_BAD_PARAMETER; return false; } /* copy pcr into buf in reversed byte order, then copy in data */ reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr)); in_size += sizeof(pcr); tb_memcpy(WRAPPER_IN_BUF + in_size, (void *)in, sizeof(*(tpm12_digest_t *)in)); in_size += sizeof(*(tpm12_digest_t *)in); ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_EXTEND, in_size, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: Pcr %d extend, return value = %08X\n", pcr, ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: Pcr %d extend, return value = %08X\n", pcr, ret); ti->error = ret; return false; } return true; } static bool tpm12_pcr_extend(struct tpm_if *ti, uint32_t locality, uint32_t pcr, const hash_list_t *in) { tpm_digest_t digest; if ( ti == NULL ) return false; if ( in == NULL || in->count != 1 || in->entries[0].alg != TB_HALG_SHA1 ) { ti->error = TPM_BAD_PARAMETER; return false; } digest = in->entries[0].hash; return _tpm12_pcr_extend(ti, locality, pcr, &digest); } typedef struct __packed { uint16_t size_of_select; uint8_t pcr_select[3]; } tpm_pcr_selection_t; /* PCRs lower than 16 are not resetable */ #define TPM_PCR_RESETABLE_MIN 16 static bool tpm12_pcr_reset(struct tpm_if *ti, uint32_t locality, uint32_t pcr) { uint32_t ret, in_size, out_size = 0; uint16_t size_of_select; tpm_pcr_selection_t pcr_sel = {0,{0,}}; if ( ti == NULL ) return false; if ( pcr >= TPM_NR_PCRS || pcr < TPM_PCR_RESETABLE_MIN ) { ti->error = TPM_BAD_PARAMETER; return false; } /* the pcr_sel.pcr_select[size_of_select - 1] should not be 0 */ size_of_select = pcr / 8 + 1; reverse_copy(&pcr_sel.size_of_select, &size_of_select, sizeof(size_of_select)); pcr_sel.pcr_select[pcr / 8] = 1 << (pcr % 8); in_size = sizeof(pcr_sel); tb_memcpy(WRAPPER_IN_BUF, (void *)&pcr_sel, in_size); ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_RESET, in_size, &out_size); if ( ret != TPM_SUCCESS ) { ti->error = ret; return false; } printk(TBOOT_DETA"TPM: Pcr %d reset, return value = %08X\n", pcr, ret); return true; } #define TPM_NV_READ_VALUE_DATA_SIZE_MAX (TPM_RSP_SIZE_MAX - 14) static bool tpm12_nv_read_value(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, uint8_t *data, uint32_t *data_size) { uint32_t ret, in_size = 0, out_size; if ( ti == NULL ) return false; if ( data == NULL || data_size == NULL || *data_size == 0 ) { ti->error = TPM_BAD_PARAMETER; return false; } if ( *data_size > TPM_NV_READ_VALUE_DATA_SIZE_MAX ) *data_size = TPM_NV_READ_VALUE_DATA_SIZE_MAX; /* copy the index, offset and *data_size into buf in reversed byte order */ reverse_copy(WRAPPER_IN_BUF, &index, sizeof(index)); in_size += sizeof(index); reverse_copy(WRAPPER_IN_BUF + in_size, &offset, sizeof(offset)); in_size += sizeof(offset); reverse_copy(WRAPPER_IN_BUF + in_size, data_size, sizeof(*data_size)); in_size += sizeof(*data_size); out_size = *data_size + sizeof(*data_size); ret = tpm12_submit_cmd(locality, TPM_ORD_NV_READ_VALUE, in_size, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: read nv index %08x from offset %08x, return value = %08X\n", index, offset, ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: read nv index %08x offset %08x, return value = %08X\n", index, offset, ret); ti->error = ret; return false; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, WRAPPER_OUT_BUF, out_size); } #endif if ( out_size <= sizeof(*data_size) ) { *data_size = 0; return true; } out_size -= sizeof(*data_size); reverse_copy(data_size, WRAPPER_OUT_BUF, sizeof(*data_size)); *data_size = (*data_size > out_size) ? out_size : *data_size; if( *data_size > 0 ) tb_memcpy(data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size); return true; } #define TPM_NV_WRITE_VALUE_DATA_SIZE_MAX (TPM_CMD_SIZE_MAX - 22) static bool tpm12_nv_write_value(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, const uint8_t *data, uint32_t data_size) { uint32_t ret, in_size = 0, out_size = 0; if ( ti == NULL ) return false; if ( data == NULL || data_size == 0 || data_size > TPM_NV_WRITE_VALUE_DATA_SIZE_MAX ) { ti->error = TPM_BAD_PARAMETER; return false; } /* copy index, offset and *data_size into buf in reversed byte order */ reverse_copy(WRAPPER_IN_BUF, &index, sizeof(index)); in_size += sizeof(index); reverse_copy(WRAPPER_IN_BUF + in_size, &offset, sizeof(offset)); in_size += sizeof(offset); reverse_copy(WRAPPER_IN_BUF + in_size, &data_size, sizeof(data_size)); in_size += sizeof(data_size); tb_memcpy(WRAPPER_IN_BUF + in_size, data, data_size); in_size += data_size; ret = tpm12_submit_cmd(locality, TPM_ORD_NV_WRITE_VALUE, in_size, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n", index, offset, data_size, ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n", index, offset, data_size, ret); ti->error = ret; return false; } return true; } #define TPM_CAP_VERSION_VAL 0x1A typedef uint16_t tpm_structure_tag_t; typedef struct __packed { uint8_t major; uint8_t minor; uint8_t rev_major; uint8_t rev_minor; } tpm_version_t; typedef struct __packed { tpm_structure_tag_t tag; tpm_version_t version; uint16_t specLevel; uint8_t errataRev; uint8_t tpmVendorID[4]; uint16_t vendorSpecificSize; uint8_t vendorSpecific[]; } tpm_cap_version_info_t; #define HMAC_BLOCK_SIZE 64 #define HMAC_OUTPUT_SIZE 20 static bool hmac(const uint8_t key[HMAC_OUTPUT_SIZE], const uint8_t *msg, uint32_t len, uint8_t md[HMAC_OUTPUT_SIZE]) { uint8_t ipad[HMAC_BLOCK_SIZE], opad[HMAC_BLOCK_SIZE]; uint32_t i; SHA_CTX ctx; COMPILE_TIME_ASSERT(HMAC_OUTPUT_SIZE <= HMAC_BLOCK_SIZE); for ( i = 0; i < HMAC_BLOCK_SIZE; i++ ) { ipad[i] = 0x36; opad[i] = 0x5C; } for ( i = 0; i < HMAC_OUTPUT_SIZE; i++ ) { ipad[i] ^= key[i]; opad[i] ^= key[i]; } SHA1_Init(&ctx); SHA1_Update(&ctx, ipad, HMAC_BLOCK_SIZE); SHA1_Update(&ctx, msg, len); SHA1_Final(md, &ctx); SHA1_Init(&ctx); SHA1_Update(&ctx, opad, HMAC_BLOCK_SIZE); SHA1_Update(&ctx, md, HMAC_OUTPUT_SIZE); SHA1_Final(md, &ctx); return true; } typedef uint16_t tpm_entity_type_t; typedef uint32_t tpm_authhandle_t; typedef struct __packed { uint8_t nonce[20]; } tpm_nonce_t; #define TPM_ET_SRK 0x0004 #define TPM_KH_SRK 0x40000000 typedef uint32_t tpm_key_handle_t; typedef tpm12_digest_t tpm_composite_hash_t; typedef struct __packed { tpm_structure_tag_t tag; tpm_locality_selection_t locality_at_creation; tpm_locality_selection_t locality_at_release; tpm_pcr_selection_t creation_pcr_selection; tpm_pcr_selection_t release_pcr_selection; tpm_composite_hash_t digest_at_creation; tpm_composite_hash_t digest_at_release; } tpm_pcr_info_long_t; typedef uint8_t tpm_authdata_t[20]; typedef tpm_authdata_t tpm_encauth_t; typedef struct __packed { tpm_structure_tag_t tag; tpm_entity_type_t et; uint32_t seal_info_size; } tpm_stored_data12_header_t; typedef struct __packed { tpm_stored_data12_header_t header; uint32_t enc_data_size; uint8_t enc_data[]; } tpm_stored_data12_short_t; typedef struct __packed { tpm_stored_data12_header_t header; tpm_pcr_info_long_t seal_info; uint32_t enc_data_size; uint8_t enc_data[]; } tpm_stored_data12_t; #define UNLOAD_INTEGER(buf, offset, var) {\ reverse_copy(buf + offset, &(var), sizeof(var));\ offset += sizeof(var);\ } #define UNLOAD_BLOB(buf, offset, blob, size) {\ tb_memcpy(buf + offset, blob, size);\ offset += size;\ } #define UNLOAD_BLOB_TYPE(buf, offset, blob) \ UNLOAD_BLOB(buf, offset, blob, sizeof(*(blob))) #define UNLOAD_PCR_SELECTION(buf, offset, sel) {\ UNLOAD_INTEGER(buf, offset, (sel)->size_of_select);\ UNLOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\ } #define UNLOAD_PCR_INFO_LONG(buf, offset, info) {\ UNLOAD_INTEGER(buf, offset, (info)->tag);\ UNLOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_creation);\ UNLOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_release);\ UNLOAD_PCR_SELECTION(buf, offset, &(info)->creation_pcr_selection);\ UNLOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection);\ UNLOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\ UNLOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\ } #define UNLOAD_STORED_DATA12(buf, offset, hdr) {\ UNLOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->tag);\ UNLOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->et);\ UNLOAD_INTEGER(buf, offset,\ ((tpm_stored_data12_header_t *)(hdr))->seal_info_size);\ if ( ((tpm_stored_data12_header_t *)(hdr))->seal_info_size == 0 ) {\ UNLOAD_INTEGER(buf, offset,\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ UNLOAD_BLOB(buf, offset,\ ((tpm_stored_data12_short_t *)hdr)->enc_data,\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ }\ else {\ UNLOAD_PCR_INFO_LONG(buf, offset,\ &((tpm_stored_data12_t *)hdr)->seal_info);\ UNLOAD_INTEGER(buf, offset,\ ((tpm_stored_data12_t *)hdr)->enc_data_size);\ UNLOAD_BLOB(buf, offset,\ ((tpm_stored_data12_t *)hdr)->enc_data,\ ((tpm_stored_data12_t *)hdr)->enc_data_size);\ }\ } #define LOAD_INTEGER(buf, offset, var) {\ reverse_copy(&(var), buf + offset, sizeof(var));\ offset += sizeof(var);\ } #define LOAD_BLOB(buf, offset, blob, size) {\ tb_memcpy(blob, buf + offset, size);\ offset += size;\ } #define LOAD_BLOB_TYPE(buf, offset, blob) \ LOAD_BLOB(buf, offset, blob, sizeof(*(blob))) #define LOAD_PCR_SELECTION(buf, offset, sel, size) while (1) {\ if ( size < sizeof(tpm_pcr_selection_t) ) {\ size++;\ break;\ }\ LOAD_INTEGER(buf, offset, (sel)->size_of_select);\ if ( (sel)->size_of_select > sizeof((sel)->pcr_select) ) {\ size++;\ break;\ }\ LOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\ size = sizeof(tpm_pcr_selection_t);\ break;\ } #define LOAD_PCR_INFO_LONG(buf, offset, info, size) while (1) {\ uint32_t ps_size = sizeof(tpm_pcr_selection_t);\ if ( size < sizeof(tpm_pcr_info_long_t) ) {\ size++;\ break;\ }\ LOAD_INTEGER(buf, offset, (info)->tag);\ LOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_creation);\ LOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_release);\ LOAD_PCR_SELECTION(buf, offset, &(info)->creation_pcr_selection, ps_size);\ if ( ps_size > sizeof(tpm_pcr_selection_t) ) {\ size++;\ break;\ }\ ps_size = sizeof(tpm_pcr_selection_t);\ LOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection, ps_size);\ if ( ps_size > sizeof(tpm_pcr_selection_t) ) {\ size++;\ break;\ }\ LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\ LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\ size=sizeof(tpm_pcr_info_long_t);\ break;\ } #define LOAD_STORED_DATA12(buf, offset, hdr, size) while (1){\ uint32_t pil_size = sizeof(tpm_pcr_info_long_t);\ if ( size < sizeof(tpm_stored_data12_short_t) ) {\ size++;\ break;\ }\ LOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->tag);\ LOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->et);\ LOAD_INTEGER(buf, offset, \ ((tpm_stored_data12_header_t *)(hdr))->seal_info_size);\ if ( ((tpm_stored_data12_header_t *)(hdr))->seal_info_size == 0 ) {\ LOAD_INTEGER(buf, offset,\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ if ( size - sizeof(tpm_stored_data12_short_t) <\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size ) {\ size++;\ break;\ }\ LOAD_BLOB(buf, offset,\ ((tpm_stored_data12_short_t *)hdr)->enc_data,\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ size = sizeof(tpm_stored_data12_short_t) +\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size;\ }\ else {\ if ( size < sizeof(tpm_stored_data12_t) ) {\ size++;\ break;\ }\ LOAD_PCR_INFO_LONG(buf, offset,\ &((tpm_stored_data12_t *)hdr)->seal_info, pil_size);\ if ( pil_size > sizeof(tpm_pcr_info_long_t) ) {\ size++;\ break;\ }\ LOAD_INTEGER(buf, offset,\ ((tpm_stored_data12_t *)hdr)->enc_data_size);\ if ( size - sizeof(tpm_stored_data12_t) <\ ((tpm_stored_data12_t *)hdr)->enc_data_size ) {\ size++;\ break;\ }\ LOAD_BLOB(buf, offset,\ ((tpm_stored_data12_t *)hdr)->enc_data,\ ((tpm_stored_data12_t *)hdr)->enc_data_size);\ size = sizeof(tpm_stored_data12_t) +\ ((tpm_stored_data12_t *)hdr)->enc_data_size;\ }\ break;\ } static uint32_t tpm12_oiap(uint32_t locality, tpm_authhandle_t *hauth, tpm_nonce_t *nonce_even) { uint32_t ret, offset, out_size; if ( hauth == NULL || nonce_even == NULL ) return TPM_BAD_PARAMETER; offset = 0; out_size = sizeof(*hauth) + sizeof(*nonce_even); ret = tpm12_submit_cmd(locality, TPM_ORD_OIAP, offset, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: start OIAP, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: start OIAP, return value = %08X\n", ret); return ret; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, WRAPPER_OUT_BUF, out_size); } #endif offset = 0; LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *hauth); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); return ret; } static uint32_t tpm12_osap(uint32_t locality, tpm_entity_type_t ent_type, uint32_t ent_value, const tpm_nonce_t *odd_osap, tpm_authhandle_t *hauth, tpm_nonce_t *nonce_even, tpm_nonce_t *even_osap) { uint32_t ret, offset, out_size; if ( odd_osap == NULL || hauth == NULL || nonce_even == NULL || even_osap == NULL ) return TPM_BAD_PARAMETER; offset = 0; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ent_type); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ent_value); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, odd_osap); out_size = sizeof(*hauth) + sizeof(*nonce_even) + sizeof(*even_osap); ret = tpm12_submit_cmd(locality, TPM_ORD_OSAP, offset, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: start OSAP, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: start OSAP, return value = %08X\n", ret); return ret; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, WRAPPER_OUT_BUF, out_size); } #endif offset = 0; LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *hauth); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, even_osap); return ret; } static uint32_t _tpm12_seal(uint32_t locality, tpm_key_handle_t hkey, const tpm_encauth_t *enc_auth, uint32_t pcr_info_size, const tpm_pcr_info_long_t *pcr_info, uint32_t in_data_size, const uint8_t *in_data, tpm_authhandle_t hauth, const tpm_nonce_t *nonce_odd, uint8_t *cont_session, const tpm_authdata_t *pub_auth, uint32_t *sealed_data_size, uint8_t *sealed_data, tpm_nonce_t *nonce_even, tpm_authdata_t *res_auth) { uint32_t ret, offset, out_size, size; if ( enc_auth == NULL || pcr_info == NULL || in_data == NULL || nonce_odd == NULL || cont_session == NULL || pub_auth == NULL || sealed_data_size == NULL || sealed_data == NULL || nonce_even == NULL || res_auth == NULL ) { printk(TBOOT_WARN"TPM: _tpm12_seal() bad parameter\n"); return TPM_BAD_PARAMETER; } offset = 0; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hkey); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, enc_auth); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size); UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, pcr_info); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size); UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, pub_auth); out_size = WRAPPER_OUT_MAX_SIZE; ret = tpm12_submit_cmd_auth1(locality, TPM_ORD_SEAL, offset, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: seal data, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: seal data, return value = %08X\n", ret); return ret; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, WRAPPER_OUT_BUF, out_size); } #endif if ( *sealed_data_size < ( out_size - sizeof(*nonce_even) - sizeof(*cont_session) - sizeof(*res_auth) ) ) { printk(TBOOT_WARN"TPM: sealed blob is too small\n"); return TPM_NOSPACE; } offset = 0; size = *sealed_data_size; LOAD_STORED_DATA12(WRAPPER_OUT_BUF, offset, sealed_data, size); if ( *sealed_data_size < size ) { printk(TBOOT_WARN"TPM: sealed blob is too small\n"); return TPM_NOSPACE; } *sealed_data_size = size; LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth); return ret; } static uint32_t _tpm12_unseal(uint32_t locality, tpm_key_handle_t hkey, const uint8_t *in_data, tpm_authhandle_t hauth, const tpm_nonce_t *nonce_odd, uint8_t *cont_session, const tpm_authdata_t *auth, tpm_authhandle_t hauth_d, const tpm_nonce_t *nonce_odd_d, uint8_t *cont_session_d, const tpm_authdata_t *auth_d, uint32_t *secret_size, uint8_t *secret, tpm_nonce_t *nonce_even, tpm_authdata_t *res_auth, tpm_nonce_t *nonce_even_d, tpm_authdata_t *res_auth_d) { uint32_t ret, offset, out_size, size; if ( in_data == NULL || nonce_odd == NULL || cont_session == NULL || auth == NULL || nonce_odd_d == NULL || cont_session_d == NULL || auth_d == NULL || secret_size == NULL || secret == NULL || nonce_even == NULL || res_auth == NULL || nonce_even_d == NULL || res_auth_d == NULL ) { printk(TBOOT_WARN"TPM: _tpm_unseal() bad parameter\n"); return TPM_BAD_PARAMETER; } offset = 0; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hkey); UNLOAD_STORED_DATA12(WRAPPER_IN_BUF, offset, in_data); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, auth); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth_d); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd_d); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session_d); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, auth_d); out_size = WRAPPER_OUT_MAX_SIZE; ret = tpm12_submit_cmd_auth2(locality, TPM_ORD_UNSEAL, offset, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: unseal data, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: unseal data, return value = %08X\n", ret); return ret; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, WRAPPER_OUT_BUF, out_size); } #endif offset = 0; LOAD_INTEGER(WRAPPER_OUT_BUF, offset, size); if ( *secret_size < size || size != ( out_size - sizeof(*secret_size) - sizeof(*nonce_even) - sizeof(*cont_session) - sizeof(*res_auth) - sizeof(*nonce_even_d) - sizeof(*cont_session_d) - sizeof(*res_auth_d) ) ) { printk(TBOOT_WARN"TPM: unsealed data too small\n"); return TPM_NOSPACE; } *secret_size = size; LOAD_BLOB(WRAPPER_OUT_BUF, offset, secret, *secret_size); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even); LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even_d); LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session_d); LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth_d); return ret; } #define XOR_BLOB_TYPE(data, pad) {\ for ( uint32_t i = 0; i < sizeof(*(data)); i++ ) \ ((uint8_t *)data)[i] ^= ((uint8_t *)pad)[i % sizeof(*(pad))];\ } static const tpm_authdata_t srk_authdata = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const tpm_authdata_t blob_authdata = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static uint32_t _tpm12_wrap_seal(uint32_t locality, const tpm_pcr_info_long_t *pcr_info, uint32_t in_data_size, const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) { uint32_t ret; tpm_nonce_t odd_osap, even_osap, nonce_even, nonce_odd; tpm_authhandle_t hauth; tpm_authdata_t shared_secret, pub_auth, res_auth; tpm_encauth_t enc_auth; uint8_t cont_session = false; tpm_key_handle_t hkey = TPM_KH_SRK; uint32_t pcr_info_size = sizeof(*pcr_info); uint32_t offset; uint32_t ordinal = TPM_ORD_SEAL; tpm12_digest_t digest; /* skip generate nonce for odd_osap, just use the random value in stack */ /* establish a osap session */ ret = tpm12_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth, &nonce_even, &even_osap); if ( ret != TPM_SUCCESS ) return ret; /* calculate the shared secret shared-secret = HMAC(srk_auth, even_osap || odd_osap) */ offset = 0; UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap); hmac((uint8_t *)&srk_authdata, WRAPPER_IN_BUF, offset, (uint8_t *)&shared_secret); /* generate ecrypted authdata for data enc_auth = XOR(authdata, sha1(shared_secret || last_even_nonce)) */ offset = 0; UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &shared_secret); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); tb_memcpy(&enc_auth, &blob_authdata, sizeof(blob_authdata)); XOR_BLOB_TYPE(&enc_auth, &digest); /* skip generate nonce for nonce_odd, just use the random value in stack */ /* calculate authdata */ /* in_param_digest = sha1(1S ~ 6S) */ offset = 0; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &enc_auth); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size); UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, pcr_info); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size); UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size); sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); /* authdata = hmac(key, in_param_digest || auth_params) */ offset = 0; UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session); hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset, (uint8_t *)&pub_auth); /* call the simple seal function */ ret = _tpm12_seal(locality, hkey, (const tpm_encauth_t *)&enc_auth, pcr_info_size, pcr_info, in_data_size, in_data, hauth, &nonce_odd, &cont_session, (const tpm_authdata_t *)&pub_auth, sealed_data_size, sealed_data, &nonce_even, &res_auth); /* skip check for res_auth */ return ret; } static uint32_t _tpm12_wrap_unseal(uint32_t locality, const uint8_t *in_data, uint32_t *secret_size, uint8_t *secret) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" uint32_t ret; tpm_nonce_t odd_osap, even_osap; tpm_nonce_t nonce_even, nonce_odd, nonce_even_d, nonce_odd_d; tpm_authhandle_t hauth, hauth_d; tpm_authdata_t shared_secret; tpm_authdata_t pub_auth, res_auth, pub_auth_d, res_auth_d; uint8_t cont_session = false, cont_session_d = false; tpm_key_handle_t hkey = TPM_KH_SRK; uint32_t offset; uint32_t ordinal = TPM_ORD_UNSEAL; tpm12_digest_t digest; /* skip generate nonce for odd_osap, just use the random value in stack */ /* establish a osap session */ ret = tpm12_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth, &nonce_even, &even_osap); if ( ret != TPM_SUCCESS ) return ret; /* calculate the shared secret shared-secret = HMAC(auth, even_osap || odd_osap) */ offset = 0; UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap); hmac((uint8_t *)&srk_authdata, WRAPPER_IN_BUF, offset, (uint8_t *)&shared_secret); /* establish a oiap session */ ret = tpm12_oiap(locality, &hauth_d, &nonce_even_d); if ( ret != TPM_SUCCESS ) return ret; /* skip generate nonce_odd & nonce_odd_d, just use the random values */ /* calculate authdata */ /* in_param_digest = sha1(1S ~ 6S) */ offset = 0; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal); UNLOAD_STORED_DATA12(WRAPPER_IN_BUF, offset, in_data); sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); /* authdata1 = hmac(key, in_param_digest || auth_params1) */ offset = 0; UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session); hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset, (uint8_t *)&pub_auth); /* authdata2 = hmac(key, in_param_digest || auth_params2) */ offset = 0; UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even_d); UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd_d); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session_d); hmac((uint8_t *)&blob_authdata, WRAPPER_IN_BUF, offset, (uint8_t *)&pub_auth_d); /* call the simple seal function */ ret = _tpm12_unseal(locality, hkey, in_data, hauth, &nonce_odd, &cont_session, (const tpm_authdata_t *)&pub_auth, hauth_d, &nonce_odd_d, &cont_session_d, (const tpm_authdata_t *)&pub_auth_d, secret_size, secret, &nonce_even, &res_auth, &nonce_even_d, &res_auth_d); /* skip check for res_auth */ return ret; #pragma GCC diagnostic pop } static bool init_pcr_info(uint32_t locality, tpm_locality_selection_t release_locs, uint32_t nr_create, const uint8_t indcs_create[], uint32_t nr_release, const uint8_t indcs_release[], const tpm12_digest_t *values_release[], tpm_pcr_info_long_t *pcr_info) { uint32_t offset; uint32_t i, blob_size; static tpm_locality_selection_t localities[TPM_NR_LOCALITIES] = { TPM_LOC_ZERO, TPM_LOC_ONE, TPM_LOC_TWO, TPM_LOC_THREE, TPM_LOC_FOUR }; if ( (release_locs & TPM_LOC_RSVD) != 0 ) return false; if ( pcr_info == NULL ) return false; if ( locality >= TPM_NR_LOCALITIES ) return false; if ( indcs_create == NULL ) nr_create = 0; if ( indcs_release == NULL || values_release == NULL ) nr_release = 0; for ( i = 0; i < nr_create; i++ ) if ( indcs_create[i] >= TPM_NR_PCRS ) return false; for ( i = 0; i < nr_release; i++ ) { if ( indcs_release[i] >= TPM_NR_PCRS || values_release[i] == NULL ) return false; } tb_memset(pcr_info, 0, sizeof(*pcr_info)); pcr_info->tag = TPM_TAG_PCR_INFO_LONG; pcr_info->locality_at_creation = localities[locality]; pcr_info->locality_at_release = release_locs; pcr_info->creation_pcr_selection.size_of_select = 3; for ( i = 0; i < nr_create; i++ ) pcr_info->creation_pcr_selection.pcr_select[indcs_create[i]/8] |= 1 << (indcs_create[i] % 8); pcr_info->release_pcr_selection.size_of_select = 3; for ( i = 0; i < nr_release; i++ ) pcr_info->release_pcr_selection.pcr_select[indcs_release[i]/8] |= 1 << (indcs_release[i] % 8); if ( nr_release > 0 ) { offset = 0; UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, &pcr_info->release_pcr_selection); blob_size = sizeof(tpm12_digest_t) * nr_release; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size); for ( i = 0; i < nr_release; i++ ) UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, values_release[i]); sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&pcr_info->digest_at_release); } return true; } static bool tpm12_seal(struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) { const uint8_t pcr_indcs_create[] = {17, 18}; const uint8_t pcr_indcs_release[] = {17, 18}; const tpm12_digest_t *pcr_values_release[] = {(tpm12_digest_t *)&post_launch_pcr17, (tpm12_digest_t *)&post_launch_pcr18}; uint32_t pcr_nr_create = ARRAY_SIZE(pcr_indcs_create); uint32_t pcr_nr_release = ARRAY_SIZE(pcr_indcs_release); uint32_t ret; tpm_pcr_info_long_t pcr_info; tpm_locality_selection_t release_locs = 1 << locality; if ( ti == NULL ) return false; if ( locality >= TPM_NR_LOCALITIES || in_data_size == 0 || in_data == NULL || sealed_data_size == NULL || sealed_data == NULL || *sealed_data_size == 0 ) { printk(TBOOT_WARN"TPM: tpm12_seal() bad parameter\n"); ti->error = TPM_BAD_PARAMETER; return false; } if ( !init_pcr_info(locality, release_locs, pcr_nr_create, pcr_indcs_create, pcr_nr_release, pcr_indcs_release, pcr_values_release, &pcr_info) ) { printk(TBOOT_WARN"TPM: tpm12_seal() bad parameter\n"); ti->error = TPM_BAD_PARAMETER; return false; } ret = _tpm12_wrap_seal(locality, &pcr_info, in_data_size, in_data, sealed_data_size, sealed_data); if ( ret != TPM_SUCCESS ) { ti->error = ret; return false; } return true; } static bool check_sealed_data(uint32_t size, const uint8_t *data) { if ( size < sizeof(tpm_stored_data12_header_t) ) return false; if ( ((tpm_stored_data12_header_t *)data)->tag != TPM_TAG_STORED_DATA12 ) return false; if ( ((tpm_stored_data12_header_t *)data)->seal_info_size == 0 ) { tpm_stored_data12_short_t *data12_s; if ( size < sizeof(*data12_s) ) return false; data12_s = (tpm_stored_data12_short_t *)data; if ( size != sizeof(*data12_s) + data12_s->enc_data_size ) return false; } else { tpm_stored_data12_t *data12; if ( size < sizeof(*data12) ) return false; data12 = (tpm_stored_data12_t *)data; if ( size != sizeof(*data12) + data12->enc_data_size ) return false; } return true; } static bool tpm12_unseal(struct tpm_if *ti, uint32_t locality, uint32_t sealed_data_size, const uint8_t *sealed_data, uint32_t *secret_size, uint8_t *secret) { uint32_t ret; if ( ti == NULL ) return false; if ( sealed_data == NULL || secret_size == NULL || secret == NULL ) { printk(TBOOT_WARN"TPM: tpm12_unseal() bad parameter\n"); ti->error = TPM_BAD_PARAMETER; return false; } if ( !check_sealed_data(sealed_data_size, sealed_data) ) { printk(TBOOT_WARN"TPM: tpm12_unseal() blob invalid\n"); ti->error = TPM_BAD_PARAMETER; return false; } ret = _tpm12_wrap_unseal(locality, sealed_data, secret_size, secret); if ( ret != TPM_SUCCESS ) { ti->error = ret; return false; } return true; } static void calc_pcr_composition(uint32_t nr, const uint8_t indcs[], const tpm12_digest_t *values[], tpm_composite_hash_t *composite) { uint32_t i, offset, blob_size; tpm_pcr_selection_t sel; if ( nr == 0 || indcs == NULL || values == NULL || composite == NULL) return; sel.size_of_select = 3; sel.pcr_select[0] = sel.pcr_select[1] = sel.pcr_select[2] = 0; for ( i = 0; i < nr; i++ ) sel.pcr_select[indcs[i]/8] |= 1 << (indcs[i] % 8); offset = 0; UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, &sel); blob_size = sizeof(tpm12_digest_t) * nr; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size); for ( i = 0; i < nr; i++ ) UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, values[i]); sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)composite); } static tpm_composite_hash_t *get_cre_pcr_composite(uint8_t *data) { if ( ((tpm_stored_data12_header_t *)data)->seal_info_size == 0 ) return NULL; else return &((tpm_stored_data12_t *)data)->seal_info.digest_at_creation; } static bool tpm12_cmp_creation_pcrs(uint32_t pcr_nr_create, const uint8_t pcr_indcs_create[], const tpm12_digest_t *pcr_values_create[], uint32_t sealed_data_size, uint8_t *sealed_data) { uint32_t i; tpm_composite_hash_t composite = {{0,}}, *cre_composite; if ( pcr_indcs_create == NULL ) pcr_nr_create = 0; for ( i = 0; i < pcr_nr_create; i++ ) { if ( pcr_indcs_create[i] >= TPM_NR_PCRS ) return false; } if ( !check_sealed_data(sealed_data_size, sealed_data) ) { printk(TBOOT_WARN"TPM: Bad blob.\n"); return false; } if ( pcr_nr_create > 0 ) calc_pcr_composition(pcr_nr_create, pcr_indcs_create, pcr_values_create, &composite); cre_composite = get_cre_pcr_composite(sealed_data); if ( cre_composite == NULL ) return false; if ( tb_memcmp(&composite, cre_composite, sizeof(composite)) ) { printk(TBOOT_WARN"TPM: Not equal to creation composition:\n"); print_hex(NULL, (uint8_t *)&composite, sizeof(composite)); print_hex(NULL, (uint8_t *)cre_composite, sizeof(composite)); return false; } return true; } static bool tpm12_verify_creation(struct tpm_if *ti, uint32_t sealed_data_size, uint8_t *sealed_data) { uint8_t pcr_indcs_create[] = {17, 18}; tpm12_digest_t pcr17, pcr18; const tpm12_digest_t *pcr_values_create[] = {&pcr17, &pcr18}; int i; if ( ti == NULL || sealed_data == NULL ) return false; tpm12_pcr_read(ti, 2, 17, (tpm_pcr_value_t *)&pcr17); tpm12_pcr_read(ti, 2, 18, (tpm_pcr_value_t *)&pcr18); /* to prevent rollback attack using old sealed measurements, verify that (creation) PCRs at mem integrity seal time are same as if we extend current PCRs with unsealed VL measurements */ /* TBD: we should check all DRTM PCRs */ for ( i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { if ( g_pre_k_s3_state.vl_entries[i].pcr == 17 ) extend_hash((tb_hash_t *)&pcr17, &g_pre_k_s3_state.vl_entries[i].hl.entries[0].hash, TB_HALG_SHA1); else if ( g_pre_k_s3_state.vl_entries[i].pcr == 18 ) extend_hash((tb_hash_t *)&pcr18, &g_pre_k_s3_state.vl_entries[i].hl.entries[0].hash, TB_HALG_SHA1); } if ( !tpm12_cmp_creation_pcrs(ARRAY_SIZE(pcr_indcs_create), pcr_indcs_create, pcr_values_create, sealed_data_size, sealed_data) ) { printk(TBOOT_WARN"extended PCR values don't match creation values in sealed blob.\n"); return false; } return true; } typedef uint32_t tpm_capability_area_t; #define TPM_CAP_NV_INDEX 0x00000011 static uint32_t tpm12_get_capability(uint32_t locality, tpm_capability_area_t cap_area, uint32_t sub_cap_size, const uint8_t *sub_cap, uint32_t *resp_size, uint8_t *resp) { uint32_t ret, offset, out_size, size; if ( sub_cap == NULL || resp_size == NULL || resp == NULL ) { printk(TBOOT_WARN"TPM: tpm12_get_capability() bad parameter\n"); return TPM_BAD_PARAMETER; } offset = 0; UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cap_area); UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, sub_cap_size); UNLOAD_BLOB(WRAPPER_IN_BUF, offset, sub_cap, sub_cap_size); out_size = sizeof(*resp_size) + *resp_size; ret = tpm12_submit_cmd(locality, TPM_ORD_GET_CAPABILITY, offset, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get capability, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: get capability, return value = %08X\n", ret); return ret; } offset = 0; LOAD_INTEGER(WRAPPER_OUT_BUF, offset, size); if ( *resp_size < size || size != out_size - sizeof(*resp_size) ) { printk(TBOOT_WARN"TPM: capability response too small\n"); return TPM_FAIL; } *resp_size = size; LOAD_BLOB(WRAPPER_OUT_BUF, offset, resp, *resp_size); return ret; } typedef struct __packed { tpm_pcr_selection_t pcr_selection; tpm_locality_selection_t locality_at_release; tpm_composite_hash_t digest_at_release; } tpm_pcr_info_short_t; typedef struct __packed { tpm_structure_tag_t tag; uint32_t attributes; } tpm_nv_attributes_t; typedef struct __packed { tpm_structure_tag_t tag; uint32_t nv_index; tpm_pcr_info_short_t pcr_info_read; tpm_pcr_info_short_t pcr_info_write; tpm_nv_attributes_t permission; uint8_t b_read_st_clear; uint8_t b_write_st_clear; uint8_t b_write_define; uint32_t data_size; } tpm_nv_data_public_t; static bool tpm12_get_nvindex_size(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *size) { uint32_t ret, offset, resp_size; uint8_t sub_cap[sizeof(index)]; uint8_t resp[sizeof(tpm_nv_data_public_t)]; uint32_t idx; if ( ti == NULL ) return false; if ( size == NULL ) { printk(TBOOT_WARN"TPM: tpm12_get_nvindex_size() bad parameter\n"); ti->error = TPM_BAD_PARAMETER; return false; } offset = 0; UNLOAD_INTEGER(sub_cap, offset, index); resp_size = sizeof(resp); ret = tpm12_get_capability(locality, TPM_CAP_NV_INDEX, sizeof(sub_cap), sub_cap, &resp_size, resp); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get nvindex size, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_DETA"TPM: fail to get public data of 0x%08X in TPM NV\n", index); ti->error = ret; return false; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, resp, resp_size); } #endif /* check size */ if ( resp_size == 0 ) { printk(TBOOT_WARN"TPM: Index 0x%08X does not exist\n", index); ti->error = TPM_BADINDEX; return false; } /* check index */ offset = sizeof(tpm_structure_tag_t); LOAD_INTEGER(resp, offset, idx); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get index value = %08X\n", idx); #endif if ( idx != index ) { printk(TBOOT_DETA"TPM: Index 0x%08X is not the one expected 0x%08X\n", idx, index); ti->error = TPM_BADINDEX; return false; } if ( resp_size != sizeof(resp) ) { printk(TBOOT_WARN"TPM: public data size of Index 0x%08X responsed incorrect\n", index); ti->error = TPM_FAIL; return false; } offset = resp_size - sizeof(uint32_t); LOAD_INTEGER(resp, offset, *size); return true; } static bool tpm12_get_nvindex_permission(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *attribute) { uint32_t ret, offset, resp_size; uint8_t sub_cap[sizeof(index)]; uint8_t resp[sizeof(tpm_nv_data_public_t)]; uint32_t idx; if ( ti == NULL ) return false; if ( attribute == NULL ) { printk(TBOOT_WARN"TPM: tpm12_get_nvindex_permission() bad parameter\n"); ti->error = TPM_BAD_PARAMETER; return false; } offset = 0; UNLOAD_INTEGER(sub_cap, offset, index); resp_size = sizeof(resp); ret = tpm12_get_capability(locality, TPM_CAP_NV_INDEX, sizeof(sub_cap), sub_cap, &resp_size, resp); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get nvindex permission, return value = %08X\n", ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_WARN"TPM: fail to get public data of 0x%08X in TPM NV\n", index); ti->error = ret; return false; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, resp, resp_size); } #endif /* check size */ if ( resp_size == 0 ) { printk(TBOOT_WARN"TPM: Index 0x%08X does not exist\n", index); ti->error = TPM_BADINDEX; return false; } /* check index */ offset = sizeof(tpm_structure_tag_t); LOAD_INTEGER(resp, offset, idx); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get index value = %08X\n", idx); #endif if ( idx != index ) { printk(TBOOT_WARN"TPM: Index 0x%08X is not the one expected 0x%08X\n", idx, index); ti->error = TPM_BADINDEX; return false; } if ( resp_size != sizeof(resp) ) { printk(TBOOT_ERR"TPM: public data size of Index 0x%08X responsed incorrect\n", index); ti->error = TPM_FAIL; return false; } offset = resp_size - sizeof(uint32_t) - 3 * sizeof(uint8_t) - sizeof(uint32_t); LOAD_INTEGER(resp, offset, *attribute); return true; } typedef struct __packed { tpm_structure_tag_t tag; uint8_t disable; uint8_t ownership; uint8_t deactivated; uint8_t read_pubek; uint8_t disable_owner_clear; uint8_t allow_maintenance; uint8_t physical_presence_lifetime_lock; uint8_t physical_presence_hw_enable; uint8_t physical_presence_cmd_enable; uint8_t cekp_used; uint8_t tpm_post; uint8_t tpm_post_lock; uint8_t fips; uint8_t operator; uint8_t enable_revoke_ek; uint8_t nv_locked; uint8_t read_srk_pub; uint8_t tpm_established; uint8_t maintenance_done; uint8_t disable_full_da_logic_info; } tpm_permanent_flags_t; typedef struct __packed { tpm_structure_tag_t tag; uint8_t deactivated; uint8_t disable_force_clear; uint8_t physical_presence; uint8_t phycical_presence_lock; uint8_t b_global_lock; } tpm_stclear_flags_t; #define TPM_CAP_FLAG 0x00000004 #define TPM_CAP_FLAG_PERMANENT 0x00000108 #define TPM_CAP_FLAG_VOLATILE 0x00000109 static uint32_t tpm12_get_flags(uint32_t locality, uint32_t flag_id, uint8_t *flags, uint32_t flag_size) { uint32_t ret, offset, resp_size; uint8_t sub_cap[sizeof(flag_id)]; tpm_structure_tag_t tag; if ( flags == NULL ) { printk(TBOOT_WARN"TPM: tpm12_get_flags() bad parameter\n"); return TPM_BAD_PARAMETER; } offset = 0; UNLOAD_INTEGER(sub_cap, offset, flag_id); resp_size = flag_size; ret = tpm12_get_capability(locality, TPM_CAP_FLAG, sizeof(sub_cap), sub_cap, &resp_size, flags); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get flags %08X, return value = %08X\n", flag_id, ret); #endif if ( ret != TPM_SUCCESS ) return ret; /* 1.2 spec, main part 2, rev 103 add one more byte to permanent flags, to be backward compatible, not assume all expected bytes can be gotten */ if ( resp_size > flag_size ) { printk(TBOOT_WARN"TPM: tpm12_get_flags() response size too small\n"); return TPM_FAIL; } offset = 0; LOAD_INTEGER(flags, offset, tag); offset = 0; UNLOAD_BLOB_TYPE(flags, offset, &tag); return ret; } #define TPM_CAP_PROPERTY 0x00000005 #define TPM_CAP_PROP_TIS_TIMEOUT 0x00000115 static uint32_t tpm12_get_timeout(uint32_t locality, uint8_t *prop, uint32_t prop_size) { uint32_t ret, offset, resp_size, prop_id = TPM_CAP_PROP_TIS_TIMEOUT; uint8_t sub_cap[sizeof(prop_id)]; uint32_t resp[4]; if ( (prop == NULL) || (prop_size < sizeof(resp)) ) { printk(TBOOT_WARN"TPM: tpm12_get_timeout() bad parameter\n"); return TPM_BAD_PARAMETER; } offset = 0; UNLOAD_INTEGER(sub_cap, offset, prop_id); resp_size = prop_size; ret = tpm12_get_capability(locality, TPM_CAP_PROPERTY, sizeof(sub_cap), sub_cap, &resp_size, prop); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get prop %08X, return value = %08X\n", prop_id, ret); #endif if ( ret != TPM_SUCCESS ) return ret; if ( resp_size != prop_size ) { printk(TBOOT_WARN"TPM: tpm_get_property() response size incorrect\n"); return TPM_FAIL; } offset = 0; LOAD_INTEGER(prop, offset, resp); offset = 0; UNLOAD_BLOB_TYPE(prop, offset, &resp); return ret; } /* ensure TPM is ready to accept commands */ static bool tpm12_init(struct tpm_if *ti) { tpm_permanent_flags_t pflags; tpm_stclear_flags_t vflags; uint32_t timeout[4]; uint32_t locality; uint32_t ret; if ( ti == NULL ) return false; printk(TBOOT_WARN"Warning: TPM1.2 detected, SHA1 is selected as hashing algorithm.\n"); if (!txt_is_launched()) ti->cur_loc = 0; else ti->cur_loc = 2; locality = ti->cur_loc; if ( !tpm_validate_locality(locality) ) { printk(TBOOT_WARN"TPM is not available.\n"); return false; } /* make sure tpm is not disabled/deactivated */ tb_memset(&pflags, 0, sizeof(pflags)); ret = tpm12_get_flags(locality, TPM_CAP_FLAG_PERMANENT, (uint8_t *)&pflags, sizeof(pflags)); if ( ret != TPM_SUCCESS ) { printk(TBOOT_WARN"TPM is disabled or deactivated.\n"); ti->error = ret; return false; } if ( pflags.disable ) { printk(TBOOT_WARN"TPM is disabled.\n"); return false; } tb_memset(&vflags, 0, sizeof(vflags)); ret = tpm12_get_flags(locality, TPM_CAP_FLAG_VOLATILE, (uint8_t *)&vflags, sizeof(vflags)); if ( ret != TPM_SUCCESS ) { printk(TBOOT_WARN"TPM is disabled or deactivated.\n"); ti->error = ret; return false; } if ( vflags.deactivated ) { printk(TBOOT_WARN"TPM is deactivated.\n"); return false; } printk(TBOOT_INFO"TPM is ready\n"); printk(TBOOT_DETA"TPM nv_locked: %s\n", (pflags.nv_locked != 0) ? "TRUE" : "FALSE"); /* get tpm timeout values */ ret = tpm12_get_timeout(locality, (uint8_t *)&timeout, sizeof(timeout)); if ( ret != TPM_SUCCESS ) { printk(TBOOT_WARN"TPM timeout values are not achieved, " "default values will be used.\n"); ti->error = ret; } else { /* * timeout_x represents the number of milliseconds for the timeout * and timeout[x] represents the number of microseconds. */ ti->timeout.timeout_a = timeout[0]/1000; ti->timeout.timeout_b = timeout[1]/1000; ti->timeout.timeout_c = timeout[2]/1000; ti->timeout.timeout_d = timeout[3]/1000; printk(TBOOT_DETA"TPM timeout values: A: %u, B: %u, C: %u, D: %u\n", ti->timeout.timeout_a, ti->timeout.timeout_b, ti->timeout.timeout_c, ti->timeout.timeout_d); /* * if any timeout values are less than default values, set to default * value (due to bug with some TPMs) */ if ( ti->timeout.timeout_a < TIMEOUT_A ) { ti->timeout.timeout_a = TIMEOUT_A; printk(TBOOT_WARN"Wrong timeout A, fallback to %u\n", TIMEOUT_A); } if ( ti->timeout.timeout_b < TIMEOUT_B ) { ti->timeout.timeout_b = TIMEOUT_B; printk(TBOOT_WARN"Wrong timeout B, fallback to %u\n", TIMEOUT_B); } if ( ti->timeout.timeout_c < TIMEOUT_C ) { ti->timeout.timeout_c = TIMEOUT_C; printk(TBOOT_WARN"Wrong timeout C, fallback to %u\n", TIMEOUT_C); } if ( ti->timeout.timeout_d < TIMEOUT_D ) { ti->timeout.timeout_d = TIMEOUT_D; printk(TBOOT_WARN"Wrong timeout D, fallback to %u\n", TIMEOUT_D); } } /* init version */ ti->major = TPM12_VER_MAJOR; ti->minor = TPM12_VER_MINOR; /* init supported alg list */ ti->banks = 1; ti->alg_count = 1; ti->algs[0] = TB_HALG_SHA1; ti->extpol = TB_EXTPOL_FIXED; ti->cur_alg = TB_HALG_SHA1; /* init NV index */ ti->tb_policy_index = 0x20000001; ti->lcp_own_index = 0x40000001; ti->tb_err_index = 0x20000002; ti->sgx_svn_index = 0x50000004; return true; } static uint32_t tpm12_save_state(struct tpm_if *ti, uint32_t locality) { uint32_t ret, offset, out_size; uint32_t retries = 0; if ( ti == NULL ) return TPM_BAD_PARAMETER; do { offset = 0; out_size = 0; ret = tpm12_submit_cmd(locality, TPM_ORD_SAVE_STATE, offset, &out_size); if ( retries == 0 ) printk(TBOOT_INFO"TPM: save state, return value = %08X\n", ret); else if ( retries == 1 ) printk(TBOOT_INFO"retrying command: ."); else printk(TBOOT_INFO"."); if ( ret != TPM_RETRY ) break; retries++; delay(100); } while ( retries < MAX_SAVESTATE_RETRIES ); if ( retries >= MAX_SAVESTATE_RETRIES ) printk(TBOOT_INFO"TIMEOUT!"); if ( retries > 0 ) printk(TBOOT_INFO"\n"); return ret; } static bool tpm12_get_random(struct tpm_if *ti, uint32_t locality, uint8_t *random_data, uint32_t *data_size) { uint32_t ret, in_size = 0, out_size, requested_size; static bool first_attempt; if ( ti == NULL ) return false; if ( random_data == NULL || data_size == NULL || *data_size == 0 ) { ti->error = TPM_BAD_PARAMETER; return false; } first_attempt = true; requested_size = *data_size; /* copy the *data_size into buf in reversed byte order */ reverse_copy(WRAPPER_IN_BUF + in_size, data_size, sizeof(*data_size)); in_size += sizeof(*data_size); out_size = *data_size + sizeof(*data_size); ret = tpm12_submit_cmd(locality, TPM_ORD_GET_RANDOM, in_size, &out_size); #ifdef TPM_TRACE printk(TBOOT_DETA"TPM: get random %u bytes, return value = %08X\n", *data_size, ret); #endif if ( ret != TPM_SUCCESS ) { printk(TBOOT_WARN"TPM: get random %u bytes, return value = %08X\n", *data_size, ret); ti->error = ret; return false; } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, WRAPPER_OUT_BUF, out_size); } #endif if ( out_size <= sizeof(*data_size) ) { *data_size = 0; return true; } out_size -= sizeof(*data_size); reverse_copy(data_size, WRAPPER_OUT_BUF, sizeof(*data_size)); if ( *data_size > requested_size ) { printk(TBOOT_WARN"Requeseted %x random bytes but got %x\n", requested_size, *data_size); ti->error = TPM_NOSPACE; return false; } if ( *data_size > 0 ) tb_memcpy(random_data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size); /* data might be used as key, so clear from buffer memory */ tb_memset(WRAPPER_OUT_BUF + sizeof(*data_size), 0, *data_size); /* if TPM doesn't return all requested random bytes, try one more time */ if ( *data_size < requested_size ) { printk(TBOOT_WARN"requested %x random bytes but only got %x\n", requested_size, *data_size); /* we're only going to try twice */ if ( first_attempt ) { first_attempt = false; uint32_t second_size = requested_size - *data_size; printk(TBOOT_INFO"trying one more time to get remaining %x bytes\n", second_size); if (!tpm12_get_random(ti, locality, random_data + *data_size, &second_size)) return false; *data_size += second_size; } } return true; } static bool tpm12_cap_pcrs(struct tpm_if *ti, u32 locality, int pcr) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" bool was_capped[TPM_NR_PCRS] = {false}; tpm_pcr_value_t cap_val; /* use whatever val is on stack */ if ( ti == NULL ) return false; if (pcr >= 0) { _tpm12_pcr_extend(ti, locality, pcr, &cap_val); return true; } /* ensure PCRs 17 + 18 are always capped */ _tpm12_pcr_extend(ti, locality, 17, &cap_val); _tpm12_pcr_extend(ti, locality, 18, &cap_val); was_capped[17] = was_capped[18] = true; /* also cap every dynamic PCR we extended (only once) */ /* don't cap static PCRs since then they would be wrong after S3 resume */ tb_memset(&was_capped, true, TPM_PCR_RESETABLE_MIN*sizeof(bool)); for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { if ( !was_capped[g_pre_k_s3_state.vl_entries[i].pcr] ) { _tpm12_pcr_extend(ti, locality, g_pre_k_s3_state.vl_entries[i].pcr, &cap_val); was_capped[g_pre_k_s3_state.vl_entries[i].pcr] = true; } } printk(TBOOT_INFO"cap'ed dynamic PCRs\n"); return true; #pragma GCC diagnostic pop } static bool tpm12_check(void) { uint32_t ret, out_size = 0; ret = tpm12_submit_cmd(0, 0xFFFFFFFF, 0, &out_size); return ( ret == TPM_BAD_ORDINAL ); } const struct tpm_if_fp tpm_12_if_fp = { .init = tpm12_init, .pcr_read = tpm12_pcr_read, .pcr_extend = tpm12_pcr_extend, .pcr_reset = tpm12_pcr_reset, .nv_read = tpm12_nv_read_value, .nv_write = tpm12_nv_write_value, .get_nvindex_size = tpm12_get_nvindex_size, .get_nvindex_permission = tpm12_get_nvindex_permission, .seal = tpm12_seal, .unseal = tpm12_unseal, .verify_creation = tpm12_verify_creation, .get_random = tpm12_get_random, .save_state = tpm12_save_state, .cap_pcrs = tpm12_cap_pcrs, .check = tpm12_check, }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/tpm_20.c0000644000000000000000000026517414210363175014760 0ustar 00000000000000/* * tpm_20.c: TPM2.0-related support functions * * Copyright (c) 2006-2013, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static u8 cmd_buf[MAX_COMMAND_SIZE]; static u8 rsp_buf[MAX_RESPONSE_SIZE]; extern loader_ctx *g_ldr_ctx; #define reverse_copy_in(out, var) {\ _reverse_copy((uint8_t *)(out), (uint8_t *)&(var), sizeof(var));\ out += sizeof(var);\ } #define reverse_copy_out(var, out) {\ _reverse_copy((uint8_t *)&(var), (uint8_t *)(out), sizeof(var));\ out += sizeof(var);\ } static void reverse_copy_header(u32 cmd_code, TPM_CMD_SESSIONS_IN *sessions_in) { u16 tag; if (sessions_in == NULL || sessions_in->num_sessions == 0) tag = TPM_ST_NO_SESSIONS; else tag = TPM_ST_SESSIONS; reverse_copy(cmd_buf, &tag, sizeof(tag)); reverse_copy(cmd_buf + CMD_CC_OFFSET, &cmd_code, sizeof(cmd_code)); } static void reverse_copy_pcr_selection_in(void **other, TPML_PCR_SELECTION *pcr_selection) { u32 i, k; /* Copy count of pcrs to be read. */ reverse_copy_in(*other, pcr_selection->count); for (i=0; icount; i++) { /* Copy alg ID for PCR to be read. */ reverse_copy_in(*other, pcr_selection->selections[i].hash); /* Copy size of select array. */ reverse_copy_in(*other, pcr_selection->selections[i].size_of_select); /* Copy bit field of the PCRs selected. */ for (k=0; kselections[i].size_of_select; k++) reverse_copy_in(*other, pcr_selection->selections[i].pcr_select[k]); } } static bool reverse_copy_pcr_selection_out(TPML_PCR_SELECTION *pcr_selection, void **other) { u32 i, k; if (pcr_selection == NULL) return false; /* Copy count of pcrs to be read. */ reverse_copy_out(pcr_selection->count, *other); if ( pcr_selection->count > HASH_COUNT ) return false; for (i=0; icount; i++) { /* Copy alg ID for PCR to be read. */ reverse_copy_out(pcr_selection->selections[i].hash, *other); /* Copy size of select array. */ reverse_copy_out(pcr_selection->selections[i].size_of_select, *other); if ( pcr_selection->selections[i].size_of_select > sizeof(pcr_selection->selections[i].pcr_select) ) return false; /* Copy bit field of the PCRs selected */ for (k=0; kselections[i].size_of_select; k++) reverse_copy_out(pcr_selection->selections[i].pcr_select[k], *other); } return true; } /* * Copy sized byte buffer from source to destination and * twiddle the bytes in the size field. * * This can be used for the any of the following * TPM 2.0 data structures, but is not limited to these: * * ENCRYPTED_SECRET_2B * TPM2B_DIGEST * TPM2B_NONCE * TPM2B_DATA * etc. (any structures consisting of UINT16 followed by a * byte buffer whose size is specified by the UINT16. * * Inputs: * * dest -- pointer to SIZED_BYTE_BUFFER * src -- pointer to SIZED_BYTE_BUFFER * * Outputs: * * number of bytes copied */ static u16 reverse_copy_sized_buf_in(TPM2B *dest, TPM2B *src) { int i; if (dest == NULL || src == NULL) return 0; reverse_copy(&dest->size, &src->size, sizeof(u16)); for (i=0; isize; i++) dest->buffer[i] = src->buffer[i]; return sizeof(u16) + src->size; } /* * Inputs: dest->size should contain the buffer size of dest->buffer[] * Outputs: dest->size should contain the final copied data size * * Return: 0, failed; 2+, succeed. */ static u16 reverse_copy_sized_buf_out(TPM2B *dest, TPM2B *src) { u16 i, size; if (dest == NULL || src == NULL) return 0; reverse_copy(&size, &src->size, sizeof(u16)); if ( size > dest->size ) return 0; dest->size = size; for (i=0; isize; i++) dest->buffer[i] = src->buffer[i]; return sizeof(u16) + dest->size; } static bool reverse_copy_digest_out(TPML_DIGEST *tpml_digest, void **other) { u32 i; u16 size; if (tpml_digest == NULL) return false; reverse_copy_out(tpml_digest->count, *other); if ( tpml_digest->count > 8 ) return false; for (i=0; icount; i++) { tpml_digest->digests[i].t.size = sizeof(tpml_digest->digests[i].t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(tpml_digest->digests[i]), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; } return true; } static void reverse_copy_session_data_in(void **other, TPM_CMD_SESSION_DATA_IN *session_data, u32 *session_size) { *session_size += sizeof(u32) + sizeof( u16 ) + session_data->nonce.t.size + sizeof( u8 ) + sizeof( u16 ) + session_data->hmac.t.size; /* copy session handle */ reverse_copy_in(*other, session_data->session_handle); /* Copy nonce */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&session_data->nonce); /* Copy attributes */ *((u8 *)*other) = *(u8 *)(void *)&(session_data->session_attr); *other += sizeof(u8); /* Copy hmac data */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&session_data->hmac); } static void reverse_copy_sessions_in(void **other, TPM_CMD_SESSIONS_IN *sessions_in) { int i; u32 session_size = 0; void *session_size_ptr = *other; if (sessions_in == NULL) return; if (sessions_in->num_sessions != 0) { *other += sizeof(u32); for (i=0; inum_sessions; i++) reverse_copy_session_data_in(other, &sessions_in->sessions[i], &session_size); } reverse_copy(session_size_ptr, &session_size, sizeof(u32)); } static bool reverse_copy_session_data_out(TPM_CMD_SESSION_DATA_OUT *session_data, void **other) { u16 size; if (session_data == NULL) return false; /* Copy nonce */ session_data->nonce.t.size = sizeof(session_data->nonce.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(session_data->nonce), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; /* Copy sessionAttributes */ *(u8 *)(void *)&(session_data->session_attr) = *((u8 *)*other); *other += sizeof(u8); /* Copy hmac */ session_data->hmac.t.size = sizeof(session_data->hmac.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(session_data->hmac), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; return true; } static bool reverse_copy_sessions_out(TPM_CMD_SESSIONS_OUT *sessions_out, void *other, u16 rsp_tag, TPM_CMD_SESSIONS_IN *sessions_in) { int i; if (sessions_in == NULL || sessions_out == NULL || rsp_tag != TPM_ST_SESSIONS) return false; sessions_out->num_sessions = sessions_in->num_sessions; for (i=0; inum_sessions; i++) if ( !reverse_copy_session_data_out(&sessions_out->sessions[i], &other) ) return false; return true; } typedef struct { u16 alg_id; u16 size; /* Size of digest */ } HASH_SIZE_INFO; HASH_SIZE_INFO hash_sizes[] = { {TPM_ALG_SHA1, SHA1_DIGEST_SIZE}, {TPM_ALG_SHA256, SHA256_DIGEST_SIZE}, {TPM_ALG_SHA384, SHA384_DIGEST_SIZE}, {TPM_ALG_SHA512, SHA512_DIGEST_SIZE}, {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE}, {TPM_ALG_NULL,0} }; u16 get_digest_size(u16 id) { unsigned int i; for(i=0; i<(sizeof(hash_sizes)/sizeof(HASH_SIZE_INFO)); i++) { if(hash_sizes[i].alg_id == id) return hash_sizes[i].size; } /* If not found, return 0 size, and let TPM handle the error. */ return 0 ; } static void reverse_copy_digest_value_in(void **other, TPML_DIGEST_VALUES *tpml_digest) { unsigned int i, k, num_bytes; reverse_copy_in(*other, tpml_digest->count); for (i=0; icount; i++) { reverse_copy_in(*other, tpml_digest->digests[i].hash_alg); num_bytes = get_digest_size(tpml_digest->digests[i].hash_alg); for (k=0; kdigests[i].digest.sha1[k]; *other += sizeof(u8); } } } static bool reverse_copy_digest_values_out(TPML_DIGEST_VALUES *tpml_digest, void **other) { unsigned int i, k, num_bytes; if (tpml_digest == NULL) return false; reverse_copy_out(tpml_digest->count, *other); if ( tpml_digest->count > HASH_COUNT ) return false; for (i=0; icount; i++) { reverse_copy_out(tpml_digest->digests[i].hash_alg, *other); num_bytes = get_digest_size(tpml_digest->digests[i].hash_alg); for (k=0; kdigests[i].digest.sha1[k] = *((u8 *)*other); *other += sizeof(u8); } } return true; } /* * Copy public data from input data structure into output data stream * for commands that require it. * * Inputs: * * pointer to pointer to TPM command area to fill in with public data * * pointer to TPM2B_PUBLIC structure * * Outputs: * * otherData pointer points to end byte past command buffer. This allows * caller to set the commandSize field for the command. */ static void reverse_copy_public_in(void **other, TPM2B_PUBLIC *public) { TPMT_KEYEDHASH_SCHEME *scheme; TPMT_RSA_SCHEME *rsa_scheme = &(public->t.public_area.param.rsa.scheme); TPMT_ECC_SCHEME *ecc_scheme = &(public->t.public_area.param.ecc.scheme); TPMT_KDF_SCHEME *kdf = &(public->t.public_area.param.ecc.kdf); TPMT_ASYM_SCHEME *asym_scheme = &(public->t.public_area.param.asym.scheme); void *size_ptr; u16 size; size_ptr = *other; *other += sizeof(u16); reverse_copy_in(*other, public->t.public_area.type); reverse_copy_in(*other, public->t.public_area.name_alg); /* Copy public->t.object_attr */ reverse_copy(*other, (void *)&public->t.public_area.object_attr, sizeof(u32)); *other += sizeof(u32); /* Copy public->t.auth_policy */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&public->t.public_area.auth_policy); /* Copy public->t.param */ switch(public->t.public_area.type) { case TPM_ALG_KEYEDHASH: scheme = &(public->t.public_area.param.keyed_hash.scheme); reverse_copy_in(*other, scheme->scheme); if(scheme->scheme != TPM_ALG_NULL) { /* copy details */ if(scheme->scheme == TPM_ALG_HMAC) { reverse_copy_in(*other, scheme->details.hmac.hash_alg); } else { reverse_copy_in(*other, scheme->details.xor.hash_alg); reverse_copy_in(*other, scheme->details.xor.kdf); } } /* Copy public->t.public_area.unique */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&public->t.public_area.unique.keyed_hash); break; case TPM_ALG_SYMCIPHER: reverse_copy_in(*other, public->t.public_area.param.sym.alg); if (public->t.public_area.param.sym.alg != TPM_ALG_NULL) { reverse_copy_in(*other, public->t.public_area.param.sym.key_bits.sym); reverse_copy_in(*other, public->t.public_area.param.sym.mode.sym); } /* Copy public->t.public_area.unique */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&public->t.public_area.unique.sym); break; case TPM_ALG_RSA: /* Copy symmetric fields */ reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.alg); if (public->t.public_area.param.rsa.symmetric.alg != TPM_ALG_NULL) { reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.key_bits.sym); reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.mode.sym); } /* Copy scheme */ reverse_copy_in(*other, rsa_scheme->scheme); if (rsa_scheme->scheme != TPM_ALG_NULL) { switch (rsa_scheme->scheme) { case TPM_ALG_RSASSA: reverse_copy_in(*other, rsa_scheme->details.rsassa.hash_alg); break; case TPM_ALG_RSAPSS: reverse_copy_in(*other, rsa_scheme->details.rsapss.hash_alg); break; case TPM_ALG_OAEP: reverse_copy_in(*other, rsa_scheme->details.oaep.hash_alg); break; case TPM_ALG_ECDSA: reverse_copy_in(*other, rsa_scheme->details.ecdsa.hash_alg); break; case TPM_ALG_SM2: reverse_copy_in(*other, rsa_scheme->details.sm2.hash_alg); break; case TPM_ALG_ECDAA: reverse_copy_in(*other, rsa_scheme->details.ecdaa.hash_alg); reverse_copy_in(*other, rsa_scheme->details.ecdaa.count); break; case TPM_ALG_ECSCHNORR: reverse_copy_in(*other, rsa_scheme->details.ec_schnorr.hash_alg); break; default: reverse_copy_in(*other, rsa_scheme->details.any.hash_alg); break; } } /* Copy keybits */ reverse_copy_in(*other, public->t.public_area.param.rsa.key_bits); /* Copy exponent */ reverse_copy_in(*other, public->t.public_area.param.rsa.exponent); /* Copy public->t.public_area.unique */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&public->t.public_area.unique.rsa); break; case TPM_ALG_ECC: /* Copy symmetric fields */ reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.alg); if (public->t.public_area.param.ecc.symmetric.alg != TPM_ALG_NULL) { reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.key_bits.sym); reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.mode.sym); } /* Copy ECC scheme */ reverse_copy_in(*other, ecc_scheme->scheme); if (ecc_scheme->scheme != TPM_ALG_NULL) { switch (ecc_scheme->scheme) { case TPM_ALG_RSASSA: reverse_copy_in(*other, ecc_scheme->details.rsassa.hash_alg); break; case TPM_ALG_RSAPSS: reverse_copy_in(*other, ecc_scheme->details.rsapss.hash_alg); break; case TPM_ALG_ECDSA: reverse_copy_in(*other, ecc_scheme->details.ecdsa.hash_alg); break; case TPM_ALG_SM2: reverse_copy_in(*other, ecc_scheme->details.sm2.hash_alg); break; case TPM_ALG_ECDAA: reverse_copy_in(*other, ecc_scheme->details.ecdaa.hash_alg); reverse_copy_in(*other, ecc_scheme->details.ecdaa.count); break; case TPM_ALG_ECSCHNORR: reverse_copy_in(*other, ecc_scheme->details.ec_schnorr.hash_alg); break; case TPM_ALG_HMAC: reverse_copy_in(*other, ecc_scheme->details.hmac.hash_alg); break; default: reverse_copy_in(*other, ecc_scheme->details.any.hash_alg); break; } } /* Copy curve_id */ reverse_copy_in(*other, public->t.public_area.param.ecc.curve_id); /* Copy KDF scheme */ reverse_copy_in(*other, kdf->scheme); switch (kdf->scheme) { case TPM_ALG_MGF1: reverse_copy_in(*other, kdf->details.mgf1.hash_alg); break; case TPM_ALG_KDF1_SP800_56a: reverse_copy_in(*other, kdf->details.kdf1_SP800_56a.hash_alg); break; case TPM_ALG_KDF1_SP800_108: reverse_copy_in(*other, kdf->details.kdf1_sp800_108.hash_alg); break; default: /* Copy something bogus and let TPM return error code */ *((u16 *)*other) = 0xffff; *other += sizeof(u16); break; } /* Copy public->t.public_area.unique */ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&public->t.public_area.unique.ecc); break; default: /* Copy symmetric fields */ reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.alg); if (public->t.public_area.param.asym.symmetric.alg != TPM_ALG_NULL) { reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.key_bits.sym); reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.mode.sym); } /* Copy scheme */ reverse_copy_in(*other, asym_scheme->scheme); if (asym_scheme->scheme != TPM_ALG_NULL) { switch (asym_scheme->scheme) { case TPM_ALG_RSASSA: reverse_copy_in(*other, asym_scheme->details.rsassa.hash_alg); break; case TPM_ALG_RSAPSS: reverse_copy_in(*other, asym_scheme->details.rsapss.hash_alg); break; case TPM_ALG_OAEP: reverse_copy_in(*other, asym_scheme->details.oaep.hash_alg); break; case TPM_ALG_ECDSA: reverse_copy_in(*other, asym_scheme->details.ecdsa.hash_alg); break; case TPM_ALG_SM2: reverse_copy_in(*other, asym_scheme->details.sm2.hash_alg); break; case TPM_ALG_ECDAA: reverse_copy_in(*other, asym_scheme->details.ecdaa.hash_alg); reverse_copy_in(*other, asym_scheme->details.ecdaa.count); break; case TPM_ALG_ECSCHNORR: reverse_copy_in(*other, asym_scheme->details.ec_schnorr.hash_alg); break; default: reverse_copy_in(*other, asym_scheme->details.any.hash_alg); break; } } break; } /* Now calculate and write the inPublic size; don't include size field in the size calc */ size = (u8 *)*other - (u8 *)size_ptr - sizeof(u16); reverse_copy(size_ptr, &size, sizeof(u16)); } /* * Copy public data from input data structure into output data stream * for commands that require it. * * Inputs: * * pointer to TPM2B_PUBLIC structure for returned data * * pointer to pointer to TPM command byte stream for the returned data * * Outputs: * * public contains the de-canonicalized data extracted from the output data stream */ static bool reverse_copy_public_out(TPM2B_PUBLIC *public, void **other) { TPMT_KEYEDHASH_SCHEME *scheme; TPMT_RSA_SCHEME *rsa_scheme = &(public->t.public_area.param.rsa.scheme); TPMT_ECC_SCHEME *ecc_scheme = &(public->t.public_area.param.ecc.scheme); TPMT_KDF_SCHEME *kdf = &(public->t.public_area.param.ecc.kdf); TPMT_ASYM_SCHEME *asym_scheme = &(public->t.public_area.param.asym.scheme); u16 size; if (public == NULL) return false; reverse_copy_out(public->t.size, *other); reverse_copy_out(public->t.public_area.type, *other); reverse_copy_out(public->t.public_area.name_alg, *other); /* Copy public->t.object_attr */ reverse_copy((void *)&public->t.public_area.object_attr, *other, sizeof(u32)); *other += sizeof(u32); /* Copy public->t.auth_policy */ public->t.public_area.auth_policy.t.size = sizeof(public->t.public_area.auth_policy.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.auth_policy, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; /* Copy public->t.param */ switch(public->t.public_area.type) { case TPM_ALG_KEYEDHASH: scheme = &(public->t.public_area.param.keyed_hash.scheme); reverse_copy_out(scheme->scheme, *other); if(scheme->scheme != TPM_ALG_NULL) { /* copy details */ if(scheme->scheme == TPM_ALG_HMAC) { reverse_copy_out(scheme->details.hmac.hash_alg, *other); } else { reverse_copy_out(scheme->details.xor.hash_alg, *other); reverse_copy_out(scheme->details.xor.kdf, *other); } } /* Copy public->t.public_area.unique */ public->t.public_area.unique.keyed_hash.t.size = sizeof(public->t.public_area.unique.keyed_hash.t.buffer); size = reverse_copy_sized_buf_out( (TPM2B *)&public->t.public_area.unique.keyed_hash, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; break; case TPM_ALG_SYMCIPHER: reverse_copy_out(public->t.public_area.param.sym.alg, *other); if (public->t.public_area.param.sym.alg != TPM_ALG_NULL) { reverse_copy_out(public->t.public_area.param.sym.key_bits.sym, *other); reverse_copy_out(public->t.public_area.param.sym.mode.sym, *other); } /* Copy public->t.public_area.unique */ public->t.public_area.unique.sym.t.size = sizeof(public->t.public_area.unique.sym.t.buffer); size = reverse_copy_sized_buf_out( (TPM2B *)&public->t.public_area.unique.sym, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; break; case TPM_ALG_RSA: /* Copy symmetric fields */ reverse_copy_out(public->t.public_area.param.rsa.symmetric.alg, *other); if (public->t.public_area.param.rsa.symmetric.alg != TPM_ALG_NULL) { reverse_copy_out(public->t.public_area.param.rsa.symmetric.key_bits.sym, *other); reverse_copy_out(public->t.public_area.param.rsa.symmetric.mode.sym, *other); } /* Copy scheme */ reverse_copy_out(rsa_scheme->scheme, *other); if (rsa_scheme->scheme != TPM_ALG_NULL) { switch (rsa_scheme->scheme) { case TPM_ALG_RSASSA: reverse_copy_out(rsa_scheme->details.rsassa.hash_alg, *other); break; case TPM_ALG_RSAPSS: reverse_copy_out(rsa_scheme->details.rsapss.hash_alg, *other); break; case TPM_ALG_OAEP: reverse_copy_out(rsa_scheme->details.oaep.hash_alg, *other); break; case TPM_ALG_ECDSA: reverse_copy_out(rsa_scheme->details.ecdsa.hash_alg, *other); break; case TPM_ALG_SM2: reverse_copy_out(rsa_scheme->details.sm2.hash_alg, *other); break; case TPM_ALG_ECDAA: reverse_copy_out(rsa_scheme->details.ecdaa.hash_alg, *other); reverse_copy_out(rsa_scheme->details.ecdaa.count, *other); break; case TPM_ALG_ECSCHNORR: reverse_copy_out(rsa_scheme->details.ec_schnorr.hash_alg, *other); break; default: reverse_copy_out(rsa_scheme->details.any.hash_alg, *other); break; } } /* Copy keybits */ reverse_copy_out(public->t.public_area.param.rsa.key_bits, *other); /* Copy exponent */ reverse_copy_out(public->t.public_area.param.rsa.exponent, *other); /* Copy public->t.public_area.unique */ public->t.public_area.unique.rsa.t.size = sizeof(public->t.public_area.unique.rsa.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.rsa, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; break; case TPM_ALG_ECC: /* Copy symmetric fields */ reverse_copy_out(public->t.public_area.param.ecc.symmetric.alg, *other); if (public->t.public_area.param.ecc.symmetric.alg != TPM_ALG_NULL) { reverse_copy_out(public->t.public_area.param.ecc.symmetric.key_bits.sym, *other); reverse_copy_out(public->t.public_area.param.ecc.symmetric.mode.sym, *other); } /* Copy ECC scheme */ reverse_copy_out(ecc_scheme->scheme, *other); if (ecc_scheme->scheme != TPM_ALG_NULL) { switch (ecc_scheme->scheme) { case TPM_ALG_RSASSA: reverse_copy_out(ecc_scheme->details.rsassa.hash_alg, *other); break; case TPM_ALG_RSAPSS: reverse_copy_out(ecc_scheme->details.rsapss.hash_alg, *other); break; case TPM_ALG_ECDSA: reverse_copy_out(ecc_scheme->details.ecdsa.hash_alg, *other); break; case TPM_ALG_SM2: reverse_copy_out(ecc_scheme->details.sm2.hash_alg, *other); break; case TPM_ALG_ECDAA: reverse_copy_out(ecc_scheme->details.ecdaa.hash_alg, *other); reverse_copy_out(ecc_scheme->details.ecdaa.count, *other); break; case TPM_ALG_ECSCHNORR: reverse_copy_out(ecc_scheme->details.ec_schnorr.hash_alg, *other); break; case TPM_ALG_HMAC: reverse_copy_out(ecc_scheme->details.hmac.hash_alg, *other); break; default: reverse_copy_out(ecc_scheme->details.any.hash_alg, *other); break; } } /* Copy curve_id */ reverse_copy_out(public->t.public_area.param.ecc.curve_id, *other); /* Copy KDF scheme */ reverse_copy_out(kdf->scheme, *other); switch (kdf->scheme) { case TPM_ALG_MGF1: reverse_copy_out(kdf->details.mgf1.hash_alg, *other); break; case TPM_ALG_KDF1_SP800_56a: reverse_copy_out(kdf->details.kdf1_SP800_56a.hash_alg, *other); break; case TPM_ALG_KDF1_SP800_108: reverse_copy_out(kdf->details.kdf1_sp800_108.hash_alg, *other); break; default: /* Copy something bogus and let TPM return error code */ *((u16 *)*other) = 0xffff; *other += sizeof(u16); break; } /* Copy public->t.public_area.unique */ public->t.public_area.unique.ecc.x.t.size = sizeof(public->t.public_area.unique.ecc.x.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.ecc.x, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; public->t.public_area.unique.ecc.y.t.size = sizeof(public->t.public_area.unique.ecc.y.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.ecc.y, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; break; default: /* Copy symmetric fields */ reverse_copy_out(public->t.public_area.param.asym.symmetric.alg, *other); if (public->t.public_area.param.asym.symmetric.alg != TPM_ALG_NULL) { reverse_copy_out(public->t.public_area.param.asym.symmetric.key_bits.sym, *other); reverse_copy_out(public->t.public_area.param.asym.symmetric.mode.sym, *other); } /* Copy scheme */ reverse_copy_out(asym_scheme->scheme, *other); if (asym_scheme->scheme != TPM_ALG_NULL) { switch (asym_scheme->scheme) { case TPM_ALG_RSASSA: reverse_copy_out(asym_scheme->details.rsassa.hash_alg, *other); break; case TPM_ALG_RSAPSS: reverse_copy_out(asym_scheme->details.rsapss.hash_alg, *other); break; case TPM_ALG_OAEP: reverse_copy_out(asym_scheme->details.oaep.hash_alg, *other); break; case TPM_ALG_ECDSA: reverse_copy_out(asym_scheme->details.ecdsa.hash_alg, *other); break; case TPM_ALG_SM2: reverse_copy_out(asym_scheme->details.sm2.hash_alg, *other); break; case TPM_ALG_ECDAA: reverse_copy_out(asym_scheme->details.ecdaa.hash_alg, *other); reverse_copy_out(asym_scheme->details.ecdaa.count, *other); break; case TPM_ALG_ECSCHNORR: reverse_copy_out(asym_scheme->details.ec_schnorr.hash_alg, *other); break; default: reverse_copy_out(asym_scheme->details.any.hash_alg, *other); break; } } break; } return true; } static bool reverse_copy_creation_data_out(TPM2B_CREATION_DATA *data, void **other) { u16 size; if (data == NULL) return false; reverse_copy_out(data->t.size, *other); if ( !reverse_copy_pcr_selection_out(&data->t.data.pcr_select, other) ) return false; data->t.data.pcr_digest.t.size = sizeof(data->t.data.pcr_digest.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.pcr_digest), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; *((u8 *)(void *)&data->t.data.locality) = *((u8 *)*other); *other += sizeof(u8); reverse_copy_out(data->t.data.parent_name_alg, *other); data->t.data.parent_name.t.size = sizeof(data->t.data.parent_name.t.name); size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_name), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; data->t.data.parent_qualified_name.t.size = sizeof(data->t.data.parent_qualified_name.t.name); size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_qualified_name), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; data->t.data.outside_info.t.size = sizeof(data->t.data.outside_info.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.outside_info), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; return true; } static bool reverse_copy_ticket_out(TPMT_TK_CREATION *ticket, void **other) { u16 size; if (ticket == NULL) return false; reverse_copy_out(ticket->tag, *other); reverse_copy_out(ticket->hierarchy, *other); ticket->digest.t.size = sizeof(ticket->digest.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(ticket->digest), (TPM2B *)*other); if ( size == 0 ) return false; *other += size; return true; } static void reverse_copy_context_in(void **other, TPMS_CONTEXT *context) { if (context == NULL) return; reverse_copy_in(*other, context->sequence); reverse_copy_in(*other, context->savedHandle); reverse_copy_in(*other, context->hierarchy); *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&context->contextBlob); } static bool reverse_copy_context_out(TPMS_CONTEXT *context, void **other) { u16 size; if (context == NULL) return false; reverse_copy_out(context->sequence, *other); reverse_copy_out(context->savedHandle, *other); reverse_copy_out(context->hierarchy, *other); context->contextBlob.t.size = sizeof(context->contextBlob.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&context->contextBlob, (TPM2B *)*other); if ( size == 0 ) return false; *other += size; return true; } static uint32_t _tpm20_pcr_read(u32 locality, tpm_pcr_read_in *in, tpm_pcr_read_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_PCR_Read, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_pcr_selection_in(&other, &in->pcr_selection); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); /* Skip past parameter size field */ reverse_copy_out(out->pcr_update_counter, other); if ( !reverse_copy_pcr_selection_out(&out->pcr_selection, &other) ) return TPM_RC_FAILURE; if ( !reverse_copy_digest_out(&out->pcr_values, &other) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_pcr_extend(uint32_t locality, tpm_pcr_extend_in *in, tpm_pcr_extend_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_PCR_Extend, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->pcr_handle); reverse_copy_sessions_in(&other, &in->sessions); reverse_copy_digest_value_in(&other, &in->digests); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_pcr_event(uint32_t locality, tpm_pcr_event_in *in, tpm_pcr_event_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_PCR_Event, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->pcr_handle); reverse_copy_sessions_in(&other, &in->sessions); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data)); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); if ( !reverse_copy_digest_values_out(&out->digests, &other) ) return TPM_RC_FAILURE; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_pcr_reset(uint32_t locality, tpm_pcr_reset_in *in, tpm_pcr_reset_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_PCR_Reset, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy(other, &in->pcr_handle, sizeof(u32)); other += sizeof(u32); reverse_copy_sessions_in(&other, &in->sessions); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_sequence_start(uint32_t locality, tpm_sequence_start_in *in, tpm_sequence_start_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_HashSequenceStart, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->auth)); reverse_copy_in(other, in->hash_alg); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = RSP_HEAD_SIZE + sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); reverse_copy_out(out->handle, other); return ret; } static uint32_t _tpm20_sequence_update(uint32_t locality, tpm_sequence_update_in *in, tpm_sequence_update_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_SequenceUpdate, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->handle); reverse_copy_sessions_in(&other, &in->sessions); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf)); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_sequence_complete(uint32_t locality, tpm_sequence_complete_in *in, tpm_sequence_complete_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_EventSequenceComplete, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->pcr_handle); reverse_copy_in(other, in->seq_handle); reverse_copy_sessions_in(&other, &in->sessions); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf)); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); if ( !reverse_copy_digest_values_out(&out->results, &other) ) return TPM_RC_FAILURE; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_nv_read(uint32_t locality, tpm_nv_read_in *in, tpm_nv_read_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; u16 size; reverse_copy_header(TPM_CC_NV_Read, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->handle); reverse_copy_in(other, in->index); reverse_copy_sessions_in(&other, &in->sessions); reverse_copy_in(other, in->size); reverse_copy_in(other, in->offset); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(rsp_buf); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); out->data.t.size = sizeof(out->data.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_nv_write(uint32_t locality, tpm_nv_write_in *in, tpm_nv_write_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_NV_Write, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->handle); reverse_copy_in(other, in->index); reverse_copy_sessions_in(&other, &in->sessions); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data)); reverse_copy_in(other, in->offset); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_nv_read_public(uint32_t locality, tpm_nv_read_public_in *in, tpm_nv_read_public_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; u16 size; reverse_copy_header(TPM_CC_NV_ReadPublic, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->index); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); reverse_copy_out(out->nv_public.t.size, other); reverse_copy_out(out->nv_public.t.nv_public.index, other); reverse_copy_out(out->nv_public.t.nv_public.name_alg, other); reverse_copy((void *)&(out->nv_public.t.nv_public.attr), other, sizeof(u32)); other += sizeof(u32); out->nv_public.t.nv_public.auth_policy.t.size = sizeof(out->nv_public.t.nv_public.auth_policy.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->nv_public.t.nv_public.auth_policy), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; reverse_copy_out(out->nv_public.t.nv_public.data_size, other); out->nv_name.t.size = sizeof(out->nv_name.t.name); size = reverse_copy_sized_buf_out((TPM2B *)&(out->nv_name), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; return ret; } static uint32_t _tpm20_get_random(uint32_t locality, tpm_get_random_in *in, tpm_get_random_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; u16 size; reverse_copy_header(TPM_CC_GetRandom, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->bytes_req); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); out->random_bytes.t.size = sizeof(out->random_bytes.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->random_bytes), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; return ret; } static uint32_t _tpm20_shutdown(uint32_t locality, u16 type) { u32 ret; u32 cmd_size, rsp_size; void *other; reverse_copy_header(TPM_CC_Shutdown, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, type); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = RSP_HEAD_SIZE; if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); return ret; } __data u32 handle2048 = 0; static const char auth_str[] = "test"; static uint32_t _tpm20_create_primary(uint32_t locality, tpm_create_primary_in *in, tpm_create_primary_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; u16 sensitive_size; void *sensitive_size_ptr; void *other; u16 size; reverse_copy_header(TPM_CC_CreatePrimary, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->primary_handle); reverse_copy_sessions_in(&other, &in->sessions); /* Copy inSensitive */ sensitive_size_ptr = other; other += sizeof(u16); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->sensitive.t.sensitive.user_auth)); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->sensitive.t.sensitive.data)); sensitive_size = (u8 *)other - (u8 *)sensitive_size_ptr - sizeof(u16); reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(u16)); /* Copy inPublic */ reverse_copy_public_in(&other, &in->public); /* Copy outsideInfo */ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->outside_info)); /* Copy creationPCR */ reverse_copy_pcr_selection_in(&other, &in->creation_pcr); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; /* Save objHandle */ reverse_copy_out(out->obj_handle, other); reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); /* Save outPublic */ if ( !reverse_copy_public_out(&out->public, &other) ) return TPM_RC_FAILURE; /* Save creationData */ if ( !reverse_copy_creation_data_out(&(out->creation_data), &other) ) return TPM_RC_FAILURE; /* Save creationHash */ out->creation_hash.t.size = sizeof(out->creation_hash.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; /* Save creationTicket */ if ( !reverse_copy_ticket_out(&(out->creation_ticket), &other) ) return TPM_RC_FAILURE; out->name.t.size = sizeof(out->name.t.name); size = reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_create(uint32_t locality, tpm_create_in *in, tpm_create_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; u16 sensitive_size; void *sensitive_size_ptr; void *other; u16 size; reverse_copy_header(TPM_CC_Create, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->parent_handle); reverse_copy_sessions_in(&other, &in->sessions); /* Copy inSensitive */ sensitive_size_ptr = other; other += sizeof(u16); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->sensitive.t.sensitive.user_auth)); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->sensitive.t.sensitive.data)); sensitive_size = (u8 *)other - (u8 *)sensitive_size_ptr - sizeof(u16); reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(u16)); /* Copy inPublic */ reverse_copy_public_in(&other, &in->public); /* Copy outsideInfo */ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->outside_info)); /* Copy creationPCR */ reverse_copy_pcr_selection_in(&other, &in->creation_pcr); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(rsp_buf); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); /* Save outPrivate */ out->private.t.size = sizeof(out->private.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->private), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; /* Save outPublic */ if ( !reverse_copy_public_out(&out->public, &other) ) return TPM_RC_FAILURE; /* Save creationData */ if ( !reverse_copy_creation_data_out(&(out->creation_data), &other) ) return TPM_RC_FAILURE; /* Save creationHash */ out->creation_hash.t.size = sizeof(out->creation_hash.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; /* Save creationTicket */ if ( !reverse_copy_ticket_out(&(out->creation_ticket), &other) ) return TPM_RC_FAILURE; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_load(uint32_t locality, tpm_load_in *in, tpm_load_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; u16 size; reverse_copy_header(TPM_CC_Load, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->parent_handle); reverse_copy_sessions_in(&other, &in->sessions); other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->private)); reverse_copy_public_in(&other, &in->public); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy_out(out->obj_handle, other); reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); out->name.t.size = sizeof(out->name.t.name); size = reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_unseal(uint32_t locality, tpm_unseal_in *in, tpm_unseal_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; u16 size; reverse_copy_header(TPM_CC_Unseal, &in->sessions); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->item_handle); reverse_copy_sessions_in(&other, &in->sessions); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); out->data.t.size = sizeof(out->data.t.buffer); size = reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); if ( size == 0 ) return TPM_RC_FAILURE; other += size; if ( !reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_context_save(uint32_t locality, tpm_contextsave_in *in, tpm_contextsave_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_ContextSave, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->saveHandle); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); /* Skip past parameter size field */ if ( !reverse_copy_context_out(&out->context, &other) ) return TPM_RC_FAILURE; return ret; } static uint32_t _tpm20_context_load(uint32_t locality, tpm_contextload_in *in, tpm_contextload_out *out) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_ContextLoad, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_context_in(&other, &in->context); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = RSP_HEAD_SIZE + sizeof(*out); if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); /* Skip past parameter size field */ reverse_copy_out(out->loadedHandle, other); return ret; } static uint32_t _tpm20_context_flush(uint32_t locality, tpm_flushcontext_in *in) { u32 ret; u32 cmd_size, rsp_size; u16 rsp_tag; void *other; reverse_copy_header(TPM_CC_FlushContext, 0); other = (void *)cmd_buf + CMD_HEAD_SIZE; reverse_copy_in(other, in->flushHandle); /* Now set the command size field, now that we know the size of the whole command */ cmd_size = (u8 *)other - cmd_buf; reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size)); rsp_size = RSP_HEAD_SIZE; if (g_tpm_family == TPM_IF_20_FIFO) { if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } if (g_tpm_family == TPM_IF_20_CRB) { if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size)) return TPM_RC_FAILURE; } reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret)); if ( ret != TPM_RC_SUCCESS ) return ret; other = (void *)rsp_buf + RSP_HEAD_SIZE; reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag)); if (rsp_tag == TPM_ST_SESSIONS) other += sizeof(u32); return ret; } TPM_CMD_SESSION_DATA_IN pw_session; static void create_pw_session(TPM_CMD_SESSION_DATA_IN *ses) { ses->session_handle = TPM_RS_PW; ses->nonce.t.size = 0; *((u8 *)((void *)&ses->session_attr)) = 0; ses->hmac.t.size = 0; } #define SET_PCR_SELECT_BIT( pcr_selection, pcr ) \ (pcr_selection).pcr_select[( (pcr)/8 )] |= ( 1 << ( (pcr) % 8) ); static bool tpm20_pcr_read(struct tpm_if *ti, uint32_t locality, uint32_t pcr, tpm_pcr_value_t *out) { tpm_pcr_read_in read_in; tpm_pcr_read_out read_out; u32 ret; if ( ti == NULL || out == NULL ) return false; read_in.pcr_selection.count = 1; read_in.pcr_selection.selections[0].hash = ti->cur_alg; read_in.pcr_selection.selections[0].size_of_select = 3; read_in.pcr_selection.selections[0].pcr_select[0] = 0; read_in.pcr_selection.selections[0].pcr_select[1] = 0; read_in.pcr_selection.selections[0].pcr_select[2] = 0; SET_PCR_SELECT_BIT( read_in.pcr_selection.selections[0], pcr ); ret = _tpm20_pcr_read(locality, &read_in, &read_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: Pcr %d Read return value = %08X\n", pcr, ret); ti->error = ret; return false; } copy_hash(out, (tb_hash_t *)&(read_out.pcr_values.digests[0].t.buffer[0]), ti->cur_alg); return true; } static bool tpm20_pcr_extend(struct tpm_if *ti, uint32_t locality, uint32_t pcr, const hash_list_t *in) { tpm_pcr_extend_in extend_in; tpm_pcr_extend_out extend_out; u32 ret, i; if ( ti == NULL || in == NULL ) return false; extend_in.pcr_handle = pcr; extend_in.sessions.num_sessions = 1; extend_in.sessions.sessions[0] = pw_session; extend_in.digests.count = in->count; for (i=0; icount; i++) { extend_in.digests.digests[i].hash_alg = in->entries[i].alg; copy_hash((tb_hash_t *)&extend_in.digests.digests[i].digest, &in->entries[i].hash, in->entries[i].alg); } ret = _tpm20_pcr_extend(locality, &extend_in, &extend_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: Pcr %d extend, return value = %08X\n", pcr, ret); ti->error = ret; return false; } return true; } static bool tpm20_pcr_reset(struct tpm_if *ti, uint32_t locality, uint32_t pcr) { tpm_pcr_reset_in reset_in; tpm_pcr_reset_out reset_out; u32 ret; reset_in.pcr_handle = pcr; reset_in.sessions.num_sessions = 1; reset_in.sessions.sessions[0] = pw_session; ret = _tpm20_pcr_reset(locality, &reset_in, &reset_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: Pcr %d Reset return value = %08X\n", pcr, ret); ti->error = ret; return false; } return true; } static bool tpm20_hash(struct tpm_if *ti, u32 locality, const u8 *data, u32 data_size, hash_list_t *hl) { tpm_sequence_start_in start_in; tpm_sequence_start_out start_out; tpm_sequence_update_in update_in; tpm_sequence_update_out update_out; tpm_sequence_complete_in complete_in; tpm_sequence_complete_out complete_out; TPM2B_MAX_BUFFER buffer; u32 ret, i, j, chunk_size; if ( ti == NULL || data == NULL ) return false; start_in.auth.t.size = 2; start_in.auth.t.buffer[0] = 0; start_in.auth.t.buffer[1] = 0xff; start_in.hash_alg = TPM_ALG_NULL; ret = _tpm20_sequence_start(locality, &start_in, &start_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: HashSequenceStart return value = %08X\n", ret); ti->error = ret; return false; } update_in.sessions.num_sessions = 1; update_in.sessions.sessions[0] = pw_session; update_in.sessions.sessions[0].hmac = start_in.auth; update_in.handle = start_out.handle; complete_in.pcr_handle = TPM_RH_NULL; complete_in.seq_handle = start_out.handle; complete_in.sessions.num_sessions = 2; create_pw_session(&complete_in.sessions.sessions[0]); complete_in.sessions.sessions[1] = pw_session; complete_in.sessions.sessions[1].hmac = start_in.auth; for( i=0; i MAX_DIGEST_BUFFER ) { chunk_size = MAX_DIGEST_BUFFER; } else { chunk_size = data_size - i; } buffer.t.size = chunk_size; tb_memcpy( &(buffer.t.buffer[0]), &(data[i] ), chunk_size ); update_in.buf = buffer; ret = _tpm20_sequence_update(locality, &update_in, &update_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: SequenceUpdate return value = %08X\n", ret); ti->error = ret; return false; } } buffer.t.size = 0; complete_in.buf = buffer; ret = _tpm20_sequence_complete(locality, &complete_in, &complete_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: EventSequenceComplete return value = %08X\n", ret); ti->error = ret; return false; } hl->count = complete_out.results.count; if ( hl->count > MAX_ALG_NUM ) { printk(TBOOT_WARN"TPM: EventSequenceComplete return %d digests," " keep first %d\n", hl->count, MAX_ALG_NUM); hl->count = MAX_ALG_NUM; } for ( j=0; jcount; j++ ) { hl->entries[j].alg = complete_out.results.digests[j].hash_alg; tb_memcpy(&hl->entries[j].hash, &complete_out.results.digests[j].digest, sizeof(hl->entries[j].hash)); } return true; } static bool tpm20_nv_read(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, uint8_t *data, uint32_t *data_size) { tpm_nv_read_in read_in; tpm_nv_read_out read_out; u32 ret; if ( ti == NULL || data_size == NULL || *data_size == 0 ) return false; if ( *data_size > MAX_NV_INDEX_SIZE ) *data_size = MAX_NV_INDEX_SIZE; read_in.handle = index; read_in.index = index; read_in.sessions.num_sessions = 1; read_in.sessions.sessions[0] = pw_session; read_in.offset = offset; read_in.size = *data_size; ret = _tpm20_nv_read(locality, &read_in, &read_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: read NV index %08x from offset %08x, return value = %08X\n", index, offset, ret); ti->error = ret; return false; } if (read_out.data.t.size == 0 || read_out.data.t.size > *data_size) { printk(TBOOT_WARN"TPM: data_size %x too large for buffer\n", read_out.data.t.size); ti->error = TPM_RC_NV_SIZE; return false; } *data_size = read_out.data.t.size; tb_memcpy(data, &read_out.data.t.buffer[0], *data_size); return true; } static bool tpm20_nv_write(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t offset, const uint8_t *data, uint32_t data_size) { tpm_nv_write_in write_in; tpm_nv_write_out write_out; u32 ret; if ( ti == NULL || data == NULL || data_size == 0 || data_size > MAX_NV_INDEX_SIZE ) return false; write_in.handle = index; write_in.index = index; write_in.sessions.num_sessions = 1; write_in.sessions.sessions[0] = pw_session; write_in.offset = offset; write_in.data.t.size = data_size; tb_memcpy(&write_in.data.t.buffer[0], data, data_size); ret = _tpm20_nv_write(locality, &write_in, &write_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: write NV %08x, offset %08x, %08x bytes, return value = %08X\n", index, offset, data_size, ret); ti->error = ret; return false; } return true; } static bool tpm20_get_nvindex_size(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *size) { tpm_nv_read_public_in public_in; tpm_nv_read_public_out public_out; u32 ret; if ( ti == NULL || size == NULL ) return false; public_in.index = index; ret = _tpm20_nv_read_public(locality, &public_in, &public_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: fail to get public data of 0x%08X in TPM NV\n", index); ti->error = ret; return false; } if (index != public_out.nv_public.t.nv_public.index) { printk(TBOOT_WARN"TPM: Index 0x%08X is not the one expected 0x%08X\n", index, index); ti->error = TPM_RC_FAILURE; return false; } *size = public_out.nv_public.t.nv_public.data_size; return true; } static bool tpm20_get_nvindex_permission(struct tpm_if *ti, uint32_t locality, uint32_t index, uint32_t *attribute) { tpm_nv_read_public_in public_in; tpm_nv_read_public_out public_out; u32 ret; if ( ti == NULL || locality >= TPM_NR_LOCALITIES || index == 0 || attribute == NULL ) return false; public_in.index = index; ret = _tpm20_nv_read_public(locality, &public_in, &public_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: fail to get public data of 0x%08X in TPM NV\n", index); ti->error = ret; return false; } if (index != public_out.nv_public.t.nv_public.index) { printk(TBOOT_WARN"TPM: Index 0x%08X is not the one expected 0x%08X\n", index, index); ti->error = TPM_RC_FAILURE; return false; } *attribute = *(uint32_t*)(&public_out.nv_public.t.nv_public.attr); return true; } static bool tpm20_seal(struct tpm_if *ti, uint32_t locality, uint32_t in_data_size, const uint8_t *in_data, uint32_t *sealed_data_size, uint8_t *sealed_data) { tpm_create_in create_in; tpm_create_out create_out; u32 ret; create_in.parent_handle = handle2048; create_in.sessions.num_sessions = 1; create_in.sessions.sessions[0] = pw_session; create_in.sessions.sessions[0].hmac.t.size = 2; create_in.sessions.sessions[0].hmac.t.buffer[0] = 0x00; create_in.sessions.sessions[0].hmac.t.buffer[1] = 0xff; create_in.public.t.public_area.type = TPM_ALG_KEYEDHASH; create_in.public.t.public_area.name_alg = ti->cur_alg; create_in.public.t.public_area.auth_policy.t.size = 0; *(u32 *)&create_in.public.t.public_area.object_attr = 0; create_in.public.t.public_area.object_attr.userWithAuth = 1; create_in.public.t.public_area.object_attr.noDA = 1; create_in.public.t.public_area.param.keyed_hash.scheme.scheme = TPM_ALG_NULL; create_in.public.t.public_area.unique.keyed_hash.t.size = 0; COMPILE_TIME_ASSERT( sizeof(auth_str) - 1 <= sizeof(create_in.sensitive.t.sensitive.user_auth.t.buffer) ); create_in.sensitive.t.sensitive.user_auth.t.size = sizeof(auth_str) - 1; tb_memcpy(&(create_in.sensitive.t.sensitive.user_auth.t.buffer[0]), auth_str, sizeof(auth_str)-1); if ( in_data_size > sizeof(create_in.sensitive.t.sensitive.data.t.buffer) ) { printk(TBOOT_WARN"TPM: input data size to seal is too large:" " %08X(%08x)\n", in_data_size, sizeof(create_in.sensitive.t.sensitive.data.t.buffer)); return false; } create_in.sensitive.t.sensitive.data.t.size = in_data_size; tb_memcpy(&(create_in.sensitive.t.sensitive.data.t.buffer[0]), in_data, in_data_size); create_in.outside_info.t.size = 0; create_in.creation_pcr.count = 0; tb_memset(&create_out, 0, sizeof(create_out)); ret = _tpm20_create(locality, &create_in, &create_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: Create return value = %08X\n", ret); ti->error = ret; return false; } *sealed_data_size = sizeof(create_out); tb_memcpy(sealed_data, &create_out, *sealed_data_size); return true; } static bool tpm20_unseal(struct tpm_if *ti, uint32_t locality, uint32_t sealed_data_size, const uint8_t *sealed_data, uint32_t *secret_size, uint8_t *secret) { tpm_load_in load_in; tpm_load_out load_out; tpm_unseal_in unseal_in; tpm_unseal_out unseal_out; u32 ret; if ( ti == NULL || locality >= TPM_NR_LOCALITIES || sealed_data_size == 0 || sealed_data == NULL ) return false; /* For TPM 2.0, the object will need to be loaded before it may be used.*/ load_in.parent_handle = handle2048; load_in.sessions.num_sessions = 1; load_in.sessions.sessions[0] = pw_session; load_in.sessions.sessions[0].hmac.t.size = 2; load_in.sessions.sessions[0].hmac.t.buffer[0] = 0x00; load_in.sessions.sessions[0].hmac.t.buffer[1] = 0xff; load_in.private = ((tpm_create_out *)sealed_data)->private; load_in.public = ((tpm_create_out *)sealed_data)->public; ret = _tpm20_load(locality, &load_in, &load_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: Load return value = %08X\n", ret); ti->error = ret; return false; } unseal_in.sessions.num_sessions = 1; unseal_in.sessions.sessions[0] = pw_session; unseal_in.sessions.sessions[0].hmac.t.size = sizeof(auth_str) - 1; tb_memcpy(&(unseal_in.sessions.sessions[0].hmac.t.buffer[0]), auth_str, sizeof(auth_str)-1); unseal_in.item_handle = load_out.obj_handle; ret = _tpm20_unseal(locality, &unseal_in, &unseal_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: Unseal return value = %08X\n", ret); ti->error = ret; return false; } *secret_size = unseal_out.data.t.size; tb_memcpy(secret, &(unseal_out.data.t.buffer[0]), *secret_size); return true; } static bool tpm20_verify_creation(struct tpm_if *ti, uint32_t sealed_data_size, uint8_t *sealed_data) { if ( ti == NULL || sealed_data_size == 0 || sealed_data == NULL ) return false; return true; } static bool tpm20_get_random(struct tpm_if *ti, uint32_t locality, uint8_t *random_data, uint32_t *data_size) { tpm_get_random_in random_in; tpm_get_random_out random_out; u32 ret, out_size, requested_size; static bool first_attempt; if ( random_data == NULL || data_size == NULL || *data_size == 0 ) return false; first_attempt = true; requested_size = *data_size; random_in.bytes_req = *data_size; ret = _tpm20_get_random(locality, &random_in, &random_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: get random 0x%x bytes, return value = %08X\n", *data_size, ret); ti->error = ret; return false; } out_size = random_out.random_bytes.t.size; if (out_size > 0) tb_memcpy(random_data, &(random_out.random_bytes.t.buffer[0]), out_size); *data_size = out_size; /* if TPM doesn't return all requested random bytes, try one more time */ if ( out_size < requested_size ) { printk(TBOOT_WARN"requested 0x%x random bytes but only got 0x%x\n", requested_size, out_size); /* we're only going to try twice */ if ( first_attempt ) { first_attempt = false; uint32_t second_size = requested_size - out_size; printk(TBOOT_WARN"trying one more time to get remaining 0x%x bytes\n", second_size); random_in.bytes_req = second_size; ret = _tpm20_get_random(locality, &random_in, &random_out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: get random 0x%x bytes, return value = %08X\n", *data_size, ret); ti->error = ret; return false; } out_size = random_out.random_bytes.t.size; if (out_size > 0) tb_memcpy(random_data+*data_size, &(random_out.random_bytes.t.buffer[0]), out_size); *data_size += out_size; } } return true; } static uint32_t tpm20_save_state(struct tpm_if *ti, uint32_t locality) { u32 ret; if ( ti == NULL ) return false; ret = _tpm20_shutdown(locality, TPM_SU_STATE); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: Shutdown, return value = %08X\n", ret); ti->error = ret; } return ret; } #define TPM_NR_PCRS 24 #define TPM_PCR_RESETABLE_MIN 16 static bool tpm20_cap_pcrs(struct tpm_if *ti, u32 locality, int pcr) { bool was_capped[TPM_NR_PCRS] = {false}; hash_list_t cap_val; /* use whatever val is on stack */ if ( ti == NULL || locality >= TPM_NR_LOCALITIES || pcr == 0 ) return false; cap_val.count = ti->banks; for (unsigned int i=0; ibanks; i++) cap_val.entries[i].alg = ti->algs_banks[i]; if (pcr >= 0) { tpm20_pcr_extend(ti, locality, pcr, &cap_val); return true; } /* ensure PCRs 17 + 18 are always capped */ tpm20_pcr_extend(ti, locality, 17, &cap_val); tpm20_pcr_extend(ti, locality, 18, &cap_val); was_capped[17] = was_capped[18] = true; /* also cap every dynamic PCR we extended (only once) */ /* don't cap static PCRs since then they would be wrong after S3 resume */ tb_memset(&was_capped, true, TPM_PCR_RESETABLE_MIN*sizeof(bool)); for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { if ( !was_capped[g_pre_k_s3_state.vl_entries[i].pcr] ) { tpm20_pcr_extend(ti, locality, g_pre_k_s3_state.vl_entries[i].pcr, &cap_val); was_capped[g_pre_k_s3_state.vl_entries[i].pcr] = true; } } printk(TBOOT_INFO"cap'ed dynamic PCRs\n"); return true; } static bool alg_is_supported(u16 alg) { for (int i = 0; i < tboot_alg_list_count; i++) { if (alg == tboot_alg_list[i]) return true; } return false; } __data tpm_contextsave_out tpm2_context_saved; static bool tpm20_context_save(struct tpm_if *ti, u32 locality, TPM_HANDLE handle, void *context_saved) { tpm_contextsave_in in; tpm_contextsave_out out; u32 ret; if ( ti == NULL || locality >= TPM_NR_LOCALITIES ){ return false; } if ( handle == 0 ) return false; in.saveHandle = handle; ret =_tpm20_context_save(locality, &in, &out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: tpm2 context save failed, return value = %08X\n", ret); ti->error = ret; return false; } else printk(TBOOT_WARN"TPM: tpm2 context save successful, return value = %08X\n", ret); tb_memcpy((tpm_contextsave_out *)context_saved, &out, sizeof(tpm_contextsave_out)); return true; } static bool tpm20_context_load(struct tpm_if *ti, u32 locality, void *context_saved, TPM_HANDLE *handle) { tpm_contextload_in in; tpm_contextload_out out; u32 ret; if ( ti == NULL || locality >= TPM_NR_LOCALITIES ) return false; tb_memcpy(&in, (tpm_contextsave_out *)context_saved, sizeof(tpm_contextsave_out)); ret = _tpm20_context_load(locality, &in, &out); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: tpm2 context load failed, return value = %08X\n", ret); ti->error = ret; return false; } else printk(TBOOT_WARN"TPM: tpm2 context load successful, return value = %08X\n", ret); *handle = out.loadedHandle; return true; } static bool tpm20_context_flush(struct tpm_if *ti, u32 locality, TPM_HANDLE handle) { tpm_flushcontext_in in; u32 ret; if ( ti == NULL || locality >= TPM_NR_LOCALITIES ) return false; if ( handle == 0 ) return false; in.flushHandle = handle; ret = _tpm20_context_flush(locality, &in); if ( ret != TPM_RC_SUCCESS ) { printk(TBOOT_WARN"TPM: tpm2 context flush returned , return value = %08X\n", ret); ti->error = ret; return false; } else printk(TBOOT_WARN"TPM: tpm2 context flush successful, return value = %08X\n", ret); return true; } static bool tpm20_init(struct tpm_if *ti) { u32 ret; unsigned int i; tpm_info_list_t *info_list = get_tpm_info_list(g_sinit); if ( ti == NULL || info_list == NULL ) return false; if (!txt_is_launched()) ti->cur_loc = 0; else ti->cur_loc = 2; /* init version */ ti->major = TPM20_VER_MAJOR; ti->minor = TPM20_VER_MINOR; /* init timeouts value */ ti->timeout.timeout_a = TIMEOUT_A; ti->timeout.timeout_b = TIMEOUT_B; ti->timeout.timeout_c = TIMEOUT_C; ti->timeout.timeout_d = TIMEOUT_D; /* get pcr extend policy from cmdline */ get_tboot_extpol(); if (info_list->capabilities.tpm_nv_index_set == 0){ /* init NV index */ ti->tb_policy_index = 0x1200001; ti->lcp_own_index = 0x1400001; ti->tb_err_index = 0x1200002; ti->sgx_svn_index = 0x01800004; } else { ti->tb_policy_index = 0x01c10131; ti->lcp_own_index = 0x01c10106; ti->tb_err_index = 0x01c10132; ti->sgx_svn_index = 0x01c10104; } /* create one common password sesson*/ create_pw_session(&pw_session); /* init supported alg list for banks */ tpm_pcr_event_in event_in; tpm_pcr_event_out event_out; event_in.pcr_handle = 16; event_in.sessions.num_sessions = 1; event_in.sessions.sessions[0] = pw_session; event_in.data.t.size = 4; event_in.data.t.buffer[0] = 0; event_in.data.t.buffer[1] = 0xff; event_in.data.t.buffer[2] = 0x55; event_in.data.t.buffer[3] = 0xaa; ret = _tpm20_pcr_event(ti->cur_loc, &event_in, &event_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: PcrEvent not successful, return value = %08X\n", ret); ti->error = ret; return false; } ti->banks = event_out.digests.count; printk(TBOOT_INFO"TPM: supported bank count = %d\n", ti->banks); for (i=0; ibanks; i++) { ti->algs_banks[i] = event_out.digests.digests[i].hash_alg;; printk(TBOOT_INFO"TPM: bank alg = %08x\n", ti->algs_banks[i]); } /* init supported alg list */ ti->alg_count = 0; for (i=0; ibanks; i++) { if (alg_is_supported(ti->algs_banks[i])) { ti->algs[ti->alg_count] = ti->algs_banks[i]; ti->alg_count++; } } printk(TBOOT_INFO"tboot: supported alg count = %d\n", ti->alg_count); for (unsigned int i=0; ialg_count; i++) printk(TBOOT_INFO"tboot: hash alg = %08X\n", ti->algs[i]); /* reset debug PCR 16 */ if (!tpm20_pcr_reset(ti, ti->cur_loc, 16)){ printk(TBOOT_WARN"TPM: tpm20_pcr_reset failed...\n"); return false; } if (handle2048 != 0) goto out; /* create primary object as parent obj for seal */ tpm_create_primary_in primary_in; tpm_create_primary_out primary_out; primary_in.primary_handle = TPM_RH_NULL; primary_in.sessions.num_sessions = 1; primary_in.sessions.sessions[0].session_handle = TPM_RS_PW; primary_in.sessions.sessions[0].nonce.t.size = 0; primary_in.sessions.sessions[0].hmac.t.size = 0; *((u8 *)((void *)&primary_in.sessions.sessions[0].session_attr)) = 0; primary_in.sensitive.t.sensitive.user_auth.t.size = 2; primary_in.sensitive.t.sensitive.user_auth.t.buffer[0] = 0x00; primary_in.sensitive.t.sensitive.user_auth.t.buffer[1] = 0xff; primary_in.sensitive.t.sensitive.data.t.size = 0; primary_in.public.t.public_area.type = TPM_ALG_RSA; primary_in.public.t.public_area.name_alg = ti->cur_alg; *(u32 *)&primary_in.public.t.public_area.object_attr = 0; primary_in.public.t.public_area.object_attr.restricted = 1; primary_in.public.t.public_area.object_attr.userWithAuth = 1; primary_in.public.t.public_area.object_attr.decrypt = 1; primary_in.public.t.public_area.object_attr.fixedTPM = 1; primary_in.public.t.public_area.object_attr.fixedParent = 1; primary_in.public.t.public_area.object_attr.noDA = 1; primary_in.public.t.public_area.object_attr.sensitiveDataOrigin = 1; primary_in.public.t.public_area.auth_policy.t.size = 0; primary_in.public.t.public_area.param.rsa.symmetric.alg = TPM_ALG_AES; primary_in.public.t.public_area.param.rsa.symmetric.key_bits.aes= 128; primary_in.public.t.public_area.param.rsa.symmetric.mode.aes = TPM_ALG_CFB; primary_in.public.t.public_area.param.rsa.scheme.scheme = TPM_ALG_NULL; primary_in.public.t.public_area.param.rsa.key_bits = 2048; primary_in.public.t.public_area.param.rsa.exponent = 0; primary_in.public.t.public_area.unique.keyed_hash.t.size = 0; primary_in.outside_info.t.size = 0; primary_in.creation_pcr.count = 0; printk(TBOOT_DETA"TPM:CreatePrimary creating hierarchy handle = %08X\n", primary_in.primary_handle); ret = _tpm20_create_primary(ti->cur_loc, &primary_in, &primary_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: CreatePrimary return value = %08X\n", ret); ti->error = ret; return false; } handle2048 = primary_out.obj_handle; printk(TBOOT_DETA"TPM:CreatePrimary created object handle = %08X\n", handle2048); out: tpm_print(ti); return true; } const struct tpm_if_fp tpm_20_if_fp = { .init = tpm20_init, .pcr_read = tpm20_pcr_read, .pcr_extend = tpm20_pcr_extend, .hash = tpm20_hash, .pcr_reset = tpm20_pcr_reset, .nv_read = tpm20_nv_read, .nv_write = tpm20_nv_write, .get_nvindex_size = tpm20_get_nvindex_size, .get_nvindex_permission = tpm20_get_nvindex_permission, .seal = tpm20_seal, .unseal = tpm20_unseal, .verify_creation = tpm20_verify_creation, .get_random = tpm20_get_random, .save_state = tpm20_save_state, .cap_pcrs = tpm20_cap_pcrs, .context_save = tpm20_context_save, .context_load = tpm20_context_load, .context_flush = tpm20_context_flush, }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/vga.c0000644000000000000000000001631114210363175014417 0ustar 00000000000000/* * vga.c: fns for outputting strings to VGA display * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #define SSFN_CONSOLEBITMAP_TRUECOLOR #include #include static uint16_t * const legacy_screen = (uint16_t * const)VGA_BASE; static __data uint8_t cursor_x, cursor_y; static __data unsigned int num_lines; uint8_t g_vga_delay = 0; /* default to no delay */ static struct mb2_fb g_fb; static uint32_t __data fb_buff1[FB_SIZE]; static uint32_t __data fb_buff2[FB_SIZE]; typedef enum { VGA_NONE = 0, VGA_LEGACY, VGA_FB, } vga_type_t; vga_type_t vga_type; static inline void legacy_reset_screen(void) { tb_memset(legacy_screen, 0, SCREEN_BUFFER); cursor_x = 0; cursor_y = 0; num_lines = 0; outb(CTL_ADDR_REG, START_ADD_HIGH_REG); outb(CTL_DATA_REG, 0x00); outb(CTL_ADDR_REG, START_ADD_LOW_REG); outb(CTL_DATA_REG, 0x00); } static void legacy_scroll_screen(void) { for ( int y = 1; y < MAX_LINES; y++ ) { for ( int x = 0; x < MAX_COLS; x++ ) writew(VGA_ADDR(x, y-1), readw(VGA_ADDR(x, y))); } /* clear last line */ for ( int x = 0; x < MAX_COLS; x++ ) writew(VGA_ADDR(x, MAX_LINES-1), 0x720); } static void legacy_putc(int c) { bool new_row = false; switch ( c ) { case '\n': cursor_y++; cursor_x = 0; new_row = true; break; case '\r': cursor_x = 0; break; case '\t': cursor_x += 4; break; default: legacy_screen[(cursor_y * MAX_COLS) + cursor_x] = (COLOR << 8) | c; cursor_x++; break; } if ( cursor_x >= MAX_COLS ) { cursor_x %= MAX_COLS; cursor_y++; new_row = true; } if ( new_row ) { num_lines++; if ( cursor_y >= MAX_LINES ) { legacy_scroll_screen(); cursor_y--; } /* (optionally) pause after every screenful */ if ( (num_lines % (MAX_LINES - 1)) == 0 && g_vga_delay > 0 ) delay(g_vga_delay * 1000); } } static void fb_putc(int c) { bool new_row = false; switch ( c ) { case '\n': ssfn_dst.y += ssfn_src->height; ssfn_dst.x = 0; new_row = true; break; case '\r': ssfn_dst.x = 0; break; case '\t': ssfn_dst.x += 4 * ssfn_src->width; break; default: ssfn_putc(c); break; } if ( new_row ) { num_lines++; const uint32_t h = g_fb.common.fb_height; const uint32_t w = g_fb.common.fb_width; const uint32_t fh = ssfn_src->height; if ((uint32_t)ssfn_dst.y >= h - fh) { tb_memcpy(fb_buff1, &fb_buff1[w*fh], (w*h-w*fh)*sizeof(uint32_t)); tb_memset(&fb_buff1[(w*h-w*fh)], 0, w*fh*sizeof(uint32_t)); ssfn_dst.y -= fh; } for (uint32_t i = 0; i < h*w; ++i) { if (fb_buff1[i] != fb_buff2[i]) { ((volatile uint32_t*)((uint32_t)g_fb.common.fb_addr))[i] = fb_buff1[i]; fb_buff2[i] = fb_buff1[i]; } } /* (optionally) pause after every screenful */ uint32_t lines_in_screen = h / fh; if ( (num_lines % (lines_in_screen - 1)) == 0 && g_vga_delay > 0 ) { delay(g_vga_delay * 1000); } } } static void fb_init(void) { printk(TBOOT_INFO"Framebuffer info:\n"); printk(TBOOT_INFO" address: 0x%llx\n", g_fb.common.fb_addr); printk(TBOOT_INFO" pitch: %d\n", g_fb.common.fb_pitch); printk(TBOOT_INFO" width: %d\n", g_fb.common.fb_width); printk(TBOOT_INFO" height: %d\n", g_fb.common.fb_height); printk(TBOOT_INFO" bpp: %d\n", g_fb.common.fb_bpp); printk(TBOOT_INFO" type: %d\n", g_fb.common.fb_type); if (g_fb.common.fb_addr > 0xffffffffULL || plus_overflow_u32((uint32_t)g_fb.common.fb_addr, g_fb.common.fb_pitch * g_fb.common.fb_height)) { printk(TBOOT_ERR"Framebuffer at >4GB is not supported\n"); return; } if (g_fb.common.fb_width > FB_MAX_HRES || g_fb.common.fb_height > FB_MAX_VRES || g_fb.common.fb_bpp != FB_BPP) { printk(TBOOT_ERR"Not supported framebuffer size/bpp\n"); return; } for (uint32_t i = 0; i < g_fb.common.fb_width * g_fb.common.fb_height; ++i) { ((volatile uint32_t*)(uint32_t)g_fb.common.fb_addr)[i] = 0; fb_buff1[i] = 0; fb_buff2[i] = 0; } /* set up context by global variables */ ssfn_src = (ssfn_font_t*)u_vga16_sfn; ssfn_dst.ptr = (uint8_t*)fb_buff1; ssfn_dst.p = g_fb.common.fb_pitch; ssfn_dst.w = g_fb.common.fb_width; ssfn_dst.h = g_fb.common.fb_height; ssfn_dst.fg = FB_COLOR; ssfn_dst.bg = 0; ssfn_dst.x = 0; ssfn_dst.y = 0; vga_type = VGA_FB; } static void legacy_init(void) { legacy_reset_screen(); vga_type = VGA_LEGACY; } void vga_init(void) { struct mb2_fb* fb = get_framebuffer_info(g_ldr_ctx); if (fb != NULL) { g_fb = *fb; fb_init(); } else { legacy_init(); } } void vga_puts(const char *s, unsigned int cnt) { while ( *s && cnt-- ) { if (vga_type == VGA_LEGACY) { legacy_putc(*s); } else if (vga_type == VGA_FB) { fb_putc(*s); } s++; } } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/vsprintf.c0000644000000000000000000003521414210363175015520 0ustar 00000000000000/* * vsprintf.c: provides string formatting fns * * Copyright (c) 2010-2011, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include static bool div64(uint64_t num, uint32_t base, uint64_t *quot, uint32_t *rem) { /* check exceptions */ if ( (quot == NULL) || (rem == NULL) || (base == 0) ) return false; uint32_t high = num >> 32; uint32_t low = (uint32_t)num; if ( high == 0 ) { *quot = low / base; *rem = low % base; } else { uint64_t hquo = high / base; \ uint32_t hrem = high % base; uint32_t lquo; /* * use "divl" instead of "/" to avoid the link error * undefined reference to `__udivdi3' */ __asm__ __volatile__ ( "divl %4;" : "=a"(lquo), "=d"(*rem) : "a"(low), "d"(hrem), "r"(base)); *quot = (hquo << 32) + lquo; } return true; } /* * write the character into the buffer * return the position of the buffer after writting */ static unsigned long write_char_to_buffer(char *buf, size_t buf_len, unsigned long buf_pos, char ch) { /* check buffer overflow? */ if ( buf_pos >= buf_len ) return 0; *(buf + buf_pos) = ch; return buf_pos + 1; } /* * write pad_len pads into the buffer * return the position of the buffer after writting */ static unsigned long write_pads_to_buffer(char *buf, size_t buf_len, unsigned long buf_pos, char pad, size_t pad_len) { for ( unsigned int i = 0; i < pad_len; i++ ) buf_pos = write_char_to_buffer(buf, buf_len, buf_pos, pad); return buf_pos; } /* %[flags][width][.precision][length]specifier */ typedef struct { /* flag */ #define LEFT_ALIGNED (1 << 0) /* '-' */ #define SIGNED (1 << 1) /* '+' */ #define SPACE (1 << 2) /* ' ' */ #define PREFIX (1 << 3) /* '#' */ #define ZERO_PADDED (1 << 4) /* '0' */ int flag; /* width & precision */ unsigned int width, precision; /* length */ enum {NORM, LONG, LONGLONG} flag_long; /* specifier */ int base; bool cap; bool sign; bool digit; } modifiers_t; /* * write the string into the buffer regarding flags * return the position of the buffer after writing */ static unsigned long write_string_to_buffer(char *buf, size_t buf_len, unsigned long buf_pos, const char* str, size_t strlen, modifiers_t *mods) { unsigned int i; if (mods->precision > 0) strlen = (strlen > mods->precision) ? mods->precision : strlen; mods->width = ( mods->width > strlen ) ? mods->width - strlen : 0; if ( mods->flag & LEFT_ALIGNED ) { /* left align */ for ( i = 0; i < strlen; i++ ) buf_pos = write_char_to_buffer(buf, buf_len, buf_pos, str[i]); buf_pos = write_pads_to_buffer(buf, buf_len, buf_pos, ' ', mods->width); } else { /* right align */ /* if not digit, don't considering pad '0' */ char pad = ( mods->digit && (mods->flag & ZERO_PADDED) ) ? '0' : ' '; buf_pos = write_pads_to_buffer(buf, buf_len, buf_pos, pad, mods->width); for ( i = 0; i < strlen; i++ ) buf_pos = write_char_to_buffer(buf, buf_len, buf_pos, str[i]); } return buf_pos; } /* convert a integer to a string regarding flags, qualifier, specifier, etc. */ static size_t int2str(long long val, char *str, size_t strlen, const modifiers_t *mods) { unsigned int i; size_t length = 0, number_length = 0; unsigned long number_start = 0; const char hexdig_lowercase[] = "0123456789abcdef"; const char hexdig_uppercase[] = "0123456789ABCDEF"; unsigned long long nval; /* check, we support octal/decimal/hex only */ if ( (mods->base != 8) && (mods->base != 10) && (mods->base != 16) ) return 0; if ( str == NULL || strlen == 0 ) return 0; if ( mods->flag & PREFIX ) { if ( mods->base == 8 ) *(str + length++) = '0'; /* add prefix 0 for octal */ else if ( mods->base == 16 ) { if ( strlen < 2 ) return 0; /* add prefix 0x/0X for hex */ *(str + length++) = '0'; *(str + length++) = ( mods->cap ) ? 'X' : 'x'; } } /* * if it is shown as signed decimal(%d), we consider to add -/+/' ' * but, if it is an unsigned number, no need to add -/+/' ' */ if ( mods->base == 10 && mods->sign ) { if ( val < 0 ) { /* negative */ *(str + length++) = '-'; val = -val; } else { /* positive */ if ( mods->flag & SIGNED ) *(str + length++) = '+'; else if ( mods->flag & SPACE ) *(str + length++) = ' '; } } /* truncate to unsigned long or unsigned int if type of val is */ if ( mods->flag_long == LONGLONG ) nval = (unsigned long long)val; else if ( mods->flag_long == LONG ) nval = (unsigned long long)(unsigned long)val; else nval = (unsigned long long)(unsigned int)val; /* convert */ number_start = length; do { /* overflow? */ if ( length >= strlen ) break; uint32_t rem = 0; if ( !div64(nval, mods->base, &nval, &rem) ) return 0; *(str + length) = ( mods->cap ) ? hexdig_uppercase[rem] : hexdig_lowercase[rem]; length++; number_length++; } while ( nval ); /* handle precision */ while ( number_length < mods->precision ) { /* overflow? */ if ( length >= strlen ) break; *(str + length) = '0'; length++; number_length++; } /* reverse */ for ( i = 0; i < number_length/2; i++ ) { char ch; ch = *(str + number_start + i); *(str + number_start + i) = *(str + number_start + (number_length - i - 1)); *(str + number_start + (number_length - i - 1)) = ch; } return length; } int tb_vscnprintf(char *buf, size_t size, const char *fmt, va_list ap) { unsigned int buf_pos = 0; /* return value doesn't count the last '\0' */ const char *fmt_ptr; modifiers_t mods; /* check buf */ if ( (buf == NULL) || (size == 0) ) return 0; /* check fmt */ if ( fmt == NULL ) return 0; tb_memset(&mods, 0, sizeof(mods)); while ( buf_pos < size ) { bool success; /* handle normal characters */ while ( *fmt != '%' ) { buf_pos = write_char_to_buffer(buf, size, buf_pos, *fmt); if ( *fmt == '\0' ) return buf_pos - 1; fmt++; } /* handle %: %[flags][width][.precision][length]specifier */ /* * start to parse the syntax of %, save the position of fmt * in case that append the string to the buffer if % substring * doesnot match the syntax */ fmt_ptr = fmt + 1; /* skip '%' */ success = true; /* assume parsing % substring would succeed */ /* parsing flags */ while ( true ) { switch ( *fmt_ptr ) { case '-': mods.flag |= LEFT_ALIGNED; break; case '+': mods.flag |= SIGNED ; break; case ' ': mods.flag |= SPACE; break; case '#': mods.flag |= PREFIX; break; case '0': mods.flag |= ZERO_PADDED; break; default: goto handle_width; } fmt_ptr++; } /* parsing width */ handle_width: if ( *fmt_ptr == '*' ) { mods.width = va_arg(ap, int); fmt_ptr++; } else mods.width = tb_strtoul(fmt_ptr, (char **)&fmt_ptr, 10); if ( *fmt_ptr == '.' ) { /* skip . */ fmt_ptr++; /* parsing precision */ if ( *fmt_ptr == '*' ) { mods.precision = va_arg(ap, int); fmt_ptr++; } else mods.precision = tb_strtoul(fmt_ptr, (char **)&fmt_ptr, 10); } /* parsing qualifier: h l L; * h is ignored here, and 'L' and 'j' are treated as 'll' */ mods.flag_long = NORM; if ( *fmt_ptr == 'L' || *fmt_ptr == 'j' ) { mods.flag_long = LONGLONG; fmt_ptr++; } else if ( *fmt_ptr == 'l' && *(fmt_ptr + 1) == 'l' ) { mods.flag_long = LONGLONG; fmt_ptr += 2; } else if ( *fmt_ptr == 'l' ) { mods.flag_long = LONG; fmt_ptr++; } #define write_number_to_buffer(__buf, __size, __buf_pos, __mods) \ ({ \ char __str[32]; \ size_t __real_strlen; \ if ( __mods.flag_long == LONGLONG ) { \ long long __number = 0; \ __number = va_arg(ap, long long); \ __real_strlen = int2str(__number, __str, sizeof(__str), &__mods); \ } \ else if ( __mods.flag_long == LONG ) { \ long __number = 0; \ __number = va_arg(ap, long); \ __real_strlen = int2str(__number, __str, sizeof(__str), &__mods); \ } \ else { \ int __number = 0; \ __number = va_arg(ap, int); \ __real_strlen = int2str(__number, __str, sizeof(__str), &__mods); \ } \ __mods.digit = true; \ write_string_to_buffer( \ __buf, __size, __buf_pos, __str, __real_strlen, &__mods); \ }) /* parsing specifier */ mods.base = 10; mods.cap = mods.sign = false; switch ( *fmt_ptr ) { case 'c': { char str[1]; str[0] = (char)va_arg(ap, int); mods.digit = false; buf_pos = write_string_to_buffer( buf, size, buf_pos, str, tb_strlen(str), &mods); break; } case 's': { char *str; str = va_arg(ap, char *); mods.digit = false; buf_pos = write_string_to_buffer( buf, size, buf_pos, str, tb_strlen(str), &mods); break; } case 'o': mods.base = 8; buf_pos = write_number_to_buffer(buf, size, buf_pos, mods); break; case 'X': mods.cap = true; mods.base = 16; buf_pos = write_number_to_buffer(buf, size, buf_pos, mods); break; case 'p': mods.flag |= PREFIX; /* print prefix 0x for %p */ mods.flag_long = LONG; /* FALLTHROUGH */ case 'x': mods.base = 16; buf_pos = write_number_to_buffer(buf, size, buf_pos, mods); break; case 'i': case 'd': mods.sign = true; buf_pos = write_number_to_buffer(buf, size, buf_pos, mods); break; case 'u': buf_pos = write_number_to_buffer(buf, size, buf_pos, mods); break; case 'e': case 'E': /* ignore */ break; case '%': buf_pos = write_char_to_buffer(buf, size, buf_pos, '%'); break; default: success = false; break; } /* switch for specifier */ fmt_ptr++; /* skip the above character */ if ( success ) fmt = fmt_ptr; else /* parsing % substring error, treat it as a normal string */ /* *fmt = '%' */ buf_pos = write_char_to_buffer(buf, size, buf_pos, *fmt++); } /* while */ buf[buf_pos - 1] = '\0'; /* if the buffer is overflowed. */ return buf_pos - 1; } int tb_snprintf(char *buf, size_t size, const char *fmt, ...) { va_list ap; va_start(ap, fmt); int count = tb_vscnprintf(buf, size, fmt, ap); va_end(ap); return count; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/common/vtd.c0000644000000000000000000001474514210363175014450 0ustar 00000000000000/* * vtd.c: VT-d support functions * * Copyright (c) 2019, Intel Corporation * 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 Intel Corporation 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 OWNER 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. */ #include #include #include #include #include #include #include #include #include #include #include static struct acpi_table_header *g_dmar_table; static __data bool g_hide_dmar; bool vtd_bios_enabled(void) { return get_vtd_dmar_table() != NULL; } bool vtd_save_dmar_table(void) { /* find DMAR table and save it */ g_dmar_table = (struct acpi_table_header *)get_vtd_dmar_table(); printk(TBOOT_DETA"DMAR table @ %p saved.\n", g_dmar_table); return true; } bool vtd_restore_dmar_table(void) { struct acpi_table_header *hdr; g_hide_dmar = false; /* find DMAR table first */ hdr = (struct acpi_table_header *)get_vtd_dmar_table(); if ( hdr != NULL ) { printk(TBOOT_DETA"DMAR table @ %p is still there, skip restore step.\n", hdr); return true; } /* check saved DMAR table */ if ( g_dmar_table == NULL ) { printk(TBOOT_ERR"No DMAR table saved, abort restore step.\n"); return false; } /* restore DMAR if needed */ tb_memcpy(g_dmar_table->signature, DMAR_SIG, sizeof(g_dmar_table->signature)); /* need to hide DMAR table while resume from S3 */ g_hide_dmar = true; printk(TBOOT_DETA"DMAR table @ %p restored.\n", hdr); return true; } bool vtd_remove_dmar_table(void) { struct acpi_table_header *hdr; /* check whether it is needed */ if ( !g_hide_dmar ) { printk(TBOOT_DETA"No need to hide DMAR table.\n"); return true; } /* find DMAR table */ hdr = (struct acpi_table_header *)get_vtd_dmar_table(); if ( hdr == NULL ) { printk(TBOOT_DETA"No DMAR table, skip remove step.\n"); return true; } /* remove DMAR table */ hdr->signature[0] = '\0'; printk(TBOOT_DETA"DMAR table @ %p removed.\n", hdr); return true; } struct dmar_remapping *vtd_get_dmar_remap(uint32_t *remap_length) { struct acpi_dmar *dmar = get_vtd_dmar_table(); if (dmar == NULL || remap_length == NULL) { return NULL; } *remap_length = dmar->hdr.length - sizeof(*dmar); return (struct dmar_remapping*)(dmar->table_offsets); } bool vtd_disable_dma_remap(struct dmar_remapping *rs) { if (rs->type != DMAR_REMAPPING_DRHD) { return false; } uint32_t timeout; uint32_t gsts = read_reg32(rs->register_base_address, VTD_GSTS_OFFSET) & 0x96FFFFFF; if (gsts & TE_STAT) { /* Clear TE_STAT bit and write back to GCMD */ gsts &= ~TE_STAT; write_reg32(rs->register_base_address, VTD_GCMD_OFFSET, gsts); /* Wait until GSTS indicates that operation is completed */ timeout = VTD_OPERATION_TIMEOUT; while (read_reg32(rs->register_base_address, VTD_GSTS_OFFSET) & TE_STAT) { cpu_relax(); if (--timeout == 0) { return false; } } } return true; } bool vtd_disable_qie(struct dmar_remapping *rs) { if (rs->type != DMAR_REMAPPING_DRHD) { return false; } uint32_t timeout; uint32_t gsts = read_reg32(rs->register_base_address, VTD_GSTS_OFFSET) & 0x96FFFFFF; if (gsts & QIE_STAT) { /* Wait for HW to complete pending invalidation requests */ timeout = VTD_OPERATION_TIMEOUT; while (read_reg64(rs->register_base_address, VTD_IQT_OFFSET) != read_reg64(rs->register_base_address, VTD_IQH_OFFSET)) { cpu_relax(); if (--timeout == 0) { return false; } } /* Clear QIE_STAT bit and write back to GCMD */ gsts &= ~QIE_STAT; write_reg32(rs->register_base_address, VTD_GCMD_OFFSET, gsts); /* Wait until GSTS indicates that operation is completed */ timeout = VTD_OPERATION_TIMEOUT; while (read_reg32(rs->register_base_address, VTD_GSTS_OFFSET) & QIE_STAT) { cpu_relax(); if (--timeout == 0) { return false; } } /* Set IQT to 0 (IQH was set by HW) */ write_reg64(rs->register_base_address, VTD_IQT_OFFSET, 0); } return true; } bool vtd_disable_ire(struct dmar_remapping *rs) { if (rs->type != DMAR_REMAPPING_DRHD) { return false; } uint32_t timeout; uint32_t gsts = read_reg32(rs->register_base_address, VTD_GSTS_OFFSET) & 0x96FFFFFF; if (gsts & IRE_STAT) { /* Clear IRE_STAT bit and write back to GCMD */ gsts &= ~IRE_STAT; write_reg32(rs->register_base_address, VTD_GCMD_OFFSET, gsts); /* Wait until GSTS indicates that operation is completed */ timeout = VTD_OPERATION_TIMEOUT; while (read_reg32(rs->register_base_address, VTD_GSTS_OFFSET) & IRE_STAT) { cpu_relax(); if (--timeout == 0) { return false; } } } return true; }tboot-1.10.5/tboot/common/wakeup.S0000644000000000000000000000524614210363175015123 0ustar 00000000000000/* * wakeup.S: assembly S3 wakeup support * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ /* * s3 resume entry called from BIOS */ .code16 .align PAGE_SIZE, 0 ENTRY(s3_wakeup_16) cli cld mov %cs, %ax mov %ax, %ds lgdtl real_gdt_desc - s3_wakeup_16 mov $1, %eax mov %eax, %cr0 ljmpl $(cs_sel), $(s3_wakeup_32) .align 8 /* * descriptors and descriptor tables */ real_gdt_desc: .word real_gdt_table_end - real_gdt_table - 1 .long TBOOT_S3_WAKEUP_ADDR + real_gdt_table - s3_wakeup_16 .align 8 real_gdt_table: /* unused */ .quad 0x0000000000000000 real_cs_desc: /* cs */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9a00 /* read + exec */ .word 0x00cf /* granularity = 4096 */ real_ds_desc: /* ds */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9200 /* read + write */ .word 0x00cf /* granularity = 4096 */ /* end (unused) */ .quad 0x0000000000000000 real_gdt_table_end: ENTRY(s3_wakeup_end) .code32 s3_wakeup_32: mov $(ds_sel), %ecx mov %ecx, %ds mov $1, %eax mov %eax, s3_flag jmp __start tboot-1.10.5/tboot/include/acpi.h0000644000000000000000000003531314210363175014721 0ustar 00000000000000/* $OpenBSD: acpireg.h,v 1.17 2009/04/11 08:22:48 kettenis Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * Copyright (c) 2005 Marco Peereboom * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Portions copyright (c) 2010, Intel Corporation */ #ifndef __ACPI_H__ #define __ACPI_H__ //#define ACPI_DEBUG #define RSDP_SCOPE1_LOW (void *)0x000000 #define RSDP_SCOPE1_HIGH (void *)0x000400 #define RSDP_SCOPE2_LOW (void *)0x0E0000 #define RSDP_SCOPE2_HIGH (void *)0x100000 /* Root System Descriptor Pointer (RSDP) for ACPI 1.0 */ struct acpi_rsdp1 { u_int8_t signature[8]; #define RSDP_SIG "RSD PTR " u_int8_t checksum; /* make sum == 0 */ u_int8_t oemid[6]; u_int8_t revision; /* 0 for v1.0, 2 for v2.0 */ u_int32_t rsdt; /* physical */ } __packed; /* Root System Descriptor Pointer (RSDP) for ACPI 2.0 */ struct acpi_rsdp { struct acpi_rsdp1 rsdp1; /* * The following values are only valid * when rsdp_revision == 2 */ u_int32_t rsdp_length; /* length of rsdp */ u_int64_t rsdp_xsdt; /* physical */ u_int8_t rsdp_extchecksum; /* entire table */ u_int8_t rsdp_reserved[3]; /* must be zero */ } __packed; /* Common System Description Table Header */ struct acpi_table_header { u_int8_t signature[4]; u_int32_t length; u_int8_t revision; u_int8_t checksum; u_int8_t oemid[6]; u_int8_t oemtableid[8]; u_int32_t oemrevision; u_int8_t aslcompilerid[4]; u_int32_t aslcompilerrevision; } __packed; /* Root System Description Table (RSDT) */ struct acpi_rsdt { struct acpi_table_header hdr; #define RSDT_SIG "RSDT" u_int32_t table_offsets[1]; } __packed; /* Extended System Descriptiion Table */ struct acpi_xsdt { struct acpi_table_header hdr; #define XSDT_SIG "XSDT" u_int64_t table_offsets[1]; } __packed; /* Generic Address Structure */ struct acpi_gas { u_int8_t address_space_id; #define GAS_SYSTEM_MEMORY 0 #define GAS_SYSTEM_IOSPACE 1 #define GAS_PCI_CFG_SPACE 2 #define GAS_EMBEDDED 3 #define GAS_SMBUS 4 #define GAS_FUNCTIONAL_FIXED 127 u_int8_t register_bit_width; u_int8_t register_bit_offset; u_int8_t access_size; #define GAS_ACCESS_UNDEFINED 0 #define GAS_ACCESS_BYTE 1 #define GAS_ACCESS_WORD 2 #define GAS_ACCESS_DWORD 3 #define GAS_ACCESS_QWORD 4 u_int64_t address; } __packed; /* Fixed ACPI Descriptiion Table */ struct acpi_fadt { struct acpi_table_header hdr; #define FADT_SIG "FACP" u_int32_t firmware_ctl; /* phys addr FACS */ u_int32_t dsdt; /* phys addr DSDT */ /* int_model is defined in ACPI 1.0, in ACPI 2.0, it should be zero */ u_int8_t int_model; /* interrupt model (hdr_revision < 3) */ #define FADT_INT_DUAL_PIC 0 #define FADT_INT_MULTI_APIC 1 u_int8_t pm_profile; /* power mgmt profile */ #define FADT_PM_UNSPEC 0 #define FADT_PM_DESKTOP 1 #define FADT_PM_MOBILE 2 #define FADT_PM_WORKSTATION 3 #define FADT_PM_ENT_SERVER 4 #define FADT_PM_SOHO_SERVER 5 #define FADT_PM_APPLIANCE 6 #define FADT_PM_PERF_SERVER 7 u_int16_t sci_int; /* SCI interrupt */ u_int32_t smi_cmd; /* SMI command port */ u_int8_t acpi_enable; /* value to enable */ u_int8_t acpi_disable; /* value to disable */ u_int8_t s4bios_req; /* value for S4 */ u_int8_t pstate_cnt; /* value for performance (hdr_revision > 2) */ u_int32_t pm1a_evt_blk; /* power management 1a */ u_int32_t pm1b_evt_blk; /* power mangement 1b */ u_int32_t pm1a_cnt_blk; /* pm control 1a */ u_int32_t pm1b_cnt_blk; /* pm control 1b */ u_int32_t pm2_cnt_blk; /* pm control 2 */ u_int32_t pm_tmr_blk; u_int32_t gpe0_blk; u_int32_t gpe1_blk; u_int8_t pm1_evt_len; u_int8_t pm1_cnt_len; u_int8_t pm2_cnt_len; u_int8_t pm_tmr_len; u_int8_t gpe0_blk_len; u_int8_t gpe1_blk_len; u_int8_t gpe1_base; u_int8_t cst_cnt; /* (hdr_revision > 2) */ u_int16_t p_lvl2_lat; u_int16_t p_lvl3_lat; u_int16_t flush_size; u_int16_t flush_stride; u_int8_t duty_offset; u_int8_t duty_width; u_int8_t day_alrm; u_int8_t mon_alrm; u_int8_t century; u_int16_t iapc_boot_arch; /* (hdr_revision > 2) */ #define FADT_LEGACY_DEVICES 0x0001 /* Legacy devices supported */ #define FADT_i8042 0x0002 /* Keyboard controller present */ #define FADT_NO_VGA 0x0004 /* Do not probe VGA */ u_int8_t reserved1; u_int32_t flags; #define FADT_WBINVD 0x00000001 #define FADT_WBINVD_FLUSH 0x00000002 #define FADT_PROC_C1 0x00000004 #define FADT_P_LVL2_UP 0x00000008 #define FADT_PWR_BUTTON 0x00000010 #define FADT_SLP_BUTTON 0x00000020 #define FADT_FIX_RTC 0x00000040 #define FADT_RTC_S4 0x00000080 #define FADT_TMR_VAL_EXT 0x00000100 #define FADT_DCK_CAP 0x00000200 #define FADT_RESET_REG_SUP 0x00000400 #define FADT_SEALED_CASE 0x00000800 #define FADT_HEADLESS 0x00001000 #define FADT_CPU_SW_SLP 0x00002000 #define FADT_PCI_EXP_WAK 0x00004000 #define FADT_USE_PLATFORM_CLOCK 0x00008000 #define FADT_S4_RTC_STS_VALID 0x00010000 #define FADT_REMOTE_POWER_ON_CAPABLE 0x00020000 #define FADT_FORCE_APIC_CLUSTER_MODEL 0x00040000 #define FADT_FORCE_APIC_PHYS_DEST_MODE 0x00080000 /* * Following values only exist when rev > 1 * If the extended addresses exists, they * must be used in preferense to the non- * extended values above */ struct acpi_gas reset_reg; u_int8_t reset_value; u_int8_t reserved2a; u_int8_t reserved2b; u_int8_t reserved2c; u_int64_t x_firmware_ctl; u_int64_t x_dsdt; struct acpi_gas x_pm1a_evt_blk; struct acpi_gas x_pm1b_evt_blk; struct acpi_gas x_pm1a_cnt_blk; struct acpi_gas x_pm1b_cnt_blk; struct acpi_gas x_pm2_cnt_blk; struct acpi_gas x_pm_tmr_blk; struct acpi_gas x_gpe0_blk; struct acpi_gas x_gpe1_blk; } __packed; struct acpi_madt { struct acpi_table_header hdr; #define MADT_SIG "APIC" u_int32_t local_apic_address; u_int32_t flags; #define ACPI_APIC_PCAT_COMPAT 0x00000001 } __packed; struct acpi_madt_lapic { u_int8_t apic_type; #define ACPI_MADT_LAPIC 0 u_int8_t length; u_int8_t acpi_proc_id; u_int8_t apic_id; u_int32_t flags; #define ACPI_PROC_ENABLE 0x00000001 } __packed; struct acpi_madt_ioapic { u_int8_t apic_type; #define ACPI_MADT_IOAPIC 1 u_int8_t length; u_int8_t acpi_ioapic_id; u_int8_t reserved; u_int32_t address; u_int32_t global_int_base; } __packed; typedef struct acpi_madt_ioapic acpi_table_ioapic_t; struct acpi_madt_override { u_int8_t apic_type; #define ACPI_MADT_OVERRIDE 2 u_int8_t length; u_int8_t bus; #define ACPI_OVERRIDE_BUS_ISA 0 u_int8_t source; u_int32_t global_int; u_int16_t flags; #define ACPI_OVERRIDE_POLARITY_BITS 0x3 #define ACPI_OVERRIDE_POLARITY_BUS 0x0 #define ACPI_OVERRIDE_POLARITY_HIGH 0x1 #define ACPI_OVERRIDE_POLARITY_LOW 0x3 #define ACPI_OVERRIDE_TRIGGER_BITS 0xc #define ACPI_OVERRIDE_TRIGGER_BUS 0x0 #define ACPI_OVERRIDE_TRIGGER_EDGE 0x4 #define ACPI_OVERRIDE_TRIGGER_LEVEL 0xc } __packed; struct acpi_madt_nmi { u_int8_t apic_type; #define ACPI_MADT_NMI 3 u_int8_t length; u_int16_t flags; /* Same flags as acpi_madt_override */ u_int32_t global_int; } __packed; struct acpi_madt_lapic_nmi { u_int8_t apic_type; #define ACPI_MADT_LAPIC_NMI 4 u_int8_t length; u_int8_t acpi_proc_id; u_int16_t flags; /* Same flags as acpi_madt_override */ u_int8_t local_apic_lint; } __packed; struct acpi_madt_lapic_override { u_int8_t apic_type; #define ACPI_MADT_LAPIC_OVERRIDE 5 u_int8_t length; u_int16_t reserved; u_int64_t lapic_address; } __packed; struct acpi_madt_io_sapic { u_int8_t apic_type; #define ACPI_MADT_IO_SAPIC 6 u_int8_t length; u_int8_t iosapic_id; u_int8_t reserved; u_int32_t global_int_base; u_int64_t iosapic_address; } __packed; struct acpi_madt_local_sapic { u_int8_t apic_type; #define ACPI_MADT_LOCAL_SAPIC 7 u_int8_t length; u_int8_t acpi_proc_id; u_int8_t local_sapic_id; u_int8_t local_sapic_eid; u_int8_t reserved[3]; u_int32_t flags; /* Same flags as acpi_madt_lapic */ u_int32_t acpi_proc_uid; u_int8_t acpi_proc_uid_string[1]; } __packed; struct acpi_madt_platform_int { u_int8_t apic_type; #define ACPI_MADT_PLATFORM_INT 8 u_int8_t length; u_int16_t flags; /* Same flags as acpi_madt_override */ u_int8_t int_type; #define ACPI_MADT_PLATFORM_PMI 1 #define ACPI_MADT_PLATFORM_INIT 2 #define ACPI_MADT_PLATFORM_CORR_ERROR 3 u_int8_t proc_id; u_int8_t proc_eid; u_int8_t io_sapic_vec; u_int32_t global_int; u_int32_t platform_int_flags; #define ACPI_MADT_PLATFORM_CPEI 0x00000001 } __packed; union acpi_madt_entry { struct acpi_madt_lapic madt_lapic; struct acpi_madt_ioapic madt_ioapic; struct acpi_madt_override madt_override; struct acpi_madt_nmi madt_nmi; struct acpi_madt_lapic_nmi madt_lapic_nmi; struct acpi_madt_lapic_override madt_lapic_override; struct acpi_madt_io_sapic madt_io_sapic; struct acpi_madt_local_sapic madt_local_sapic; struct acpi_madt_platform_int madt_platform_int; } __packed; struct device_scope { u_int8_t type; u_int8_t length; u_int16_t reserved; u_int8_t enumeration_id; u_int8_t start_bus_number; u_int16_t path[1]; /* Path starts here */ } __packed; struct dmar_remapping { u_int16_t type; #define DMAR_REMAPPING_DRHD 0 #define DMAR_REMAPPING_RMRR 1 #define DMAR_REMAPPING_ATSR 2 #define DMAR_REMAPPING_RHSA 3 #define DMAR_REMAPPING_RESERVED 4 u_int16_t length; u_int8_t flags; #define REMAPPING_INCLUDE_PCI_ALL Ox01 u_int8_t reserved; u_int16_t segment_number; u_int64_t register_base_address; struct device_scope device_scope_entry[1]; /* Device Scope starts here */ } __packed; struct acpi_dmar { struct acpi_table_header hdr; #define DMAR_SIG "DMAR" u_int8_t host_address_width; u_int8_t flags; #define DMAR_INTR_REMAP 0x01 u_int8_t reserved[10]; struct dmar_remapping table_offsets[1]; /* dmar_remapping structure starts here */ } __packed; struct acpi_mcfg_mmcfg { u_int64_t base_address; u_int16_t group_number; u_int8_t start_bus_number; u_int8_t end_bus_number; u_int32_t reserved; } __packed; struct acpi_mcfg { struct acpi_table_header hdr; #define MCFG_SIG "MCFG" u_int64_t reserved; /* struct acpi_mcfg_mmcfg table_offsets[1]; */ u_int32_t base_address; } __packed; typedef struct acpi_mcfg acpi_table_mcfg_t; #if 0 #define ACPI_FREQUENCY 3579545 /* Per ACPI spec */ /* * PCI Configuration space */ #define ACPI_PCI_BUS(addr) (u_int16_t)((addr) >> 48) #define ACPI_PCI_DEV(addr) (u_int16_t)((addr) >> 32) #define ACPI_PCI_FN(addr) (u_int16_t)((addr) >> 16) #define ACPI_PCI_REG(addr) (u_int16_t)(addr) #define ACPI_PCI_ADDR(b,d,f,r) ((u_int64_t)(b)<<48LL | (u_int64_t)(d)<<32LL | (f)<<16LL | (r)) /* * PM1 Status Registers Fixed Hardware Feature Status Bits */ #define ACPI_PM1_STATUS 0x00 #define ACPI_PM1_TMR_STS 0x0001 #define ACPI_PM1_BM_STS 0x0010 #define ACPI_PM1_GBL_STS 0x0020 #define ACPI_PM1_PWRBTN_STS 0x0100 #define ACPI_PM1_SLPBTN_STS 0x0200 #define ACPI_PM1_RTC_STS 0x0400 #define ACPI_PM1_PCIEXP_WAKE_STS 0x4000 #define ACPI_PM1_WAK_STS 0x8000 /* * PM1 Enable Registers */ #define ACPI_PM1_ENABLE 0x02 #define ACPI_PM1_TMR_EN 0x0001 #define ACPI_PM1_GBL_EN 0x0020 #define ACPI_PM1_PWRBTN_EN 0x0100 #define ACPI_PM1_SLPBTN_EN 0x0200 #define ACPI_PM1_RTC_EN 0x0400 #define ACPI_PM1_PCIEXP_WAKE_DIS 0x4000 /* * PM1 Control Registers */ #define ACPI_PM1_CONTROL 0x00 #define ACPI_PM1_SCI_EN 0x0001 #define ACPI_PM1_BM_RLD 0x0002 #define ACPI_PM1_GBL_RLS 0x0004 #define ACPI_PM1_SLP_TYPX(x) ((x) << 10) #define ACPI_PM1_SLP_TYPX_MASK 0x1c00 #define ACPI_PM1_SLP_EN 0x2000 /* * PM2 Control Registers */ #define ACPI_PM2_CONTROL 0x06 #define ACPI_PM2_ARB_DIS 0x0001 /* * Sleeping States */ #define ACPI_STATE_S0 0 #define ACPI_STATE_S1 1 #define ACPI_STATE_S2 2 #define ACPI_STATE_S3 3 #define ACPI_STATE_S4 4 #define ACPI_STATE_S5 5 /* * ACPI Device IDs */ #define ACPI_DEV_TIM "PNP0100" /* System timer */ #define ACPI_DEV_ACPI "PNP0C08" /* ACPI device */ #define ACPI_DEV_PCIB "PNP0A03" /* PCI bus */ #define ACPI_DEV_GISAB "PNP0A05" /* Generic ISA Bus */ #define ACPI_DEV_EIOB "PNP0A06" /* Extended I/O Bus */ #define ACPI_DEV_PCIEB "PNP0A08" /* PCIe bus */ #define ACPI_DEV_MR "PNP0C02" /* Motherboard resources */ #define ACPI_DEV_NPROC "PNP0C04" /* Numeric data processor */ #define ACPI_DEV_CS "PNP0C08" /* ACPI-Compliant System */ #define ACPI_DEV_ECD "PNP0C09" /* Embedded Controller Device */ #define ACPI_DEV_CMB "PNP0C0A" /* Control Method Battery */ #define ACPI_DEV_FAN "PNP0C0B" /* Fan Device */ #define ACPI_DEV_PBD "PNP0C0C" /* Power Button Device */ #define ACPI_DEV_LD "PNP0C0D" /* Lid Device */ #define ACPI_DEV_SBD "PNP0C0E" /* Sleep Button Device */ #define ACPI_DEV_PILD "PNP0C0F" /* PCI Interrupt Link Device */ #define ACPI_DEV_MEMD "PNP0C80" /* Memory Device */ #define ACPI_DEV_SHC "ACPI0001" /* SMBus 1.0 Host Controller */ #define ACPI_DEV_SMS1 "ACPI0002" /* Smart Battery Subsystem */ #define ACPI_DEV_AC "ACPI0003" /* AC Device */ #define ACPI_DEV_MD "ACPI0004" /* Module Device */ #define ACPI_DEV_SMS2 "ACPI0005" /* SMBus 2.0 Host Controller */ #define ACPI_DEV_GBD "ACPI0006" /* GPE Block Device */ #define ACPI_DEV_PD "ACPI0007" /* Processor Device */ #define ACPI_DEV_ALSD "ACPI0008" /* Ambient Light Sensor Device */ #define ACPI_DEV_IOXA "ACPI0009" /* IO x APIC Device */ #define ACPI_DEV_IOA "ACPI000A"/ /* IO APIC Device */ #define ACPI_DEV_IOSA "ACPI000B" /* IO SAPIC Device */ #define ACPI_DEV_THZ "THERMALZONE" /* Thermal Zone */ #define ACPI_DEV_FFB "FIXEDBUTTON" /* Fixed Feature Button */ #define ACPI_DEV_ASUS "ASUS010" /* ASUS Hotkeys */ #define ACPI_DEV_THINKPAD "IBM0068" /* ThinkPad support */ #endif extern bool vtd_bios_enabled(void); extern bool save_vtd_dmar_table(void); extern bool restore_vtd_dmar_table(void); extern bool remove_vtd_dmar_table(void); extern struct acpi_table_ioapic *get_acpi_ioapic_table(void); extern struct acpi_mcfg *get_acpi_mcfg_table(void); extern struct acpi_dmar *get_vtd_dmar_table(void); extern void disable_smis(void); extern bool machine_sleep(const tboot_acpi_sleep_info_t *); extern void set_s3_resume_vector(const tboot_acpi_sleep_info_t *, uint64_t); extern struct acpi_rsdp *get_rsdp(loader_ctx *lctx); extern uint32_t get_madt_apic_base(void); #endif /* __ACPI_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/atomic.h0000644000000000000000000001306614210363175015262 0ustar 00000000000000/*- * Copyright (c) 1998 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $FreeBSD: src/sys/i386/include/atomic.h,v 1.47.2.2.2.1 2010/02/10 00:26:20 kensmith Exp $ */ /* * Portions copyright (c) 2010, Intel Corporation */ #ifndef __ATOMIC_H__ #define __ATOMIC_H__ /* * Various simple operations on memory, each of which is atomic in the * presence of interrupts and multiple processors. * * atomic_set_char(P, V) (*(u_char *)(P) |= (V)) * atomic_clear_char(P, V) (*(u_char *)(P) &= ~(V)) * atomic_add_char(P, V) (*(u_char *)(P) += (V)) * atomic_subtract_char(P, V) (*(u_char *)(P) -= (V)) * * atomic_set_short(P, V) (*(u_short *)(P) |= (V)) * atomic_clear_short(P, V) (*(u_short *)(P) &= ~(V)) * atomic_add_short(P, V) (*(u_short *)(P) += (V)) * atomic_subtract_short(P, V) (*(u_short *)(P) -= (V)) * * atomic_set_int(P, V) (*(u_int *)(P) |= (V)) * atomic_clear_int(P, V) (*(u_int *)(P) &= ~(V)) * atomic_add_int(P, V) (*(u_int *)(P) += (V)) * atomic_subtract_int(P, V) (*(u_int *)(P) -= (V)) * atomic_readandclear_int(P) (return (*(u_int *)(P)); *(u_int *)(P) = 0;) * * atomic_set_long(P, V) (*(u_long *)(P) |= (V)) * atomic_clear_long(P, V) (*(u_long *)(P) &= ~(V)) * atomic_add_long(P, V) (*(u_long *)(P) += (V)) * atomic_subtract_long(P, V) (*(u_long *)(P) -= (V)) * atomic_readandclear_long(P) (return (*(u_long *)(P)); *(u_long *)(P) = 0;) */ /* * The above functions are expanded inline in the statically-linked * kernel. Lock prefixes are generated if an SMP kernel is being * built. * * Kernel modules call real functions which are built into the kernel. * This allows kernel modules to be portable between UP and SMP systems. */ /* all operations will be defined only for 'int's */ #define atomic_t u_int #define MPLOCKED "lock ; " /* * The assembly is volatilized to avoid code chunk removal by the compiler. * GCC aggressively reorders operations and memory clobbering is necessary * in order to avoid that for memory barriers. */ #define ATOMIC_ASM(NAME, TYPE, OP, CONS, V) \ static __inline void \ atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ { \ __asm __volatile(MPLOCKED OP \ : "=m" (*p) \ : CONS (V), "m" (*p)); \ } \ \ static __inline void \ atomic_##NAME##_barr_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ { \ __asm __volatile(MPLOCKED OP \ : "=m" (*p) \ : CONS (V), "m" (*p) \ : "memory"); \ } \ struct __hack /* * Atomically add the value of v to the integer pointed to by p and return * the previous value of *p. */ static __inline u_int atomic_fetchadd_int(volatile u_int *p, u_int v) { __asm __volatile( " " MPLOCKED " " " xaddl %0, %1 ; " "# atomic_fetchadd_int" : "+r" (v), /* 0 (result) */ "=m" (*p) /* 1 */ : "m" (*p)); /* 2 */ return (v); } #define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ static __inline u_##TYPE \ atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ { \ u_##TYPE res; \ \ __asm __volatile(MPLOCKED LOP \ : "=a" (res), /* 0 */ \ "=m" (*p) /* 1 */ \ : "m" (*p) /* 2 */ \ : "memory"); \ \ return (res); \ } \ \ /* \ * The XCHG instruction asserts LOCK automagically. \ */ \ static __inline void \ atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ { \ __asm __volatile(SOP \ : "=m" (*p), /* 0 */ \ "+r" (v) /* 1 */ \ : "m" (*p) /* 2 */ \ : "memory"); \ } \ struct __hack ATOMIC_ASM(set, int, "orl %1,%0", "ir", v); ATOMIC_ASM(clear, int, "andl %1,%0", "ir", ~v); ATOMIC_ASM(add, int, "addl %1,%0", "ir", v); ATOMIC_ASM(subtract, int, "subl %1,%0", "ir", v); ATOMIC_STORE_LOAD(int, "cmpxchgl %0,%1", "xchgl %1,%0"); #undef ATOMIC_ASM #undef ATOMIC_STORE_LOAD /* Read the current value and store a zero in the destination. */ static __inline u_int atomic_readandclear_int(volatile u_int *addr) { u_int res; res = 0; __asm __volatile( " xchgl %1,%0 ; " "# atomic_readandclear_int" : "+r" (res), /* 0 */ "=m" (*addr) /* 1 */ : "m" (*addr)); return (res); } #define atomic_read(atom) atomic_load_acq_int(atom) #define atomic_inc(atom) atomic_add_int((atom), 1) #define atomic_dec(atom) atomic_subtract_int((atom), 1) #define atomic_set(atom, val) atomic_set_int((atom), (val)) #endif /* __ATOMIC_H__ */ tboot-1.10.5/tboot/include/cmdline.h0000644000000000000000000000554414210363175015423 0ustar 00000000000000/* * cmdline.h: support functions for command line parsing * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __CMDLINE_H__ #define __CMDLINE_H__ #define CMDLINE_SIZE 512 extern char g_cmdline[CMDLINE_SIZE]; extern void tboot_parse_cmdline(void); extern void get_tboot_loglvl(void); extern void get_tboot_log_targets(void); extern bool get_tboot_serial(void); extern void get_tboot_baud(void); extern void get_tboot_fmt(void); extern void get_tboot_vga_delay(void); extern bool get_tboot_mwait(void); extern bool get_tboot_prefer_da(void); extern void get_tboot_min_ram(void); extern bool get_tboot_call_racm(void); extern bool get_tboot_call_racm_check(void); extern bool get_tboot_ignore_prev_err(void); extern bool get_tboot_measure_nv(void); extern void get_tboot_extpol(void); extern bool get_tboot_force_tpm2_legacy_log(void); extern bool get_tboot_save_vtd(void); extern bool get_tboot_dump_memmap(void); /* for parse cmdline of linux kernel, say vga and mem */ extern void linux_parse_cmdline(const char *cmdline); extern bool get_linux_vga(int *vid_mode); extern bool get_linux_mem(uint64_t *initrd_max_mem); extern uint8_t get_loglvl_prefix(char **pbuf, int *len); #endif /* __CMDLINE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/com.h0000644000000000000000000002343114210363175014561 0ustar 00000000000000/*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91 * $FreeBSD: src/sys/dev/ic/ns16550.h,v 1.20 2010/01/11 04:13:06 imp Exp $ */ /* * Portions copyright (c) 2010, Intel Corporation */ /* * NS8250... UART registers. */ #ifndef __COM_H__ #define __COM_H__ /* 8250 registers #[0-6]. */ #define com_data 0 /* data register (R/W) */ #define REG_DATA com_data #define com_ier 1 /* interrupt enable register (W) */ #define REG_IER com_ier #define IER_ERXRDY 0x1 #define IER_ETXRDY 0x2 #define IER_ERLS 0x4 #define IER_EMSC 0x8 #define IER_BITS "\20\1ERXRDY\2ETXRDY\3ERLS\4EMSC" #define com_iir 2 /* interrupt identification register (R) */ #define REG_IIR com_iir #define IIR_IMASK 0xf #define IIR_RXTOUT 0xc #define IIR_BUSY 0x7 #define IIR_RLS 0x6 #define IIR_RXRDY 0x4 #define IIR_TXRDY 0x2 #define IIR_NOPEND 0x1 #define IIR_MLSC 0x0 #define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ #define IIR_BITS "\20\1NOPEND\2TXRDY\3RXRDY" #define com_lcr 3 /* line control register (R/W) */ #define com_cfcr com_lcr /* character format control register (R/W) */ #define REG_LCR com_lcr #define LCR_DLAB 0x80 #define CFCR_DLAB LCR_DLAB #define LCR_EFR_ENABLE 0xbf /* magic to enable EFR on 16650 up */ #define CFCR_EFR_ENABLE LCR_EFR_ENABLE #define LCR_SBREAK 0x40 #define CFCR_SBREAK LCR_SBREAK #define LCR_PZERO 0x30 #define CFCR_PZERO LCR_PZERO #define LCR_PONE 0x20 #define CFCR_PONE LCR_PONE #define LCR_PEVEN 0x10 #define CFCR_PEVEN LCR_PEVEN #define LCR_PODD 0x00 #define CFCR_PODD LCR_PODD #define LCR_PENAB 0x08 #define CFCR_PENAB LCR_PENAB #define LCR_STOPB 0x04 #define CFCR_STOPB LCR_STOPB #define LCR_8BITS 0x03 #define CFCR_8BITS LCR_8BITS #define LCR_7BITS 0x02 #define CFCR_7BITS LCR_7BITS #define LCR_6BITS 0x01 #define CFCR_6BITS LCR_6BITS #define LCR_5BITS 0x00 #define CFCR_5BITS LCR_5BITS #define LCR_ODD_PARITY (LCR_PENAB | LCR_PODD) #define LCR_EVEN_PARITY (LCR_PENAB | LCR_PEVEN) #define LCR_MARK_PARITY (LCR_PENAB | LCR_PONE) #define LCR_SPACE_PARITY (LCR_PENAB | LCR_PZERO) #define com_mcr 4 /* modem control register (R/W) */ #define REG_MCR com_mcr #define MCR_PRESCALE 0x80 /* only available on 16650 up */ #define MCR_LOOPBACK 0x10 #define MCR_IE 0x08 #define MCR_IENABLE MCR_IE #define MCR_DRS 0x04 #define MCR_RTS 0x02 #define MCR_DTR 0x01 #define MCR_BITS "\20\1DTR\2RTS\3DRS\4IE\5LOOPBACK\10PRESCALE" #define com_lsr 5 /* line status register (R/W) */ #define REG_LSR com_lsr #define LSR_RCV_FIFO 0x80 #define LSR_TEMT 0x40 #define LSR_TSRE LSR_TEMT #define LSR_THRE 0x20 #define LSR_TXRDY LSR_THRE #define LSR_BI 0x10 #define LSR_FE 0x08 #define LSR_PE 0x04 #define LSR_OE 0x02 #define LSR_RXRDY 0x01 #define LSR_RCV_MASK 0x1f #define LSR_BITS "\20\1RXRDY\2OE\3PE\4FE\5BI\6THRE\7TEMT\10RCV_FIFO" #define com_msr 6 /* modem status register (R/W) */ #define REG_MSR com_msr #define MSR_DCD 0x80 #define MSR_RI 0x40 #define MSR_DSR 0x20 #define MSR_CTS 0x10 #define MSR_DDCD 0x08 #define MSR_TERI 0x04 #define MSR_DDSR 0x02 #define MSR_DCTS 0x01 #define MSR_BITS "\20\1DCTS\2DDSR\3TERI\4DDCD\5CTS\6DSR\7RI\10DCD" /* 8250 multiplexed registers #[0-1]. Access enabled by LCR[7]. */ #define com_dll 0 /* divisor latch low (R/W) */ #define com_dlbl com_dll #define com_dlm 1 /* divisor latch high (R/W) */ #define com_dlbh com_dlm #define REG_DLL com_dll #define REG_DLH com_dlm /* 16450 register #7. Not multiplexed. */ #define com_scr 7 /* scratch register (R/W) */ /* 16550 register #2. Not multiplexed. */ #define com_fcr 2 /* FIFO control register (W) */ #define com_fifo com_fcr #define REG_FCR com_fcr #define FCR_ENABLE 0x01 #define FIFO_ENABLE FCR_ENABLE #define FCR_RCV_RST 0x02 #define FIFO_RCV_RST FCR_RCV_RST #define FCR_XMT_RST 0x04 #define FIFO_XMT_RST FCR_XMT_RST #define FCR_DMA 0x08 #define FIFO_DMA_MODE FCR_DMA #define FCR_RX_LOW 0x00 #define FIFO_RX_LOW FCR_RX_LOW #define FCR_RX_MEDL 0x40 #define FIFO_RX_MEDL FCR_RX_MEDL #define FCR_RX_MEDH 0x80 #define FIFO_RX_MEDH FCR_RX_MEDH #define FCR_RX_HIGH 0xc0 #define FIFO_RX_HIGH FCR_RX_HIGH #define FCR_BITS "\20\1ENABLE\2RCV_RST\3XMT_RST\4DMA" /* 16650 registers #2,[4-7]. Access enabled by LCR_EFR_ENABLE. */ #define com_efr 2 /* enhanced features register (R/W) */ #define REG_EFR com_efr #define EFR_CTS 0x80 #define EFR_AUTOCTS EFR_CTS #define EFR_RTS 0x40 #define EFR_AUTORTS EFR_RTS #define EFR_EFE 0x10 /* enhanced functions enable */ #define com_xon1 4 /* XON 1 character (R/W) */ #define com_xon2 5 /* XON 2 character (R/W) */ #define com_xoff1 6 /* XOFF 1 character (R/W) */ #define com_xoff2 7 /* XOFF 2 character (R/W) */ #define com_usr 39 /* Octeon 16750/16550 Uart Status Reg */ #define REG_USR com_usr #define USR_TXFIFO_NOTFULL 2 /* Uart TX FIFO Not full */ /* 16950 register #1. Access enabled by ACR[7]. Also requires !LCR[7]. */ #define com_asr 1 /* additional status register (R[0-7]/W[0-1]) */ /* 16950 register #3. R/W access enabled by ACR[7]. */ #define com_rfl 3 /* receiver fifo level (R) */ /* * 16950 register #4. Access enabled by ACR[7]. Also requires * !LCR_EFR_ENABLE. */ #define com_tfl 4 /* transmitter fifo level (R) */ /* * 16950 register #5. Accessible if !LCR_EFR_ENABLE. Read access also * requires ACR[6]. */ #define com_icr 5 /* index control register (R/W) */ /* * 16950 register #7. It is the same as com_scr except it has a different * abbreviation in the manufacturer's data sheet and it also serves as an * index into the Indexed Control register set. */ #define com_spr com_scr /* scratch pad (and index) register (R/W) */ #define REG_SPR com_scr /* * 16950 indexed control registers #[0-0x13]. Access is via index in SPR, * data in ICR (if ICR is accessible). */ #define com_acr 0 /* additional control register (R/W) */ #define ACR_ASE 0x80 /* ASR/RFL/TFL enable */ #define ACR_ICRE 0x40 /* ICR enable */ #define ACR_TLE 0x20 /* TTL/RTL enable */ #define com_cpr 1 /* clock prescaler register (R/W) */ #define com_tcr 2 /* times clock register (R/W) */ #define com_ttl 4 /* transmitter trigger level (R/W) */ #define com_rtl 5 /* receiver trigger level (R/W) */ /* ... */ /* Hardware extension mode register for RSB-2000/3000. */ #define com_emr com_msr #define EMR_EXBUFF 0x04 #define EMR_CTSFLW 0x08 #define EMR_DSRFLW 0x10 #define EMR_RTSFLW 0x20 #define EMR_DTRFLW 0x40 #define EMR_EFMODE 0x80 /* com port */ #define COM1_ADDR 0x3f8 #define COM2_ADDR 0x2f8 #define COM3_ADDR 0x3e8 #define COM4_ADDR 0x2e8 #define GET_LCR_DATABIT(x) ({ \ typeof(x) val = 0; \ val = (((x) == 5) ? LCR_5BITS : (val)); \ val = (((x) == 6) ? LCR_6BITS : (val)); \ val = (((x) == 7) ? LCR_7BITS : (val)); \ val = (((x) == 8) ? LCR_8BITS : (val)); \ val; }) #define GET_LCR_STOPBIT(x) ({ \ typeof(x) val = 0; \ val = (((x) > 1) ? LCR_STOPB : val); \ val; }) #define GET_LCR_PARITY(x) ({ \ typeof(x) val = 0; \ val = (((x) == 'n') ? (!LCR_PENAB) : val); \ val = (((x) == 'o') ? LCR_ODD_PARITY : val); \ val = (((x) == 'e') ? LCR_EVEN_PARITY : val); \ val = (((x) == 'm') ? LCR_MARK_PARITY : val); \ val = (((x) == 's') ? LCR_SPACE_PARITY : val); \ val; }) #define GET_LCR_VALUE(data, stop, parity) \ (GET_LCR_DATABIT(data) | GET_LCR_STOPBIT(stop) | GET_LCR_PARITY(parity)) typedef struct __packed { uint32_t bus; uint32_t slot; uint32_t func; } bdf_t; typedef struct __packed { uint32_t comc_curspeed; /* baud rate */ uint32_t comc_clockhz; /* clock hz */ uint8_t comc_fmt; /* lcr value */ uint32_t comc_port; /* serial port, COM[1|2|3|4] */ uint32_t comc_irq; /* irq */ bdf_t comc_psbdf; /* PCI serial controller bdf */ bdf_t comc_pbbdf; /* PCI bridge bdf */ } serial_port_t; extern void comc_init(void); extern void comc_puts(const char*, unsigned int); #endif /* __COM_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/compiler.h0000644000000000000000000000367114210363175015621 0ustar 00000000000000/* * compiler.h: These are various compiler-related defines * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __COMPILER_H__ #define __COMPILER_H__ #define inline __inline__ #define always_inline __inline__ __attribute__ ((always_inline)) #endif /* __COMPILER_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/ctype.h0000644000000000000000000000614714210363175015134 0ustar 00000000000000/* * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __CTYPE_H__ #define __CTYPE_H__ #include #include #include /* from: * http://fxr.watson.org/fxr/source/dist/acpica/acutils.h?v=NETBSD5 */ extern const uint8_t _ctype[]; #define _XA 0x00 /* extra alphabetic - not supported */ #define _XS 0x40 /* extra space */ #define _BB 0x00 /* BEL, BS, etc. - not supported */ #define _CN 0x20 /* CR, FF, HT, NL, VT */ #define _DI 0x04 /* ''-'9' */ #define _LO 0x02 /* 'a'-'z' */ #define _PU 0x10 /* punctuation */ #define _SP 0x08 /* space */ #define _UP 0x01 /* 'A'-'Z' */ #define _XD 0x80 /* ''-'9', 'A'-'F', 'a'-'f' */ static always_inline bool isdigit(int c) { return (_ctype[(unsigned char)(c)] & (_DI)); } static always_inline bool isspace(int c) { return (_ctype[(unsigned char)(c)] & (_SP)); } static always_inline bool isxdigit(int c) { return (_ctype[(unsigned char)(c)] & (_XD)); } static always_inline bool isupper(int c) { return (_ctype[(unsigned char)(c)] & (_UP)); } static always_inline bool islower(int c) { return (_ctype[(unsigned char)(c)] & (_LO)); } static always_inline bool isprint(int c) { return (_ctype[(unsigned char)(c)] & (_LO | _UP | _DI | _SP | _PU)); } static always_inline bool isalpha(int c) { return (_ctype[(unsigned char)(c)] & (_LO | _UP)); } #endif /* __CTYPE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/e820.h0000644000000000000000000000642014210363175014460 0ustar 00000000000000/* * e820.h: support functions for manipulating the e820 table * * Copyright (c) 2006-2009, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __E820_H__ #define __E820_H__ #ifndef E820_RAM #define E820_RAM 1 #endif #ifndef E820_RESERVED #define E820_RESERVED 2 #endif #ifndef E820_ACPI #define E820_ACPI 3 #endif #ifndef E820_NVS #define E820_NVS 4 #endif #ifndef E820_UNUSABLE #define E820_UNUSABLE 5 #endif /* these are only used by e820_check_region() */ #define E820_MIXED ((uint32_t)-1 - 1) #define E820_GAP ((uint32_t)-1) #define E820MAX 128 typedef struct __packed { uint64_t addr; /* start of memory segment */ uint64_t size; /* size of memory segment */ uint32_t type; /* type of memory segment */ } e820entry_t; typedef struct { uint32_t type; uint32_t pad; uint64_t phys_addr; uint64_t virt_addr; uint64_t num_pages; uint64_t attribute; } efi_memory_desc_t; extern memory_map_t *get_e820_copy(void); extern unsigned int get_nr_map(void); extern bool copy_e820_map(loader_ctx *lctx); extern bool e820_protect_region(uint64_t addr, uint64_t size, uint32_t type); extern bool e820_reserve_ram(uint64_t base, uint64_t length); extern void print_e820_map(void); extern uint32_t e820_check_region(uint64_t base, uint64_t length); extern bool get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram, uint64_t *min_hi_ram, uint64_t *max_hi_ram); extern bool e820_get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size); #endif /* __E820_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/efi_memmap.h0000644000000000000000000001000514210363175016073 0ustar 00000000000000/* * efi_memmap.h: EFI memory map parsing functions * * Copyright (c) 2006-2020, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _EFI_MEMMAP_H_ #define _EFI_MEMMAP_H_ #include #include /* Memory types: */ #define EFI_RESERVED_TYPE 0 #define EFI_LOADER_CODE 1 #define EFI_LOADER_DATA 2 #define EFI_BOOT_SERVICES_CODE 3 #define EFI_BOOT_SERVICES_DATA 4 #define EFI_RUNTIME_SERVICES_CODE 5 #define EFI_RUNTIME_SERVICES_DATA 6 #define EFI_CONVENTIONAL_MEMORY 7 #define EFI_UNUSABLE_MEMORY 8 #define EFI_ACPI_RECLAIM_MEMORY 9 #define EFI_ACPI_MEMORY_NVS 10 #define EFI_MEMORY_MAPPED_IO 11 #define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 #define EFI_PAL_CODE 13 #define EFI_MAX_MEMORY_TYPE 14 /* Attribute values: */ #define EFI_MEMORY_UC ((u64)0x0000000000000001ULL) /* uncached */ #define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ #define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ #define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ #define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ #define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ #define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* requires runtime mapping */ #define EFI_MEMORY_DESCRIPTOR_VERSION 1 #define EFI_PAGE_SHIFT 12 #define EFI_MEMMAP_MAX_ENTRIES 682 /* limited by TBOOT_EFI_MEMMAP_COPY_SIZE */ typedef struct __packed { uint32_t size; uint32_t descr_size; uint8_t descr[0]; /**< array of efi_mem_descr_t, each element has descr_size bytes */ } efi_memmap_t; typedef struct __packed { uint32_t type; uint32_t padding; uint64_t physical_start; uint64_t virtual_start; uint64_t num_pages; uint64_t attribute; } efi_mem_descr_t; bool efi_memmap_copy(loader_ctx *lctx); uint32_t efi_memmap_get_addr(uint32_t *descr_size, uint32_t *descr_vers, uint32_t *mmap_size); efi_mem_descr_t* efi_memmap_walk(efi_mem_descr_t* prev); bool efi_memmap_is_free(uint32_t region_type); bool efi_memmap_reserve(uint64_t base, uint64_t length); bool efi_memmap_get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size); void efi_memmap_dump(void); #endiftboot-1.10.5/tboot/include/integrity.h0000644000000000000000000000645114210363175016024 0ustar 00000000000000/* * integrity.h: routines for memory integrity measurement & * verification. Memory integrity is protected with tpm seal * * Copyright (c) 2007-2009, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _TBOOT_INTEGRITY_H_ #define _TBOOT_INTEGRITY_H_ #include /* * state that must be saved across S3 and will be sealed for integrity * before extending PCRs and launching kernel */ #define MAX_VL_HASHES 32 #define MAX_ALG_NUM 5 typedef struct { uint16_t alg; tb_hash_t hash; } hash_entry_t; typedef struct { uint32_t count; hash_entry_t entries[MAX_ALG_NUM]; } hash_list_t; typedef struct { /* low and high memory regions to protect w/ VT-d PMRs */ uint64_t vtd_pmr_lo_base; uint64_t vtd_pmr_lo_size; uint64_t vtd_pmr_hi_base; uint64_t vtd_pmr_hi_size; /* VL policy at time of sealing */ tb_hash_t pol_hash; /* verified launch measurements to be re-extended in DRTM PCRs * a given PCR may have more than one hash and will get extended in the * order it appears in the list */ uint8_t num_vl_entries; struct { uint8_t pcr; hash_list_t hl; } vl_entries[MAX_VL_HASHES]; } pre_k_s3_state_t; /* * state that must be saved across S3 and will be sealed for integrity * just before entering S3 (after kernel shuts down) */ typedef struct { uint64_t kernel_s3_resume_vector; uint8_t kernel_integ[POLY1305_DIGEST_SIZE]; } post_k_s3_state_t; extern pre_k_s3_state_t g_pre_k_s3_state; extern post_k_s3_state_t g_post_k_s3_state; extern bool seal_pre_k_state(void); extern bool seal_post_k_state(void); extern bool verify_integrity(void); #endif /* _TBOOT_INTEGRITY_H_ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/io.h0000644000000000000000000000557414210363175014422 0ustar 00000000000000/*- * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * */ /* * Portions copyright (c) 2010, Intel Corporation */ #ifndef __IO_H__ #define __IO_H__ /* from: * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.158 2010/01/01 20:55:11 obrien Exp $ */ /* modified to use tboot's types */ #define readb(va) (*(volatile uint8_t *) (va)) #define readw(va) (*(volatile uint16_t *) (va)) #define readl(va) (*(volatile uint32_t *) (va)) #define writeb(va, d) (*(volatile uint8_t *) (va) = (d)) #define writew(va, d) (*(volatile uint16_t *) (va) = (d)) #define writel(va, d) (*(volatile uint32_t *) (va) = (d)) static inline uint8_t inb(uint16_t port) { uint8_t data; __asm volatile("inb %w1, %0" : "=a" (data) : "Nd" (port)); return (data); } static inline uint16_t inw(uint16_t port) { uint16_t data; __asm volatile("inw %w1, %0" : "=a" (data) : "Nd" (port)); return (data); } static inline uint32_t inl(uint16_t port) { uint32_t data; __asm volatile("inl %w1, %0" : "=a" (data) : "Nd" (port)); return (data); } static inline void outb(uint16_t port, uint8_t data) { __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); } static inline void outw(uint16_t port, uint16_t data) { __asm volatile("outw %0, %w1" : : "a" (data), "Nd" (port)); } static inline void outl(uint16_t port, uint32_t data) { __asm volatile("outl %0, %w1" : : "a" (data), "Nd" (port)); } #endif /* __IO_H__ */ tboot-1.10.5/tboot/include/linux_defns.h0000644000000000000000000002605614210363175016327 0ustar 00000000000000/* * linux_defns.h: Linux kernel type definitions * * Copyright (c) 2006-2009, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __LINUX_DEFNS_H__ #define __LINUX_DEFNS_H__ #define SECTOR_SIZE (1 << 9) /* 0x200 = 512B */ #define KERNEL_HEADER_OFFSET 0x1F1 /* linux kernel header */ typedef struct __attribute__ ((packed)) { uint8_t setup_sects; /* The size of the setup in sectors */ #define DEFAULT_SECTOR_NUM 4 /* default sector number 4 */ #define MAX_SECTOR_NUM 64 /* max sector number 64 */ uint16_t root_flags; /* If set, the root is mounted readonly */ uint32_t syssize; /* The size of the 32-bit code in 16-byte paras */ uint16_t ram_size; /* DO NOT USE - for bootsect.S use only */ uint16_t vid_mode; /* Video mode control */ uint16_t root_dev; /* Default root device number */ uint16_t boot_flag; /* 0xAA55 magic number */ uint16_t jump; /* Jump instruction */ uint32_t header; /* Magic signature "HdrS" */ #define HDRS_MAGIC 0x53726448 uint16_t version; /* Boot protocol version supported */ uint32_t realmode_swtch; /* Boot loader hook */ uint16_t start_sys; /* The load-low segment (0x1000) (obsolete) */ uint16_t kernel_version; /* Points to kernel version string */ uint8_t type_of_loader; /* Boot loader identifier */ #define LOADER_TYPE_LILO 0x01 #define LOADER_TYPE_LOADLIN 0x10 #define LOADER_TYPE_BOOTSECT_LOADER 0x20 #define LOADER_TYPE_SYSLINUX 0x30 #define LOADER_TYPE_ETHERBOOT 0x40 #define LOADER_TYPE_ELILO 0x50 #define LOADER_TYPE_GRUB 0x71 #define LOADER_TYPE_U_BOOT 0x80 #define LOADER_TYPE_XEN 0x90 #define LOADER_TYPE_UNKNOWN 0xFF uint8_t loadflags; /* Boot protocol option flags */ #define FLAG_LOAD_HIGH 0x01 #define FLAG_CAN_USE_HEAP 0x80 uint16_t setup_move_size;/* Move to high memory size (used with hooks) */ uint32_t code32_start; /* Boot loader hook */ uint32_t ramdisk_image; /* initrd load address (set by boot loader) */ uint32_t ramdisk_size; /* initrd size (set by boot loader) */ uint32_t bootsect_kludge;/* DO NOT USE - for bootsect.S use only */ uint16_t heap_end_ptr; /* Free memory after setup end */ uint8_t ext_loader_ver; /* Boot Protocol: 2.02+ */ uint8_t ext_loader_type;/* Boot Protocol: 2.02+ */ uint32_t cmd_line_ptr; /* 32-bit pointer to the kernel command line */ uint32_t initrd_addr_max;/* Highest legal initrd address */ uint32_t kernel_alignment; /* Physical addr alignment required for kernel */ uint8_t relocatable_kernel; /* Whether kernel is relocatable or not */ uint8_t min_alignment; /* Boot Protocol: 2.10+ */ uint16_t xloadflags; /* Boot Protocol: 2.12+ */ uint32_t cmdline_size; /* Maximum size of the kernel command line */ uint32_t hardware_subarch; /* Hardware subarchitecture */ uint64_t hardware_subarch_data; /* Subarchitecture-specific data */ uint32_t payload_offset; uint32_t payload_length; uint64_t setup_data; uint64_t pref_address; uint32_t init_size; uint32_t handover_offset; } linux_kernel_header_t; typedef struct __attribute__ ((packed)) { uint8_t screen_info[0x040-0x000]; /* 0x000 */ uint8_t apm_bios_info[0x054-0x040]; /* 0x040 */ uint8_t _pad2[4]; /* 0x054 */ uint8_t tboot_shared_addr[8]; /* 0x058 */ uint8_t ist_info[0x070-0x060]; /* 0x060 */ uint8_t _pad3[16]; /* 0x070 */ uint8_t hd0_info[16]; /* obsolete! */ /* 0x080 */ uint8_t hd1_info[16]; /* obsolete! */ /* 0x090 */ uint8_t sys_desc_table[0x0b0-0x0a0]; /* 0x0a0 */ uint8_t _pad4[144]; /* 0x0b0 */ uint8_t edid_info[0x1c0-0x140]; /* 0x140 */ uint8_t efi_info[0x1e0-0x1c0]; /* 0x1c0 */ uint8_t alt_mem_k[0x1e4-0x1e0]; /* 0x1e0 */ uint8_t scratch[0x1e8-0x1e4]; /* 0x1e4 */ uint8_t e820_entries; /* 0x1e8 */ uint8_t eddbuf_entries; /* 0x1e9 */ uint8_t edd_mbr_sig_buf_entries; /* 0x1ea */ uint8_t _pad6[6]; /* 0x1eb */ linux_kernel_header_t hdr; /* setup header */ /* 0x1f1 */ uint8_t _pad7[0x290-0x1f1-sizeof(linux_kernel_header_t)]; uint8_t edd_mbr_sig_buffer[0x2d0-0x290]; /* 0x290 */ e820entry_t e820_map[E820MAX]; /* 0x2d0 */ uint8_t _pad8[48]; /* 0xcd0 */ uint8_t eddbuf[0xeec-0xd00]; /* 0xd00 */ uint8_t _pad9[276]; /* 0xeec */ } boot_params_t; typedef struct __attribute__ ((packed)) { u8 orig_x; /* 0x00 */ u8 orig_y; /* 0x01 */ u16 ext_mem_k; /* extended memory size in kb */ /* 0x02 */ u16 orig_video_page; /* 0x04 */ u8 orig_video_mode; /* representing the specific mode that was in effect when booting */ /* 0x06 */ u8 orig_video_cols; /* 0x07 */ u16 unused2; /* 0x08 */ u16 orig_video_ega_bx; /* video state and installed memory */ /* 0x0a */ u16 unused3; /* 0x0c */ u8 orig_video_lines; /* 0x0e */ u8 orig_video_isVGA; /* distinguish between VGA text and vesa lfb based screen setups */ /* 0x0f */ u16 orig_video_points; /* font height */ /* 0x10 */ u16 lfb_width; /* 0x12 */ u16 lfb_height; /* 0x14 */ u16 lfb_depth; /* 0x16 */ u32 lfb_base; /* 0x18 */ u32 lfb_size; /* 0x1c */ u16 cl_magic; /* 0x20 */ u16 cl_offset; /* 0x22 */ u16 lfb_line_len; /* 0x24 */ u8 red_mask_size; /* 0x26 */ u8 red_field_pos; /* 0x27 */ u8 green_mask_size; /* 0x28 */ u8 green_field_pos; /* 0x29 */ u8 blue_mask_size; /* 0x2a */ u8 blue_field_pos; /* 0x2b */ u8 reserved_mask_size; /* 0x2c */ u8 reserved_field_pos; /* 0x2d */ u16 vesapm_segment; /* 0x2e */ u16 vesapm_offset; /* 0x30 */ u16 lfb_pages; /* 0x32 */ u16 vesa_attrib; /* 0x34 */ u32 capabilities; /* 0x36 */ #define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit. */ u32 ext_lfb_base; /* 0x3a */ /* padding out to 0x40 */ } screen_info_t; /* recommended layout | Protected-mode kernel | The kernel protected-mode code. 100000 +---------------------------+ | I/O memory hole | 0A0000 +---------------------------+ | Reserved for BIOS | Do not use. Reserved for BIOS EBDA. 099100 +---------------------------+ | cmdline | 099000 +---------------------------+ | Stack/heap | For use by the kernel real-mode code. 098000 +---------------------------+ | Kernel setup | The kernel real-mode code. 090200 +---------------------------+ | Kernel boot sector | The kernel legacy boot sector. 090000 +---------------------------+ | Boot loader | <- Boot sector entry point 0000:7C00 001000 +---------------------------+ | Reserved for MBR/BIOS | 000800 +---------------------------+ | Typically used by MBR | 000600 +---------------------------+ | BIOS use only | 000000 +---------------------------+ */ #define BZIMAGE_PROTECTED_START 0x100000 #define LEGACY_REAL_START 0x90000 #define REAL_KERNEL_OFFSET 0x0000 #define BOOT_SECTOR_OFFSET 0x0200 #define KERNEL_CMDLINE_OFFSET 0x8D00 #define REAL_END_OFFSET 0x9100 #define REAL_MODE_SIZE REAL_END_OFFSET - REAL_KERNEL_OFFSET struct efi_info { uint32_t efi_ldr_sig; uint32_t efi_systable; uint32_t efi_memdescr_size; uint32_t efi_memdescr_ver; uint32_t efi_memmap; uint32_t efi_memmap_size; uint32_t efi_systable_hi; uint32_t efi_memmap_hi; }; #endif /* __LINUX_DEFNS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/loader.h0000644000000000000000000001067014210363175015252 0ustar 00000000000000/* * loader.h: support functions for manipulating ELF and AOUT binaries * * Copyright (c) 2006-2013, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __LOADER_H__ #define __LOADER_H__ typedef struct { void *addr; uint32_t type; } loader_ctx; extern loader_ctx *g_ldr_ctx; #ifndef __MULTIBOOT_H__ /* a few useful utility types */ typedef struct { uint32_t mod_start; uint32_t mod_end; uint32_t string; uint32_t reserved; } module_t; typedef struct { uint32_t size; uint32_t base_addr_low; uint32_t base_addr_high; uint32_t length_low; uint32_t length_high; uint32_t type; } memory_map_t; #endif extern void print_loader_ctx(loader_ctx *lctx); extern bool find_module_by_uuid(loader_ctx *lctx, void **base, size_t *size, const uuid_t *uuid); extern bool find_module_by_file_signature(loader_ctx *lctx, void **base, size_t *size, const char* file_signature); extern bool find_platform_racm(loader_ctx *lctx, void **base, uint32_t *size); extern bool find_platform_sinit_module(loader_ctx *lctx, void **base, uint32_t *size); extern bool find_lcp_module(loader_ctx *lctx, void **base, uint32_t *size); extern bool is_kernel_linux(void); extern uint32_t find_efi_memmap(loader_ctx *lctx, uint32_t *descr_size, uint32_t *descr_vers, uint32_t *mmap_size); extern bool launch_kernel(bool is_measured_launch); extern bool verify_loader_context(loader_ctx *lctx); extern bool verify_modules(loader_ctx *lctx); extern module_t *get_module(loader_ctx *lctx, unsigned int i); extern unsigned int get_module_count(loader_ctx *lctx); extern bool remove_txt_modules(loader_ctx *lctx); extern bool have_loader_memlimits(loader_ctx *lctx); extern bool have_loader_memmap(loader_ctx *lctx); extern memory_map_t *get_loader_memmap(loader_ctx *lctx); extern uint32_t get_loader_memmap_length(loader_ctx *lctx); extern uint32_t get_loader_mem_lower(loader_ctx *lctx); extern uint32_t get_loader_mem_upper(loader_ctx *lctx); extern char *get_module_cmd(loader_ctx *lctx, module_t *mod); extern char *get_cmdline(loader_ctx *lctx); extern void determine_loader_type(void *addr, uint32_t magic); extern unsigned long get_loader_ctx_end(loader_ctx *lctx); extern void replace_e820_map(loader_ctx *lctx); extern uint8_t *get_loader_rsdp(loader_ctx *lctx, uint32_t *length); extern bool is_loader_launch_efi(loader_ctx *lctx); extern bool get_loader_efi_ptr(loader_ctx *lctx, uint32_t *address, uint64_t *long_address); extern bool load_framebuffer_info(loader_ctx *lctx, void *vscr, bool efifb); extern char *get_first_module_cmd(loader_ctx *lctx); extern struct mb2_fb* get_framebuffer_info(loader_ctx *lctx); #endif /* __LOADER_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/lz.h0000644000000000000000000000333114210363175014425 0ustar 00000000000000/************************************************************************* * Name: lz.h * Author: Marcus Geelnard * Description: LZ77 coder/decoder interface. * Reentrant: Yes *------------------------------------------------------------------------- * Copyright (c) 2003-2010 Marcus Geelnard * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would * be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * * Marcus Geelnard * marcus.geelnard at home.se *************************************************************************/ #ifndef _lz_h_ #define _lz_h_ #ifdef __cplusplus extern "C" { #endif /************************************************************************* * Function prototypes *************************************************************************/ int LZ_Compress( char *in, char *out, unsigned int insize, unsigned int outsize ); int LZ_Uncompress( char *in, char *out, unsigned int insize, unsigned int outsize ); #ifdef __cplusplus } #endif #endif /* _lz_h_ */ tboot-1.10.5/tboot/include/memlog.h0000644000000000000000000000347114210363175015265 0ustar 00000000000000/* * memlog.h: log messages to memory * * Copyright (c) 2006-2020, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __MEMLOG_H__ #define __MEMLOG_H__ #include void memlog_init(void); void memlog_write(const char *str, unsigned int count); void memlog_compress(uint32_t required_space); #endiftboot-1.10.5/tboot/include/misc.h0000644000000000000000000000607114210363175014737 0ustar 00000000000000/* * misc.h: miscellaneous support fns * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __MISC_H__ #define __MISC_H__ extern void print_hex(const char * buf, const void * prtptr, size_t size); extern void delay(int millisecs); /* * These three "plus overflow" functions take a "x" value * and add the "y" value to it and if the two values are * greater than the size of the variable type, they will * overflow the type and end up with a smaller value and * return TRUE - that they did overflow. i.e. * x + y <= variable type maximum. */ static inline bool plus_overflow_u64(uint64_t x, uint64_t y) { return ((((uint64_t)(~0)) - x) < y); } static inline bool plus_overflow_u32(uint32_t x, uint32_t y) { return ((((uint32_t)(~0)) - x) < y); } /* * This checks to see if two numbers multiplied together are larger * than the type that they are. Returns TRUE if OVERFLOWING. * If the first parameter "x" is greater than zero and * if that is true, that the largest possible value 0xFFFFFFFF / "x" * is less than the second parameter "y". If "y" is zero then * it will also fail because no unsigned number is less than zero. */ static inline bool multiply_overflow_u32(uint32_t x, uint32_t y) { return (x > 0) ? ((((uint32_t)(~0))/x) < y) : false; } #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define AP_WAKE_TRIGGER_DEF 0xffffffff #endif /* __MISC_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/msr.h0000644000000000000000000000757414210363175014616 0ustar 00000000000000/*- * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * */ /* * Portions copyright (c) 2010-2011, Intel Corporation */ #ifndef __MSR_H__ #define __MSR_H__ #ifndef __ASSEMBLY__ /* from: * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.155.2.3 2009/11/25 01:52:36 kmacy Exp $ */ static inline uint64_t rdmsr(uint32_t msr) { uint64_t rv; __asm__ __volatile__ ("rdmsr" : "=A" (rv) : "c" (msr)); return (rv); } static inline void wrmsr(uint32_t msr, uint64_t newval) { __asm__ __volatile__ ("wrmsr" : : "A" (newval), "c" (msr)); } #endif /* !__ASSEMBLY__ */ /* * from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91 * $FreeBSD: src/sys/i386/include/specialreg.h,v 1.53.2.1.2.2 2009/11/06 17:09:04 attilio Exp $ */ #define MSR_IA32_PLATFORM_ID 0x017 #define MSR_APICBASE 0x01b #define MSR_IA32_FEATURE_CONTROL 0x03a #define MSR_IA32_SMM_MONITOR_CTL 0x09b #define MSR_MTRRcap 0x0fe #define MSR_MCG_CAP 0x179 #define MSR_MCG_STATUS 0x17a #define MSR_IA32_MISC_ENABLE 0x1a0 #define MSR_IA32_MISC_ENABLE_MONITOR_FSM (1<<18) #define MSR_MTRRdefType 0x2ff #define MSR_MC0_STATUS 0x401 #define MSR_IA32_VMX_BASIC_MSR 0x480 #define MSR_IA32_VMX_PINBASED_CTLS_MSR 0x481 #define MSR_IA32_VMX_PROCBASED_CTLS_MSR 0x482 #define MSR_IA32_VMX_EXIT_CTLS_MSR 0x483 #define MSR_IA32_VMX_ENTRY_CTLS_MSR 0x484 #define MSR_IA32_SE_SVN_STATUS 0x500 /* * Constants related to MSR's. */ #define APICBASE_BSP 0x00000100 #define MSR_IA32_SMM_MONITOR_CTL_VALID 1 #define MSR_IA32_SMM_MONITOR_CTL_MSEG_BASE(x) (x>>12) /* MSRs & bits used for VMX enabling */ #define IA32_FEATURE_CONTROL_MSR_LOCK 0x1 #define IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX 0x2 #define IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL 0x7f00 #define IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER 0x8000 /* AMD64 MSR's */ #define MSR_EFER 0xc0000080 /* extended features */ /* EFER bits */ #define _EFER_LME 8 /* Long mode enable */ #define MTRR_TYPE_UNCACHABLE 0 #define MTRR_TYPE_WRTHROUGH 4 #define MTRR_TYPE_WRBACK 6 #endif /* __MSR_H__ */ tboot-1.10.5/tboot/include/multiboot.h0000644000000000000000000002332414210363175016022 0ustar 00000000000000/* * multiboot.h: definitions for the multiboot bootloader specification * * Copyright (c) 2013, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __MULTIBOOT_H__ #define __MULTIBOOT_H__ #include /* Multiboot2 tag alignment. */ #define MULTIBOOT2_TAG_ALIGN 8 /* Multiboot Header Definitions of OS image*/ #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 #define MULTIBOOT_HEADER_SEARCH_LIMIT 8192 /* Bit definitions of flags field of multiboot header*/ #define MULTIBOOT_HEADER_MODS_ALIGNED 0x1 #define MULTIBOOT_HEADER_WANT_MEMORY 0x2 /* bit definitions of flags field of multiboot information */ #define MBI_MEMLIMITS (1<<0) #define MBI_BOOTDEV (1<<1) #define MBI_CMDLINE (1<<2) #define MBI_MODULES (1<<3) #define MBI_AOUT (1<<4) #define MBI_ELF (1<<5) #define MBI_MEMMAP (1<<6) #define MBI_DRIVES (1<<7) #define MBI_CONFIG (1<<8) #define MBI_BTLDNAME (1<<9) #define MBI_APM (1<<10) #define MBI_VBE (1<<11) /* multiboot 2 constants */ #define MB2_HEADER_MAGIC 0xe85250d6 #define MB2_LOADER_MAGIC 0x36d76289 #define MB2_HEADER_SEARCH_LIMIT 32768 #define MB2_ARCH_X86 0 #define MB2_HDR_TAG_END 0 #define MB2_HDR_TAG_INFO_REQ 1 #define MB2_HDR_TAG_ADDR 2 #define MB2_HDR_TAG_ENTRY_ADDR 3 #define MB2_HDR_TAG_CONSOLE_FLAGS 4 #define MB2_HDR_TAG_FRAMEBUFFER 5 #define MB2_HDR_TAG_MOD_ALIGN 6 #define MB2_HDR_TAG_REQUIRED 0 #define MB2_HDR_TAG_OPTIONAL 1 #define MB2_CONS_FLAGS_CONS_REQ 1 #define MB2_CONS_FLAGS_EGA_TEXT_SUP 2 #define MB2_TAG_TYPE_END 0 #define MB2_TAG_TYPE_CMDLINE 1 #define MB2_TAG_TYPE_LOADER_NAME 2 #define MB2_TAG_TYPE_MODULE 3 #define MB2_TAG_TYPE_MEMLIMITS 4 #define MB2_TAG_TYPE_BOOTDEV 5 #define MB2_TAG_TYPE_MMAP 6 #define MB2_TAG_TYPE_VBE 7 #define MB2_TAG_TYPE_FRAMEBUFFER 8 #define MB2_TAG_TYPE_ELF_SECTIONS 9 #define MB2_TAG_TYPE_APM 10 #define MB2_TAG_TYPE_EFI32 11 #define MB2_TAG_TYPE_EFI64 12 #define MB2_TAG_TYPE_SMBIOS 13 #define MB2_TAG_TYPE_ACPI_OLD 14 #define MB2_TAG_TYPE_ACPI_NEW 15 #define MB2_TAG_TYPE_NETWORK 16 #define MB2_TAG_TYPE_EFI_MMAP 17 #define MB2_TAG_TYPE_EFI_BS 18 #ifndef __ASSEMBLY__ /* mb2 header flags */ struct mb2_hdr_tag_info_req { uint16_t type; uint16_t flags; uint32_t size; uint32_t requests[0]; }; struct mb2_hdr_tag_addr { uint16_t type; uint16_t flags; uint32_t size; uint32_t header_addr; uint32_t load_addr; uint32_t load_end_addr; uint32_t bss_end_addr; }; struct mb2_hdr_tag_entry_addr { uint16_t type; uint16_t flags; uint32_t size; uint32_t entry_addr; }; struct mb2_hdr_tag_console_flags { uint16_t type; uint16_t flags; uint32_t size; uint32_t console_flags; }; struct mb2_hdr_tag_framebuffer { uint16_t type; uint16_t flags; uint32_t size; uint32_t width; uint32_t height; uint32_t depth; }; struct mb2_hdr_tag_mod_align { uint16_t type; uint16_t flags; uint32_t size; uint32_t width; uint32_t height; uint32_t depth; }; /* MB2 info tags */ struct mb2_tag { uint32_t type; uint32_t size; }; struct mb2_tag_string { uint32_t type; uint32_t size; char string[0]; }; struct mb2_tag_memlimits { uint32_t type; uint32_t size; uint32_t mem_lower; uint32_t mem_upper; }; struct mb2_tag_bootdev { uint32_t type; uint32_t size; uint32_t biosdev; uint32_t slice; uint32_t part; }; struct mb2_mmap_entry { uint64_t addr; uint64_t len; #define MULTIBOOT_MEMORY_AVAILABLE 1 #define MULTIBOOT_MEMORY_RESERVED 2 #define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 #define MULTIBOOT_MEMORY_NVS 4 #define MULTIBOOT_MEMORY_BADRAM 5 uint32_t type; uint32_t zero; } __attribute__((packed)); struct mb2_tag_mmap { uint32_t type; uint32_t size; uint32_t entry_size; uint32_t entry_version; struct mb2_mmap_entry entries[0]; }; struct mb2_tag_module { uint32_t type; uint32_t size; uint32_t mod_start; uint32_t mod_end; char cmdline[0]; }; struct mb2_tag_old_acpi { uint32_t type; uint32_t size; uint8_t rsdp[0]; }; struct mb2_tag_new_acpi { uint32_t type; uint32_t size; uint8_t rsdp[0]; }; struct mb2_tag_efi32 { uint32_t type; uint32_t size; uint32_t pointer; }; struct mb2_tag_efi64 { uint32_t type; uint32_t size; uint64_t pointer; }; struct mb2_tag_network { uint32_t type; uint32_t size; uint8_t dhcpack[0]; }; struct mb2_tag_smbios { uint32_t type; uint32_t size; uint8_t major; uint8_t minor; uint8_t reserved[6]; uint8_t tables[0]; }; struct mb2_tag_elf_sections { uint32_t type; uint32_t size; uint32_t num; uint32_t entsize; uint32_t shndx; char sections[0]; }; struct mb2_tag_apm { uint32_t type; uint32_t size; uint16_t version; uint16_t cseg; uint32_t offset; uint16_t cseg_16; uint16_t dseg; uint16_t flags; uint16_t cseg_len; uint16_t cseg_16_len; uint16_t dseg_len; }; struct mb2_vbe_info_block { uint8_t external_specification[512]; }; struct mb2_vbe_mode_info_block { uint8_t external_specification[256]; }; struct mb2_tag_vbe { uint32_t type; uint32_t size; uint16_t vbe_mode; uint16_t vbe_interface_seg; uint16_t vbe_interface_off; uint16_t vbe_interface_len; struct mb2_vbe_info_block vbe_control_info; struct mb2_vbe_mode_info_block vbe_mode_info; }; struct mb2_tag_efi_mmap { uint32_t type; uint32_t size; uint32_t descr_size; uint32_t descr_vers; uint8_t efi_mmap[0]; }; struct mb2_fb_common { uint32_t type; uint32_t size; uint64_t fb_addr; uint32_t fb_pitch; uint32_t fb_width; uint32_t fb_height; uint8_t fb_bpp; #define MB2_FB_TYPE_INDEXED 0 #define MB2_FB_TYPE_RGB 1 #define MB2_FB_TYPE_EGA_TEXT 2 uint8_t fb_type; uint16_t reserved; }; struct mb2_color { uint8_t red; uint8_t green; uint8_t blue; }; struct mb2_fb { struct mb2_fb_common common; union { struct { uint16_t fb_palette_num_colors; struct mb2_color fb_palette[0]; }; struct { uint8_t fb_red_field_position; uint8_t fb_red_mask_size; uint8_t fb_green_field_position; uint8_t fb_green_mask_size; uint8_t fb_blue_field_position; uint8_t fb_blue_mask_size; }; }; }; /* MB1 */ typedef struct { uint32_t tabsize; uint32_t strsize; uint32_t addr; uint32_t reserved; } aout_t; /* a.out kernel image */ typedef struct { uint32_t num; uint32_t size; uint32_t addr; uint32_t shndx; } elf_t; /* elf kernel */ typedef struct { uint8_t bios_driver; uint8_t top_level_partition; uint8_t sub_partition; uint8_t third_partition; } boot_device_t; typedef struct { uint32_t flags; /* valid if flags[0] (MBI_MEMLIMITS) set */ uint32_t mem_lower; uint32_t mem_upper; /* valid if flags[1] set */ boot_device_t boot_device; /* valid if flags[2] (MBI_CMDLINE) set */ uint32_t cmdline; /* valid if flags[3] (MBI_MODS) set */ uint32_t mods_count; uint32_t mods_addr; /* valid if flags[4] or flags[5] set */ union { aout_t aout_image; elf_t elf_image; } syms; /* valid if flags[6] (MBI_MEMMAP) set */ uint32_t mmap_length; uint32_t mmap_addr; /* valid if flags[7] set */ uint32_t drives_length; uint32_t drives_addr; /* valid if flags[8] set */ uint32_t config_table; /* valid if flags[9] set */ uint32_t boot_loader_name; /* valid if flags[10] set */ uint32_t apm_table; /* valid if flags[11] set */ uint32_t vbe_control_info; uint32_t vbe_mode_info; uint16_t vbe_mode; uint16_t vbe_interface_seg; uint16_t vbe_interface_off; uint16_t vbe_interface_len; } multiboot_info_t; typedef struct { uint32_t mod_start; uint32_t mod_end; uint32_t string; uint32_t reserved; } module_t; typedef struct { uint32_t size; uint32_t base_addr_low; uint32_t base_addr_high; uint32_t length_low; uint32_t length_high; uint32_t type; } memory_map_t; #endif /* __ASSEMBLY__ */ #endif /* __MULTIBOOT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/mutex.h0000644000000000000000000000410414210363175015141 0ustar 00000000000000/* $OpenBSD: mutex.h,v 1.6 2009/04/27 21:48:56 kettenis Exp $ */ /* * Copyright (c) 2004 Artur Grabowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Portions copyright (c) 2010, Intel Corporation */ #ifndef __MUTEX_H__ #define __MUTEX_H__ /* * A mutex is: * - owned by a cpu. * - non-recursive. * - spinning. * - not providing mutual exclusion between processes, only cpus. * - providing interrupt blocking when necessary. * * Different mutexes can be nested, but not interleaved. This is ok: * "mtx_enter(foo); mtx_enter(bar); mtx_leave(bar); mtx_leave(foo);" * This is _not_ ok: * "mtx_enter(foo); mtx_enter(bar); mtx_leave(foo); mtx_leave(bar);" */ struct mutex { __volatile__ uint32_t mtx_lock; }; /* * Some architectures need to do magic for the ipl, so they need a macro. */ void mtx_init(struct mutex *); void mtx_enter(struct mutex *); void mtx_leave(struct mutex *); #endif /* __MUTEX_H__ */ tboot-1.10.5/tboot/include/page.h0000644000000000000000000000462414210363175014722 0ustar 00000000000000/* * page.h: definitions for page size/mask/shift/etc. * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __PAGE_H__ #define __PAGE_H__ /* From http://fxr.watson.org/fxr/source/i386/include/param.h */ #define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */ #define PAGE_SIZE (1 << PAGE_SHIFT) /* bytes/page */ /* PAGE_MASK is used to pass bits 12 and above. */ #define PAGE_MASK (~(PAGE_SIZE-1)) /* This is used to address the L2's 4MB pages */ /* From figure 4-3 of IA64/IA32 Arch SDM vol 3A */ #define FOURMB_PAGE_SHIFT 22 /* macros to rounds things up/down to a page */ #define PAGE_UP(p) (((unsigned long)(p) + PAGE_SIZE- 1) & PAGE_MASK) #define PAGE_DOWN(p) ((unsigned long)(p) & PAGE_MASK) #endif /* __PAGE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/paging.h0000644000000000000000000001030114210363175015240 0ustar 00000000000000/* * paging.h: Definitions for paging in tboot (PAE+PSE) * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __PAGING_H__ #define __PAGING_H__ /* direct map starts from 0, size 64M */ #define DIRECTMAP_VIRT_START 0 #define DIRECTMAP_VIRT_ORDER 26 #define DIRECTMAP_VIRT_SIZE (1UL << DIRECTMAP_VIRT_ORDER) #define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + DIRECTMAP_VIRT_SIZE) /* MAC window starts from 0x80000000, size 1G */ #define MAC_VIRT_START 0x80000000 #define MAC_VIRT_ORDER 30 #define MAC_VIRT_SIZE (1UL << MAC_VIRT_ORDER) #define MAC_VIRT_END (MAC_VIRT_START + MAC_VIRT_SIZE) /* PAE with 2-Mbyte Pages */ #define TB_PAGETABLE_ORDER 9 #define TB_L1_PAGETABLE_ENTRIES (1 << TB_PAGETABLE_ORDER) #define TB_L2_PAGETABLE_ENTRIES (1 << TB_PAGETABLE_ORDER) #define TB_L1_PAGETABLE_SHIFT 21 #define TB_L2_PAGETABLE_SHIFT 30 #define MAC_PAGE_SIZE (1UL << TB_L1_PAGETABLE_SHIFT) #define MAC_PAGE_MASK (~(MAC_PAGE_SIZE - 1)) #define _PAGE_PRESENT 0x01 #define _PAGE_RW 0x02 #define _PAGE_SIZE 0x80 #define MAKE_TB_PDE(paddr) \ (((uint64_t)(paddr) & ~0x00000000001FFFFF) | _PAGE_PRESENT \ | _PAGE_RW | _PAGE_SIZE) #define MAKE_TB_PDPTE(paddr) \ (((uint64_t)(paddr) & ~0x0000000000000FFF) | _PAGE_PRESENT) /* Given a virtual address, get an entry offset into a page table. */ #define pd_table_offset(a) \ (((a) >> TB_L1_PAGETABLE_SHIFT) & (TB_L1_PAGETABLE_ENTRIES - 1)) #define pdptr_table_offset(a) \ (((a) >> TB_L2_PAGETABLE_SHIFT) & (TB_L2_PAGETABLE_ENTRIES - 1)) /* PAE: 52 bit physical address */ #define PADDR_BIT 52 #define PADDR_MASK ((1ULL << PADDR_BIT) - 1) /* * PDE entry * 31-bit pfn = pde[51:21] * 13-bit flags = pde[12:0] */ #define PDE_FLAG_BIT 13 #define PDE_FLAG_MASK ((1UL << PDE_FLAG_BIT) - 1) #define PDE_PADDR_MASK (PADDR_MASK & (~PDE_FLAG_MASK)) #define get_pde_flags(pde) ((int)(pde) & PDE_FLAG_MASK) #define get_pde_paddr(pde) ((pde) & PDE_PADDR_MASK) /* * PDPTE entry * 40-bit pfn = pdptre[51:12] * 12-bit flags = pdptre[11:0] */ #define PDPTE_FLAG_BIT 12 #define PDPTE_FLAG_MASK ((1UL << PDPTE_FLAG_BIT) - 1) #define PDPTE_PADDR_MASK (PADDR_MASK & (~PDPTE_FLAG_MASK)) #define get_pdptre_flags(pdptre) ((int)(pdptre) & PDPTE_FLAG_MASK) #define get_pdptre_paddr(pdptre) ((pdptre) & PDPTE_PADDR_MASK) void map_pages_to_tboot(unsigned long vstart, unsigned long pfn, unsigned long nr_pfns); void destroy_tboot_mapping(unsigned long vstart, unsigned long vend); bool enable_paging(void); bool disable_paging(void); #endif /* __PAGING_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/pci_cfgreg.h0000644000000000000000000000527614210363175016102 0ustar 00000000000000/* * Copyright (c) 1997, Stefan Esser * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.15.2.1.4.1 2010/06/14 02:09:06 kensmith Exp $ * $FreeBSD: src/sys/dev/pci/pcireg.h,v 1.72.2.4.2.1 2010/06/14 02:09:06 kensmith Exp $ */ /* * Portions copyright (c) 2010, Intel Corporation */ #ifndef __PCI_CFGREG_H__ #define __PCI_CFGREG_H__ #define PCI_BUSMAX 255 /* highest supported bus number */ #define PCI_SLOTMAX 31 /* highest supported slot number */ #define PCI_FUNCMAX 7 /* highest supported function number */ #define PCI_REGMAX 255 /* highest supported config register addr. */ #define CONF1_ADDR_PORT 0x0cf8 #define CONF1_DATA_PORT 0x0cfc #define CONF1_ENABLE 0x80000000ul #define CONF1_ENABLE_CHK 0x80000000ul #define CONF1_ENABLE_MSK 0x7f000000ul #define CONF1_ENABLE_CHK1 0xff000001ul #define CONF1_ENABLE_MSK1 0x80000001ul #define CONF1_ENABLE_RES1 0x80000000ul #define CONF2_ENABLE_PORT 0x0cf8 #define CONF2_FORWARD_PORT 0x0cfa #define CONF2_ENABLE_CHK 0x0e #define CONF2_ENABLE_RES 0x0e #define PCIR_COMMAND 0x04 #define PCIR_BARS 0x10 #define PCIR_IOBASEL_1 0x1c int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes); void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes); #endif /* __PCI_CFGREG_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/poly1305.h0000644000000000000000000000271414210363175015300 0ustar 00000000000000/* * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #ifndef POLY1305_H #define POLY1305_H #define POLY1305_BLOCK_SIZE 16 #define POLY1305_DIGEST_SIZE 16 #define POLY1305_KEY_SIZE 32 typedef struct poly1305_context POLY1305; typedef void (*poly1305_blocks_f) (void *ctx, const unsigned char *inp, size_t len, unsigned int padbit); typedef void (*poly1305_emit_f) (void *ctx, unsigned char mac[16], const unsigned int nonce[4]); struct poly1305_context { double opaque[24]; /* large enough to hold internal state, declared * 'double' to ensure at least 64-bit invariant * alignment across all platforms and * configurations */ unsigned int nonce[4]; unsigned char data[POLY1305_BLOCK_SIZE]; size_t num; struct { poly1305_blocks_f blocks; poly1305_emit_f emit; } func; }; size_t Poly1305_ctx_size(void); void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32]); void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len); void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16]); #endiftboot-1.10.5/tboot/include/printk.h0000644000000000000000000000503014210363175015305 0ustar 00000000000000/* * printk.h: printk to serial for very early boot stages * * Copyright (c) 2006-2010, Intel Corporation * * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __PRINTK_H__ #define __PRINTK_H__ #include #include #define TBOOT_LOG_LEVEL_NONE 0x00 #define TBOOT_LOG_LEVEL_ERR 0x01 #define TBOOT_LOG_LEVEL_WARN 0x02 #define TBOOT_LOG_LEVEL_INFO 0x04 #define TBOOT_LOG_LEVEL_DETA 0x08 #define TBOOT_LOG_LEVEL_ALL 0xFF #define TBOOT_LOG_TARGET_NONE 0x00 #define TBOOT_LOG_TARGET_VGA 0x01 #define TBOOT_LOG_TARGET_SERIAL 0x02 #define TBOOT_LOG_TARGET_MEMORY 0x04 extern uint8_t g_log_level; extern uint8_t g_log_targets; extern uint8_t g_vga_delay; extern serial_port_t g_com_port; #define serial_init() comc_init() #define serial_write(s, n) comc_puts(s, n) #define vga_write(s,n) vga_puts(s, n) extern void printk_init(bool force_vga_off); extern void printk_disable_vga(void); extern void printk_flush(void); extern void printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); #endif tboot-1.10.5/tboot/include/processor.h0000644000000000000000000002154714210363175016030 0ustar 00000000000000/* Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * */ /* * Portions copyright (c) 2010, Intel Corporation */ #ifndef __PROCESSOR_H__ #define __PROCESSOR_H__ /* from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91 * $FreeBSD: stable/8/sys/i386/include/specialreg.h 198989 2009-11-06 15:24:48Z attilio $ */ /* * EFLAGS bits */ #define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ #define X86_EFLAGS_PF 0x00000004 /* Parity Flag */ #define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */ #define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ #define X86_EFLAGS_SF 0x00000080 /* Sign Flag */ #define X86_EFLAGS_TF 0x00000100 /* Trap Flag */ #define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */ #define X86_EFLAGS_DF 0x00000400 /* Direction Flag */ #define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */ #define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */ #define X86_EFLAGS_NT 0x00004000 /* Nested Task */ #define X86_EFLAGS_RF 0x00010000 /* Resume Flag */ #define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */ #define X86_EFLAGS_AC 0x00040000 /* Alignment Check */ #define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */ #define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ #define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ /* * Bits in 386 special registers: */ #define CR0_PE 0x00000001 /* Protected mode Enable */ #define CR0_MP 0x00000002 /* "Math" (fpu) Present */ #define CR0_EM 0x00000004 /* EMulate FPU instructions. (trap ESC only) */ #define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */ #define CR0_PG 0x80000000 /* PaGing enable */ /* * Bits in 486 special registers: */ #define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ #define CR0_WP 0x00010000 /* Write Protect (honor page protect in all modes) */ #define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */ #define CR0_NW 0x20000000 /* Not Write-through */ #define CR0_CD 0x40000000 /* Cache Disable */ /* * Bits in PPro special registers */ #define CR4_VME 0x00000001 /* Virtual 8086 mode extensions */ #define CR4_PVI 0x00000002 /* Protected-mode virtual interrupts */ #define CR4_TSD 0x00000004 /* Time stamp disable */ #define CR4_DE 0x00000008 /* Debugging extensions */ #define CR4_PSE 0x00000010 /* Page size extensions */ #define CR4_PAE 0x00000020 /* Physical address extension */ #define CR4_MCE 0x00000040 /* Machine check enable */ #define CR4_PGE 0x00000080 /* Page global enable */ #define CR4_PCE 0x00000100 /* Performance monitoring counter enable */ #define CR4_FXSR 0x00000200/* Fast FPU save/restore used by OS */ #define CR4_XMM 0x00000400 /* enable SIMD/MMX2 to use except 16 */ #define CR4_VMXE 0x00002000/* enable VMX */ #define CR4_SMXE 0x00004000/* enable SMX */ #define CR4_PCIDE 0x00020000/* enable PCID */ #ifndef __ASSEMBLY__ static inline void sse_enable(void) { asm volatile ( "mov %cr0, %eax \n" "and $0xFFFB, %ax \n" "or $0x2, %ax \n" "mov %eax, %cr0 \n" "mov %cr4, %eax \n" "or $(3 << 9), %ax \n" "mov %eax, %cr4" ); } /* from: * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.158 2010/01/01 20:55:11 obrien Exp $ */ static inline void do_cpuid(unsigned int ax, uint32_t *p) { __asm__ __volatile__ ("cpuid" : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) : "0" (ax)); } static inline void do_cpuid1(unsigned int ax, unsigned int cx, uint32_t *p) { __asm__ __volatile__ ("cpuid" : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) : "0" (ax), "c" (cx)); } static always_inline uint32_t cpuid_eax(unsigned int op) { /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */ uint32_t regs[4]; do_cpuid(op, regs); return regs[0]; } static always_inline uint32_t cpuid_ebx(unsigned int op) { /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */ uint32_t regs[4]; do_cpuid(op, regs); return regs[1]; } static always_inline uint32_t cpuid_ebx1(unsigned int op1, unsigned int op2) { /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */ uint32_t regs[4]; do_cpuid1(op1, op2, regs); return regs[1]; } static always_inline uint32_t cpuid_ecx(unsigned int op) { /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */ uint32_t regs[4]; do_cpuid(op, regs); return regs[2]; } static always_inline uint32_t cpuid_edx(unsigned int op) { /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */ uint32_t regs[4]; do_cpuid(op, regs); return regs[3]; } #define CPUID_X86_FEATURE_XMM3 (1<<0) #define CPUID_X86_FEATURE_VMX (1<<5) #define CPUID_X86_FEATURE_SMX (1<<6) static inline unsigned long read_cr0(void) { unsigned long data; __asm__ __volatile__ ("movl %%cr0,%0" : "=r" (data)); return (data); } static inline void write_ecx(unsigned long data) { __asm__ __volatile__("movl %0,%%ecx" : : "r" (data)); } static inline unsigned long read_ecx(void) { unsigned long data; __asm__ __volatile__ ("movl %%ecx,%0" : "=r" (data)); return (data); } static inline void write_cr0(unsigned long data) { __asm__ __volatile__("movl %0,%%cr0" : : "r" (data)); } static inline unsigned long read_cr4(void) { unsigned long data; __asm__ __volatile__ ("movl %%cr4,%0" : "=r" (data)); return (data); } static inline void write_cr4(unsigned long data) { __asm__ __volatile__ ("movl %0,%%cr4" : : "r" (data)); } static inline unsigned long read_cr3(void) { unsigned long data; __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (data)); return (data); } static inline void write_cr3(unsigned long data) { __asm__ __volatile__("movl %0,%%cr3" : : "r" (data) : "memory"); } static inline uint32_t read_eflags(void) { uint32_t ef; __asm__ __volatile__ ("pushfl; popl %0" : "=r" (ef)); return (ef); } static inline void write_eflags(uint32_t ef) { __asm__ __volatile__ ("pushl %0; popfl" : : "r" (ef)); } static inline void disable_intr(void) { __asm__ __volatile__ ("cli" : : : "memory"); } static inline void enable_intr(void) { __asm__ __volatile__ ("sti"); } /* was ia32_pause() */ static inline void cpu_relax(void) { __asm__ __volatile__ ("pause"); } static inline void halt(void) { __asm__ __volatile__ ("hlt"); } static inline unsigned int get_apicid(void) { return cpuid_edx(0xb); } static inline uint64_t rdtsc(void) { uint64_t rv; __asm__ __volatile__ ("rdtsc" : "=A" (rv)); return (rv); } static inline void wbinvd(void) { __asm__ __volatile__ ("wbinvd"); } static inline uint32_t bsrl(uint32_t mask) { uint32_t result; __asm__ __volatile__ ("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc"); return (result); } static inline int fls(int mask) { return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); } static always_inline void mb(void) { __asm__ __volatile__ ("lock;addl $0,0(%%esp)" : : : "memory"); } static inline void cpu_monitor(const void *addr, int extensions, int hints) { __asm __volatile__ ("monitor;" : :"a" (addr), "c" (extensions), "d"(hints)); } static inline void cpu_mwait(int extensions, int hints) { __asm __volatile__ ("mwait;" : :"a" (hints), "c" (extensions)); } #endif /* __ASSEMBLY__ */ #endif /* __PROCESSOR_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/sha1.h0000644000000000000000000000550714210363175014643 0ustar 00000000000000/*$FreeBSD: src/sys/crypto/sha1.h,v 1.8.36.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */ /*$KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the 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 PROJECT 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 PROJECT 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. */ /* * Portions copyright (c) 2010, Intel Corporation */ /* * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) * based on: http://csrc.nist.gov/fips/fip180-1.txt * implemented by Jun-ichiro itojun Itoh */ #ifndef __SHA1_H__ #define __SHA1_H__ struct sha1_ctxt { union { uint8_t b8[20]; uint32_t b32[5]; } h; union { uint8_t b8[8]; uint64_t b64[1]; } c; union { uint8_t b8[64]; uint32_t b32[16]; } m; uint8_t count; }; extern void sha1_init(struct sha1_ctxt *); extern void sha1_pad(struct sha1_ctxt *); extern void sha1_loop(struct sha1_ctxt *, const uint8_t *, size_t); extern void sha1_result(struct sha1_ctxt *, unsigned char *); #define SHA1_RESULTLEN (160/8) /* compatibilty with other SHA1 source codes */ typedef struct sha1_ctxt SHA_CTX; #define SHA1_Init(x) sha1_init((x)) #define SHA1_Update(x, y, z) sha1_loop((x), (y), (z)) #define SHA1_Final(x, y) sha1_result((y), (x)) #define SHA_DIGEST_LENGTH SHA1_RESULTLEN int sha1_buffer(const unsigned char *buffer, size_t len, unsigned char md[SHA_DIGEST_LENGTH]); #endif /* __SHA1_H__ */ tboot-1.10.5/tboot/include/sha2.h0000644000000000000000000000555114210363175014643 0ustar 00000000000000/* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. */ #ifndef __SHA2_H__ #define __SHA2_H__ #include #define SHA256_BLOCK_SIZE 64 #define SHA512_BLOCK_SIZE 128 #define MIN(x, y) ( ((x)<(y))?(x):(y) ) #define CONST64(n) n ## ULL #define STORE64H(x, y) \ do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while (0) #define LOAD64H(x, y) \ do { x = (((u64)((y)[0] & 255))<<56)|(((u64)((y)[1] & 255))<<48) | \ (((u64)((y)[2] & 255))<<40)|(((u64)((y)[3] & 255))<<32) | \ (((u64)((y)[4] & 255))<<24)|(((u64)((y)[5] & 255))<<16) | \ (((u64)((y)[6] & 255))<<8)|(((u64)((y)[7] & 255))); } while(0) #define STORE32H(x, y) \ do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while (0) #define LOAD32H(x, y) \ do { x = ((u32)((y)[0] & 255)<<24) | \ ((u32)((y)[1] & 255)<<16) | \ ((u32)((y)[2] & 255)<<8) | \ ((u32)((y)[3] & 255)); } while (0) struct sha512_state { u64 length, state[8]; u32 curlen; unsigned char buf[128]; }; struct sha256_state { u64 length; u32 state[8], curlen; unsigned char buf[64]; }; typedef union Hash_state { char dummy[1]; struct sha512_state sha512; struct sha256_state sha256; void *data; } hash_state; /* SHA 256 */ int sha256_init(hash_state * md); int sha256_process(hash_state * md, const unsigned char *in, u32 inlen); int sha256_done(hash_state * md, unsigned char *out); int sha256_buffer(const unsigned char *buffer, size_t len, unsigned char hash[32]); /* SHA 384 */ int sha384_init(hash_state * md); #define sha384_process sha512_process int sha384_done(hash_state * md, unsigned char *out); int sha384_buffer(const unsigned char *buffer, size_t len, unsigned char hash[48]); /* SHA 512 */ int sha512_init(hash_state * md); int sha512_process(hash_state * md, const unsigned char *in, u32 inlen); int sha512_done(hash_state * md, unsigned char *out); int sha512_buffer(const unsigned char *buffer, size_t len, unsigned char hash[64]); #endif /* __SHA2_H__ */tboot-1.10.5/tboot/include/string.h0000644000000000000000000000531714210363175015314 0ustar 00000000000000/*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * * @(#)libkern.h 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/sys/libkern.h,v 1.60 2009/02/14 11:34:57 rrs Exp $ */ /* * Portions copyright (c) 2010-2018, Intel Corporation */ #ifndef __STRING_H__ #define __STRING_H__ #include #include int tb_memcmp(const void *b1, const void *b2, size_t len); char *tb_index(const char *, int); int tb_strcmp(const char *, const char *); size_t tb_strlen(const char *); int tb_strncmp(const char *, const char *, size_t); char *tb_strncpy(char * __restrict, const char * __restrict, size_t); void *tb_memcpy(void *dst, const void *src, size_t len); int tb_snprintf(char *buf, size_t size, const char *fmt, ...); int tb_vscnprintf(char *buf, size_t size, const char *fmt, va_list ap); unsigned long tb_strtoul(const char *nptr, char **endptr, int base); static inline void *tb_memset(void *b, int c, size_t len) { char *bb; for (bb = (char *)b; len--; ) *bb++ = c; return (b); } static inline void *tb_memmove(void *dest, const void *src, size_t n) { return tb_memcpy(dest, src, n); } static __inline char *tb_strchr(const char *p, int ch) { return tb_index(p, ch); } #endif /* __STRING_H__ */ tboot-1.10.5/tboot/include/tpm.h0000644000000000000000000004303414210363175014604 0ustar 00000000000000/* * tpm.h: TPM-related support functions * * Copyright (c) 2006-2009, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TPM_H__ #define __TPM_H__ #include #include #include #include /* un-comment to enable detailed command tracing */ //#define TPM_TRACE #define TPM_IF_12 0 #define TPM_IF_20_FIFO 1 #define TPM_IF_20_CRB 2 #define TPM_VER_UNKNOWN 0 #define TPM_VER_12 1 #define TPM_VER_20 2 #define TPM_INTERFACE_ID_FIFO_20 0x0 #define TPM_INTERFACE_ID_CRB 0x1 #define TPM_INTERFACE_ID_FIFO_13 0xF #define TPM_LOCALITY_BASE 0xfed40000 #define TPM_LOCALITY_0 TPM_LOCALITY_BASE #define TPM_LOCALITY_1 (TPM_LOCALITY_BASE | 0x1000) #define TPM_LOCALITY_2 (TPM_LOCALITY_BASE | 0x2000) #define TPM_LOCALITY_3 (TPM_LOCALITY_BASE | 0x3000) #define TPM_LOCALITY_4 (TPM_LOCALITY_BASE | 0x4000) #define TPM_LOCALITY_BASE_N(n) (TPM_LOCALITY_BASE | ((n) << 12)) #define TPM_NR_LOCALITIES 5 #define NR_TPM_LOCALITY_PAGES ((TPM_LOCALITY_1 - TPM_LOCALITY_0) >> PAGE_SHIFT) #define TPM_LOCALITY_CRB_BASE 0xfed40000 #define TPM_LOCALITY_CRB_0 TPM_LOCALITY_CRB_BASE #define TPM_LOCALITY_CRB_1 (TPM_LOCALITY_CRB_BASE | 0x1000) #define TPM_LOCALITY_CRB_2 (TPM_LOCALITY_CRB_BASE | 0x2000) #define TPM_LOCALITY_CRB_3 (TPM_LOCALITY_CRB_BASE | 0x3000) #define TPM_LOCALITY_CRB_4 (TPM_LOCALITY_CRB_BASE | 0x4000) #define TPM_LOCALITY_CRB_BASE_N(n) (TPM_LOCALITY_CRB_BASE | ((n) << 12)) #define TPM_NR_CRB_LOCALITIES 5 #define NR_TPM_LOCALITY_CRB_PAGES ((TPM_LOCALITY_CRB_1 - TPM_LOCALITY_CRB_0) >> PAGE_SHIFT) /* * Command Header Fields: * 0 1 2 3 4 5 6 7 8 9 10 ... * ------------------------------------------------------------- * | TAG | SIZE | COMMAND CODE | other ... * ------------------------------------------------------------- * * Response Header Fields: * 0 1 2 3 4 5 6 7 8 9 10 ... * ------------------------------------------------------------- * | TAG | SIZE | RETURN CODE | other ... * ------------------------------------------------------------- */ #define CMD_HEAD_SIZE 10 #define RSP_HEAD_SIZE 10 #define CMD_SIZE_OFFSET 2 #define CMD_CC_OFFSET 6 #define RSP_SIZE_OFFSET 2 #define RSP_RST_OFFSET 6 /* * The term timeout applies to timings between various states * or transitions within the interface protocol. */ #define TIMEOUT_UNIT (0x100000 / 330) /* ~1ms, 1 tpm r/w need > 330ns */ #define TIMEOUT_A 750 /* 750ms */ #define TIMEOUT_B 2000 /* 2s */ #define TIMEOUT_C 75000 /* 750ms */ #define TIMEOUT_D 750 /* 750ms */ typedef struct __packed { uint32_t timeout_a; uint32_t timeout_b; uint32_t timeout_c; uint32_t timeout_d; } tpm_timeout_t; /* * The TCG maintains a registry of all algorithms that have an * assigned algorithm ID. That registry is the definitive list * of algorithms that may be supported by a TPM. */ #define TPM_ALG_ERROR 0x0000 #define TPM_ALG_FIRST 0x0001 #define TPM_ALG_RSA 0x0001 #define TPM_ALG_DES 0x0002 #define TPM_ALG__3DES 0x0003 #define TPM_ALG_SHA 0x0004 #define TPM_ALG_SHA1 0x0004 #define TPM_ALG_HMAC 0x0005 #define TPM_ALG_AES 0x0006 #define TPM_ALG_MGF1 0x0007 #define TPM_ALG_KEYEDHASH 0x0008 #define TPM_ALG_XOR 0x000A #define TPM_ALG_SHA256 0x000B #define TPM_ALG_SHA384 0x000C #define TPM_ALG_SHA512 0x000D #define TPM_ALG_WHIRLPOOL512 0x000E #define TPM_ALG_NULL 0x0010 #define TPM_ALG_SM3_256 0x0012 #define TPM_ALG_SM4 0x0013 #define TPM_ALG_RSASSA 0x0014 #define TPM_ALG_RSAES 0x0015 #define TPM_ALG_RSAPSS 0x0016 #define TPM_ALG_OAEP 0x0017 #define TPM_ALG_ECDSA 0x0018 #define TPM_ALG_ECDH 0x0019 #define TPM_ALG_ECDAA 0x001A #define TPM_ALG_SM2 0x001B #define TPM_ALG_ECSCHNORR 0x001C #define TPM_ALG_KDF1_SP800_56a 0x0020 #define TPM_ALG_KDF2 0x0021 #define TPM_ALG_KDF1_SP800_108 0x0022 #define TPM_ALG_ECC 0x0023 #define TPM_ALG_SYMCIPHER 0x0025 #define TPM_ALG_CTR 0x0040 #define TPM_ALG_OFB 0x0041 #define TPM_ALG_CBC 0x0042 #define TPM_ALG_CFB 0x0043 #define TPM_ALG_ECB 0x0044 #define TPM_ALG_LAST 0x0044 #define TPM_ALG_MAX_NUM (TPM_ALG_LAST - TPM_ALG_ERROR) // move from tpm.c /* * TPM registers and data structures * * register values are offsets from each locality base * see {read,write}_tpm_reg() for data struct format */ /* TPM_ACCESS_x */ #define TPM_REG_ACCESS 0x00 #define TPM_REG_STS 0x18 typedef union { u8 _raw[1]; /* 1-byte reg */ struct __packed { u8 tpm_establishment : 1; /* RO, 0=T/OS has been established before */ u8 request_use : 1; /* RW, 1=locality is requesting TPM use */ u8 pending_request : 1; /* RO, 1=other locality is requesting TPM usage */ u8 seize : 1; /* WO, 1=seize locality */ u8 been_seized : 1; /* RW, 1=locality seized while active */ u8 active_locality : 1; /* RW, 1=locality is active */ u8 reserved : 1; u8 tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */ }; } tpm_reg_access_t; /* TPM_STS_x */ typedef union { u8 _raw[3]; /* 3-byte reg */ struct __packed { u8 reserved1 : 1; u8 response_retry : 1; /* WO, 1=re-send response */ u8 self_test_done : 1; /* RO, only for version 2 */ u8 expect : 1; /* RO, 1=more data for command expected */ u8 data_avail : 1; /* RO, 0=no more data for response */ u8 tpm_go : 1; /* WO, 1=execute sent command */ u8 command_ready : 1; /* RW, 1=TPM ready to receive new cmd */ u8 sts_valid : 1; /* RO, 1=data_avail and expect bits are valid */ u16 burst_count : 16; /* RO, # read/writes bytes before wait */ }; } tpm12_reg_sts_t; typedef union { u8 _raw[4]; /* 4-byte reg */ struct __packed { u8 reserved1 : 1; u8 response_retry : 1; /* WO, 1=re-send response */ u8 self_test_done : 1; /* RO, only for version 2 */ u8 expect : 1; /* RO, 1=more data for command expected */ u8 data_avail : 1; /* RO, 0=no more data for response */ u8 tpm_go : 1; /* WO, 1=execute sent command */ u8 command_ready : 1; /* RW, 1=TPM ready to receive new cmd */ u8 sts_valid : 1; /* RO, 1=data_avail and expect bits are valid */ u16 burst_count : 16; /* RO, # read/writes bytes before wait */ /* version >= 2 */ u8 command_cancel : 1; u8 reset_establishment : 1; u8 tpm_family : 2; u8 reserved2 : 4; }; } tpm20_reg_sts_t; //----------------------------------------------------------------------------- // CRB I/F related definitions, see TCG PC Client Platform TPM Profile (PTP) Specification, Level 00 Revision 00.43 //----------------------------------------------------------------------------- #define TPM_REG_LOC_STATE 0x00 #define TPM_REG_LOC_CTRL 0x8 #define TPM_LOCALITY_STS 0x0C #define TPM_INTERFACE_ID 0x30 #define TPM_CONTROL_AREA 0x40 #define TPM_CRB_CTRL_REQ 0x40 #define TPM_CRB_CTRL_STS 0x44 #define TPM_CRB_CTRL_CANCEL 0x48 #define TPM_CRB_CTRL_START 0x4C #define TPM_CRB_CTRL_CMD_SIZE 0x58 #define TPM_CRB_CTRL_CMD_ADDR 0x5C #define TPM_CRB_CTRL_CMD_HADDR 0x60 #define TPM_CRB_CTRL_RSP_SIZE 0x64 #define TPM_CRB_CTRL_RSP_ADDR 0x68 #define TPM_CRB_DATA_BUFFER 0x80 #define TPMCRBBUF_LEN 0xF80 //3968 Bytes //#define CTRL_AREA_ADDR (uint32_t) (TPM_CRB_BASE + 0x40) //#define DATA_BUF_ADDR (uint32_t) (TPM_CRB_BASE + 0x80) typedef union { u8 _raw[4]; /* 4-byte reg */ struct __packed { u8 tpm_establishment : 1; u8 loc_assigned : 1; u8 active_locality : 3; u8 reserved : 2; u8 tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */ u8 reserved1 :8; u16 reserved2 :16; }; } tpm_reg_loc_state_t; typedef union { uint8_t _raw[4]; struct __packed { uint32_t requestAccess:1; uint32_t relinquish:1; uint32_t seize:1; uint32_t resetEstablishment:1; uint32_t reserved1:28; }; } tpm_reg_loc_ctrl_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t Granted:1; uint32_t BeenSeized:1; uint32_t R:30; }; } tpm_reg_loc_sts_t; typedef union { uint8_t _raw[8]; // 8-byte reg struct __packed { uint64_t interface_type:4; uint64_t interface_version:4; uint64_t interface_capability:4; uint64_t interface_selector:4; uint64_t rid:8; uint64_t res:8; uint64_t vid:16; uint64_t did:16; }; } tpm_crb_interface_id_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t cmdReady:1; uint32_t goIdle:1; uint32_t Reserved:30; }; } tpm_reg_ctrl_request_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t tpmsts:1; uint32_t tpmidle:1; uint32_t reserved:30; }; } tpm_reg_ctrl_sts_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t start; }; } tpm_reg_ctrl_start_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t cancel; }; } tpm_reg_ctrl_cancel_t; typedef union { uint8_t _raw[8]; struct __packed{ uint32_t cmdladdr; uint32_t cmdhaddr; }; } tpm_reg_ctrl_cmdaddr_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t cmdsize; }; } tpm_reg_ctrl_cmdsize_t; typedef union { uint8_t _raw[8]; struct __packed{ uint64_t rspaddr; }; } tpm_reg_ctrl_rspaddr_t; typedef union { uint8_t _raw[4]; struct __packed{ uint32_t rspsize; }; } tpm_reg_ctrl_rspsize_t; typedef union { uint8_t _raw[48]; struct __packed { tpm_reg_ctrl_request_t Request; tpm_reg_ctrl_sts_t Status; tpm_reg_ctrl_cancel_t Cancel; tpm_reg_ctrl_start_t Start; uint64_t R; tpm_reg_ctrl_cmdsize_t CmdSize; tpm_reg_ctrl_cmdaddr_t CmdAddr; tpm_reg_ctrl_rspsize_t RspSize; tpm_reg_ctrl_rspaddr_t RspAddr; }; } tpm_ctrl_area_t; // END OF CRB I/F /* * assumes that all reg types follow above format: * - packed * - member named '_raw' which is array whose size is that of data to read */ #define read_tpm_reg(locality, reg, pdata) _read_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata))) #define write_tpm_reg(locality, reg, pdata) _write_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata))) static inline void _read_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size) { for ( size_t i = 0; i < size; i++ ) _raw[i] = readb((TPM_LOCALITY_BASE_N(locality) | reg) + i); } static inline void _write_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size) { for ( size_t i = 0; i < size; i++ ) writeb((TPM_LOCALITY_BASE_N(locality) | reg) + i, _raw[i]); } /* * the following inline function reversely copy the bytes from 'in' to * 'out', the byte number to copy is given in count. */ #define reverse_copy(out, in, count) _reverse_copy((uint8_t *)(out), (uint8_t *)(in), count) static inline void _reverse_copy(uint8_t *out, uint8_t *in, uint32_t count) { for ( uint32_t i = 0; i < count; i++ ) out[i] = in[count - i - 1]; } /* alg id list supported by Tboot */ extern u16 tboot_alg_list[]; extern const uint8_t tboot_alg_list_count; typedef tb_hash_t tpm_digest_t; typedef tpm_digest_t tpm_pcr_value_t; /* only for tpm1.2 to (un)seal */ extern tpm_pcr_value_t post_launch_pcr17; extern tpm_pcr_value_t post_launch_pcr18; struct tpm_if; struct tpm_if_fp; struct tpm_if { #define TPM12_VER_MAJOR 1 #define TPM12_VER_MINOR 2 #define TPM20_VER_MAJOR 2 #define TPM20_VER_MINOR 0 u8 major; u8 minor; u16 family; tpm_timeout_t timeout; u32 error; /* last reported error */ u32 cur_loc; u16 banks; u16 algs_banks[TPM_ALG_MAX_NUM]; u16 alg_count; u16 algs[TPM_ALG_MAX_NUM]; /* * Only for version>=2. PCR extend policy. */ #define TB_EXTPOL_AGILE 0 #define TB_EXTPOL_EMBEDDED 1 #define TB_EXTPOL_FIXED 2 u8 extpol; u16 cur_alg; /* NV index to be used */ u32 lcp_own_index; u32 tb_policy_index; u32 tb_err_index; u32 sgx_svn_index; }; struct tpm_if_fp { bool (*init)(struct tpm_if *ti); bool (*pcr_read)(struct tpm_if *ti, u32 locality, u32 pcr, tpm_pcr_value_t *out); bool (*pcr_extend)(struct tpm_if *ti, u32 locality, u32 pcr, const hash_list_t *in); bool (*pcr_reset)(struct tpm_if *ti, u32 locality, u32 pcr); bool (*hash)(struct tpm_if *ti, u32 locality, const u8 *data, u32 data_size, hash_list_t *hl); bool (*nv_read)(struct tpm_if *ti, u32 locality, u32 index, u32 offset, u8 *data, u32 *data_size); bool (*nv_write)(struct tpm_if *ti, u32 locality, u32 index, u32 offset, const u8 *data, u32 data_size); bool (*get_nvindex_size)(struct tpm_if *ti, u32 locality, u32 index, u32 *size); #define TPM_NV_PER_WRITE_STCLEAR (1<<14) #define TPM_NV_PER_WRITEDEFINE (1<<13) #define TPM_NV_PER_WRITEALL (1<<12) #define TPM_NV_PER_AUTHWRITE (1<<2) #define TPM_NV_PER_OWNERWRITE (1<<1) #define TPM_NV_PER_PPWRITE (1<<0) bool (*get_nvindex_permission)(struct tpm_if *ti, u32 locality, u32 index, u32 *attribute); bool (*seal)(struct tpm_if *ti, u32 locality, u32 in_data_size, const u8 *in_data, u32 *sealed_data_size, u8 *sealed_data); bool (*unseal)(struct tpm_if *ti, u32 locality, u32 sealed_data_size, const u8 *sealed_data, u32 *secret_size, u8 *secret); bool (*verify_creation)(struct tpm_if *ti, u32 sealed_data_size, u8 *sealed_data); bool (*get_random)(struct tpm_if *ti, u32 locality, u8 *random_data, u32 *data_size); uint32_t (*save_state)(struct tpm_if *ti, u32 locality); bool (*context_save)(struct tpm_if *ti, u32 locality, u32 handle, void *context_saved); bool (*context_load)(struct tpm_if *ti, u32 locality, void *context_saved, u32 *handle); bool (*context_flush)(struct tpm_if *ti, u32 locality, u32 handle); bool (*cap_pcrs)(struct tpm_if *ti, u32 locality, int pcr); bool (*check)(void); }; extern struct tpm_if_data tpm_if_data; extern const struct tpm_if_fp tpm_12_if_fp; extern const struct tpm_if_fp tpm_20_if_fp; extern uint8_t g_tpm_ver; extern uint8_t g_tpm_family; extern bool tpm_validate_locality(uint32_t locality); extern bool tpm_validate_locality_crb(uint32_t locality); extern bool release_locality(uint32_t locality); extern bool prepare_tpm(void); extern bool tpm_detect(void); extern void tpm_print(struct tpm_if *ti); extern bool tpm_submit_cmd(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size); extern bool tpm_submit_cmd_crb(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size); extern bool tpm_wait_cmd_ready(uint32_t locality); extern bool tpm_request_locality_crb(uint32_t locality); extern bool tpm_relinquish_locality_crb(uint32_t locality); extern bool txt_is_launched(void); extern bool tpm_workaround_crb(void); extern struct tpm_if *get_tpm(void); extern const struct tpm_if_fp *get_tpm_fp(void); //#define TPM_UNIT_TEST 1 #ifdef TPM_UNIT_TEST void tpm_unit_test(void); #else #define tpm_unit_test() #endif /* TPM_UNIT_TEST */ #endif /* __TPM_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/tpm_20.h0000644000000000000000000014764114210363175015116 0ustar 00000000000000/* * tpm_20.h: TPM2.0-related structure * * Copyright (c) 2006-2013, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TPM20_H__ #define __TPM20_H__ /* * tpm2.0 structure defined in spec. */ typedef struct { u16 size; u8 buffer[1]; } TPM2B; // Table 205 -- SHA1 Hash Values #define SHA1_DIGEST_SIZE 20 #define SHA1_BLOCK_SIZE 64 #define SHA1_DER_SIZE 15 #define SHA1_DER {0x30,0x21,0x30,0x09,0x06, 0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14} // Table 206 -- SHA256 Hash Values #define SHA256_DIGEST_SIZE 32 #define SHA256_BLOCK_SIZE 64 #define SHA256_DER_SIZE 19 #define SHA256_DER {0x30,0x31,0x30,0x0d,0x06, 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01, 0x05,0x00,0x04,0x20} // Table 207 -- SHA384 Hash Values #define SHA384_DIGEST_SIZE 48 #define SHA384_BLOCK_SIZE 128 #define SHA384_DER_SIZE 19 #define SHA384_DER {0x30,0x41,0x30,0x0d,0x06, 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02, 0x05,0x00,0x04,0x30} // Table 208 -- SHA512 Hash Values #define SHA512_DIGEST_SIZE 64 #define SHA512_BLOCK_SIZE 128 #define SHA512_DER_SIZE 19 #define SHA512_DER {0x30,0x51,0x30,0x0d,0x06, \ 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,\ 0x05,0x00,0x04,0x40} // Table 210 -- SM3_256 Hash Values #define SM3_256_DIGEST_SIZE 32 #define SM3_256_BLOCK_SIZE 64 #define SM3_256_DER_SIZE 18 #define SM3_256_DER {0x30,0x30,0x30,0x0c,0x06, \ 0x08,0x2A,0x81,0x1C,0x81,0x45,0x01,0x83,0x11,0x05,\ 0x00,0x04,0x20} // Table 213 -- Logic Values #define YES 1 #define NO 0 #define TRUE 1 #define FALSE 0 #define SET 1 #define CLEAR 0 // Table 215 -- Implemented Algorithms #define ALG_RSA YES // 1 #define ALG_SHA1 YES // 1 #define ALG_HMAC YES // 1 #define ALG_AES YES // 1 #define ALG_MGF1 YES // 1 #define ALG_XOR YES // 1 #define ALG_KEYEDHASH YES // 1 #define ALG_SHA256 YES // 1 #define ALG_SHA384 YES // 0 #define ALG_SHA512 YES // 0 #define ALG_SM3_256 YES // 1 #define ALG_SM4 YES // 1 #define ALG_RSASSA YES // 1 #define ALG_RSAES YES // 1 #define ALG_RSAPSS YES // 1 #define ALG_OAEP YES // 1 #define ALG_ECC YES // 1 #define ALG_ECDH YES // 1 #define ALG_ECDSA YES // 1 #define ALG_ECDAA YES // 1 #define ALG_SM2 YES // 1 #define ALG_ECSCHNORR YES // 1 #define ALG_SYMCIPHER YES // 1 #define ALG_KDF1_SP800_56a YES // 1 #define ALG_KDF2 NO // 0 #define ALG_KDF1_SP800_108 YES // 1 #define ALG_CTR YES // 1 #define ALG_OFB YES // 1 #define ALG_CBC YES // 1 #define ALG_CFB YES // 1 #define ALG_ECB YES // 1 #define HASH_COUNT (ALG_SHA1+ALG_SHA256+ALG_SM3_256+ALG_SHA384+ALG_SHA512) // Table 217 -- RSA Algorithm Constants #define RSA_KEY_SIZES_BITS {1024, 2048} // {1024,2048} #define MAX_RSA_KEY_BITS 2048 #define MAX_RSA_KEY_BYTES ((MAX_RSA_KEY_BITS + 7) / 8) // 256 // Table 218 -- ECC Algorithm Constants #define ECC_CURVES {TPM_ECC_NIST_P256,TPM_ECC_BN_P256,TPM_ECC_SM2_P256} #define ECC_KEY_SIZES_BITS {256} #define MAX_ECC_KEY_BITS 256 #define MAX_ECC_KEY_BYTES ((MAX_ECC_KEY_BITS + 7) / 8) // 32 // Table 219 -- AES Algorithm Constants #define AES_KEY_SIZES_BITS {128} #define MAX_AES_KEY_BITS 128 #define MAX_AES_BLOCK_SIZE_BYTES 16 #define MAX_AES_KEY_BYTES ((MAX_AES_KEY_BITS + 7) / 8) // 16 // Table 221 -- Symmetric Algorithm Constants #define MAX_SYM_KEY_BITS MAX_AES_KEY_BITS // 128 #define MAX_SYM_KEY_BYTES MAX_AES_KEY_BYTES // 16 #define MAX_SYM_BLOCK_SIZE MAX_AES_BLOCK_SIZE_BYTES // 16 // Table 222 -- Implementation Values #define FIELD_UPGRADE_IMPLEMENTED NO // 0 typedef u16 BSIZE; #define BUFFER_ALIGNMENT 4 #define IMPLEMENTATION_PCR 24 #define PLATFORM_PCR 24 #define DRTM_PCR 17 #define NUM_LOCALITIES 5 #define MAX_HANDLE_NUM 3 #define MAX_ACTIVE_SESSIONS 64 typedef u16 CONTEXT_SLOT; typedef u64 CONTEXT_COUNTER; #define MAX_LOADED_SESSIONS 3 #define MAX_SESSION_NUM 3 #define MAX_LOADED_OBJECTS 3 #define MIN_EVICT_OBJECTS 2 #define PCR_SELECT_MIN ((PLATFORM_PCR+7)/8) // 3 #define PCR_SELECT_MAX ((IMPLEMENTATION_PCR+7)/8) // 3 #define NUM_POLICY_PCR_GROUP 1 #define NUM_AUTHVALUE_PCR_GROUP 1 #define MAX_CONTEXT_SIZE 4000 #define MAX_DIGEST_BUFFER 1024 #define MAX_NV_INDEX_SIZE 1024 #define MAX_CAP_BUFFER 1024 #define NV_MEMORY_SIZE 16384 #define NUM_STATIC_PCR 16 #define MAX_ALG_LIST_SIZE 64 #define TIMER_PRESCALE 100000 #define PRIMARY_SEED_SIZE 32 #define CONTEXT_ENCRYPT_ALG TPM_ALG_AES #define CONTEXT_ENCRYPT_KEY_BITS MAX_SYM_KEY_BITS // 128 #define CONTEXT_ENCRYPT_KEY_BYTES ((CONTEXT_ENCRYPT_KEY_BITS+7)/8) #define CONTEXT_INTEGRITY_HASH_ALG TPM_ALG_SHA256 #define CONTEXT_INTEGRITY_HASH_SIZE SHA256_DIGEST_SIZE // 32 #define PROOF_SIZE CONTEXT_INTEGRITY_HASH_SIZE // 32 #define NV_CLOCK_UPDATE_INTERVAL 12 #define NUM_POLICY_PCR 1 #define MAX_COMMAND_SIZE 4096 #define MAX_RESPONSE_SIZE 4096 #define ORDERLY_BITS 8 #define MAX_ORDERLY_COUNT ((1 << ORDERLY_BITS) - 1) // 255 #define ALG_ID_FIRST TPM_ALG_FIRST #define ALG_ID_LAST TPM_ALG_LAST #define MAX_SYM_DATA 128 #define MAX_HASH_STATE_SIZE 512 #define MAX_RNG_ENTROPY_SIZE 64 #define RAM_INDEX_SPACE 512 #define RSA_DEFAULT_PUBLIC_EXPONENT 0x00010001 #define ENABLE_PCR_NO_INCREMENT YES // 1 // Table 11 -- TPM_CC Constants typedef u32 TPM_CC; #define TPM_CC_FIRST (TPM_CC)(0x0000011F) #define TPM_CC_PP_FIRST (TPM_CC)(0x0000011F) #define TPM_CC_NV_UndefineSpaceSpecial (TPM_CC)(0x0000011F) #define TPM_CC_EvictControl (TPM_CC)(0x00000120) #define TPM_CC_HierarchyControl (TPM_CC)(0x00000121) #define TPM_CC_NV_UndefineSpace (TPM_CC)(0x00000122) #define TPM_CC_ChangeEPS (TPM_CC)(0x00000124) #define TPM_CC_ChangePPS (TPM_CC)(0x00000125) #define TPM_CC_Clear (TPM_CC)(0x00000126) #define TPM_CC_ClearControl (TPM_CC)(0x00000127) #define TPM_CC_ClockSet (TPM_CC)(0x00000128) #define TPM_CC_HierarchyChangeAuth (TPM_CC)(0x00000129) #define TPM_CC_NV_DefineSpace (TPM_CC)(0x0000012A) #define TPM_CC_PCR_Allocate (TPM_CC)(0x0000012B) #define TPM_CC_PCR_SetAuthPolicy (TPM_CC)(0x0000012C) #define TPM_CC_PP_Commands (TPM_CC)(0x0000012D) #define TPM_CC_SetPrimaryPolicy (TPM_CC)(0x0000012E) #define TPM_CC_FieldUpgradeStart (TPM_CC)(0x0000012F) #define TPM_CC_ClockRateAdjust (TPM_CC)(0x00000130) #define TPM_CC_CreatePrimary (TPM_CC)(0x00000131) #define TPM_CC_NV_GlobalWriteLock (TPM_CC)(0x00000132) #define TPM_CC_PP_LAST (TPM_CC)(0x00000132) #define TPM_CC_GetCommandAuditDigest (TPM_CC)(0x00000133) #define TPM_CC_NV_Increment (TPM_CC)(0x00000134) #define TPM_CC_NV_SetBits (TPM_CC)(0x00000135) #define TPM_CC_NV_Extend (TPM_CC)(0x00000136) #define TPM_CC_NV_Write (TPM_CC)(0x00000137) #define TPM_CC_NV_WriteLock (TPM_CC)(0x00000138) #define TPM_CC_DictionaryAttackLockReset (TPM_CC)(0x00000139) #define TPM_CC_DictionaryAttackParameters (TPM_CC)(0x0000013A) #define TPM_CC_NV_ChangeAuth (TPM_CC)(0x0000013B) #define TPM_CC_PCR_Event (TPM_CC)(0x0000013C) #define TPM_CC_PCR_Reset (TPM_CC)(0x0000013D) #define TPM_CC_SequenceComplete (TPM_CC)(0x0000013E) #define TPM_CC_SetAlgorithmSet (TPM_CC)(0x0000013F) #define TPM_CC_SetCommandCodeAuditStatus (TPM_CC)(0x00000140) #define TPM_CC_FieldUpgradeData (TPM_CC)(0x00000141) #define TPM_CC_IncrementalSelfTest (TPM_CC)(0x00000142) #define TPM_CC_SelfTest (TPM_CC)(0x00000143) #define TPM_CC_Startup (TPM_CC)(0x00000144) #define TPM_CC_Shutdown (TPM_CC)(0x00000145) #define TPM_CC_StirRandom (TPM_CC)(0x00000146) #define TPM_CC_ActivateCredential (TPM_CC)(0x00000147) #define TPM_CC_Certify (TPM_CC)(0x00000148) #define TPM_CC_PolicyNV (TPM_CC)(0x00000149) #define TPM_CC_CertifyCreation (TPM_CC)(0x0000014A) #define TPM_CC_Duplicate (TPM_CC)(0x0000014B) #define TPM_CC_GetTime (TPM_CC)(0x0000014C) #define TPM_CC_GetSessionAuditDigest (TPM_CC)(0x0000014D) #define TPM_CC_NV_Read (TPM_CC)(0x0000014E) #define TPM_CC_NV_ReadLock (TPM_CC)(0x0000014F) #define TPM_CC_ObjectChangeAuth (TPM_CC)(0x00000150) #define TPM_CC_PolicySecret (TPM_CC)(0x00000151) #define TPM_CC_Rewrap (TPM_CC)(0x00000152) #define TPM_CC_Create (TPM_CC)(0x00000153) #define TPM_CC_ECDH_ZGen (TPM_CC)(0x00000154) #define TPM_CC_HMAC (TPM_CC)(0x00000155) #define TPM_CC_Import (TPM_CC)(0x00000156) #define TPM_CC_Load (TPM_CC)(0x00000157) #define TPM_CC_Quote (TPM_CC)(0x00000158) #define TPM_CC_RSA_Decrypt (TPM_CC)(0x00000159) #define TPM_CC_HMAC_Start (TPM_CC)(0x0000015B) #define TPM_CC_SequenceUpdate (TPM_CC)(0x0000015C) #define TPM_CC_Sign (TPM_CC)(0x0000015D) #define TPM_CC_Unseal (TPM_CC)(0x0000015E) #define TPM_CC_PolicySigned (TPM_CC)(0x00000160) #define TPM_CC_ContextLoad (TPM_CC)(0x00000161) #define TPM_CC_ContextSave (TPM_CC)(0x00000162) #define TPM_CC_ECDH_KeyGen (TPM_CC)(0x00000163) #define TPM_CC_EncryptDecrypt (TPM_CC)(0x00000164) #define TPM_CC_FlushContext (TPM_CC)(0x00000165) #define TPM_CC_LoadExternal (TPM_CC)(0x00000167) #define TPM_CC_MakeCredential (TPM_CC)(0x00000168) #define TPM_CC_NV_ReadPublic (TPM_CC)(0x00000169) #define TPM_CC_PolicyAuthorize (TPM_CC)(0x0000016A) #define TPM_CC_PolicyAuthValue (TPM_CC)(0x0000016B) #define TPM_CC_PolicyCommandCode (TPM_CC)(0x0000016C) #define TPM_CC_PolicyCounterTimer (TPM_CC)(0x0000016D) #define TPM_CC_PolicyCpHash (TPM_CC)(0x0000016E) #define TPM_CC_PolicyLocality (TPM_CC)(0x0000016F) #define TPM_CC_PolicyNameHash (TPM_CC)(0x00000170) #define TPM_CC_PolicyOR (TPM_CC)(0x00000171) #define TPM_CC_PolicyTicket (TPM_CC)(0x00000172) #define TPM_CC_ReadPublic (TPM_CC)(0x00000173) #define TPM_CC_RSA_Encrypt (TPM_CC)(0x00000174) #define TPM_CC_StartAuthSession (TPM_CC)(0x00000176) #define TPM_CC_VerifySignature (TPM_CC)(0x00000177) #define TPM_CC_ECC_Parameters (TPM_CC)(0x00000178) #define TPM_CC_FirmwareRead (TPM_CC)(0x00000179) #define TPM_CC_GetCapability (TPM_CC)(0x0000017A) #define TPM_CC_GetRandom (TPM_CC)(0x0000017B) #define TPM_CC_GetTestResult (TPM_CC)(0x0000017C) #define TPM_CC_Hash (TPM_CC)(0x0000017D) #define TPM_CC_PCR_Read (TPM_CC)(0x0000017E) #define TPM_CC_PolicyPCR (TPM_CC)(0x0000017F) #define TPM_CC_PolicyRestart (TPM_CC)(0x00000180) #define TPM_CC_ReadClock (TPM_CC)(0x00000181) #define TPM_CC_PCR_Extend (TPM_CC)(0x00000182) #define TPM_CC_PCR_SetAuthValue (TPM_CC)(0x00000183) #define TPM_CC_NV_Certify (TPM_CC)(0x00000184) #define TPM_CC_EventSequenceComplete (TPM_CC)(0x00000185) #define TPM_CC_HashSequenceStart (TPM_CC)(0x00000186) #define TPM_CC_PolicyPhysicalPresence (TPM_CC)(0x00000187) #define TPM_CC_PolicyDuplicationSelect (TPM_CC)(0x00000188) #define TPM_CC_PolicyGetDigest (TPM_CC)(0x00000189) #define TPM_CC_TestParms (TPM_CC)(0x0000018A) #define TPM_CC_Commit (TPM_CC)(0x0000018B) #define TPM_CC_PolicyPassword (TPM_CC)(0x0000018C) #define TPM_CC_SM2_ZGen (TPM_CC)(0x0000018D) #define TPM_CC_LAST (TPM_CC)(0x0000018D) // Table 15 -- TPM_RC Constants typedef u32 TPM_RCS; // The 'safe' error codes typedef u32 TPM_RC; #define TPM_RC_SUCCESS (TPM_RC)(0x000) #define TPM_RC_BAD_TAG (TPM_RC)(0x030) #define RC_VER1 (TPM_RC)(0x100) #define TPM_RC_INITIALIZE (TPM_RC)(RC_VER1 + 0x000) #define TPM_RC_FAILURE (TPM_RC)(RC_VER1 + 0x001) #define TPM_RC_SEQUENCE (TPM_RC)(RC_VER1 + 0x003) #define TPM_RC_PRIVATE (TPM_RC)(RC_VER1 + 0x00B) #define TPM_RC_HMAC (TPM_RC)(RC_VER1 + 0x019) #define TPM_RC_DISABLED (TPM_RC)(RC_VER1 + 0x020) #define TPM_RC_EXCLUSIVE (TPM_RC)(RC_VER1 + 0x021) #define TPM_RC_AUTH_TYPE (TPM_RC)(RC_VER1 + 0x024) #define TPM_RC_AUTH_MISSING (TPM_RC)(RC_VER1 + 0x025) #define TPM_RC_POLICY (TPM_RC)(RC_VER1 + 0x026) #define TPM_RC_PCR (TPM_RC)(RC_VER1 + 0x027) #define TPM_RC_PCR_CHANGED (TPM_RC)(RC_VER1 + 0x028) #define TPM_RC_UPGRADE (TPM_RC)(RC_VER1 + 0x02D) #define TPM_RC_TOO_MANY_CONTEXTS (TPM_RC)(RC_VER1 + 0x02E) #define TPM_RC_AUTH_UNAVAILABLE (TPM_RC)(RC_VER1 + 0x02F) #define TPM_RC_REBOOT (TPM_RC)(RC_VER1 + 0x030) #define TPM_RC_UNBALANCED (TPM_RC)(RC_VER1 + 0x031) #define TPM_RC_COMMAND_SIZE (TPM_RC)(RC_VER1 + 0x042) #define TPM_RC_COMMAND_CODE (TPM_RC)(RC_VER1 + 0x043) #define TPM_RC_AUTHSIZE (TPM_RC)(RC_VER1 + 0x044) #define TPM_RC_AUTH_CONTEXT (TPM_RC)(RC_VER1 + 0x045) #define TPM_RC_NV_RANGE (TPM_RC)(RC_VER1 + 0x046) #define TPM_RC_NV_SIZE (TPM_RC)(RC_VER1 + 0x047) #define TPM_RC_NV_LOCKED (TPM_RC)(RC_VER1 + 0x048) #define TPM_RC_NV_AUTHORIZATION (TPM_RC)(RC_VER1 + 0x049) #define TPM_RC_NV_UNINITIALIZED (TPM_RC)(RC_VER1 + 0x04A) #define TPM_RC_NV_SPACE (TPM_RC)(RC_VER1 + 0x04B) #define TPM_RC_NV_DEFINED (TPM_RC)(RC_VER1 + 0x04C) #define TPM_RC_BAD_CONTEXT (TPM_RC)(RC_VER1 + 0x050) #define TPM_RC_CPHASH (TPM_RC)(RC_VER1 + 0x051) #define TPM_RC_PARENT (TPM_RC)(RC_VER1 + 0x052) #define TPM_RC_NEEDS_TEST (TPM_RC)(RC_VER1 + 0x053) #define TPM_RC_NO_RESULT (TPM_RC)(RC_VER1 + 0x054) #define TPM_RC_SENSITIVE (TPM_RC)(RC_VER1 + 0x055) #define RC_MAX_FM0 (TPM_RC)(RC_VER1 + 0x07F) #define RC_FMT1 (TPM_RC)(0x080) #define TPM_RC_ASYMMETRIC (TPM_RC)(RC_FMT1 + 0x001) #define TPM_RCS_ASYMMETRIC (TPM_RCS)(RC_FMT1 + 0x001) #define TPM_RC_ATTRIBUTES (TPM_RC)(RC_FMT1 + 0x002) #define TPM_RCS_ATTRIBUTES (TPM_RCS)(RC_FMT1 + 0x002) #define TPM_RC_HASH (TPM_RC)(RC_FMT1 + 0x003) #define TPM_RCS_HASH (TPM_RCS)(RC_FMT1 + 0x003) #define TPM_RC_VALUE (TPM_RC)(RC_FMT1 + 0x004) #define TPM_RCS_VALUE (TPM_RCS)(RC_FMT1 + 0x004) #define TPM_RC_HIERARCHY (TPM_RC)(RC_FMT1 + 0x005) #define TPM_RCS_HIERARCHY (TPM_RCS)(RC_FMT1 + 0x005) #define TPM_RC_KEY_SIZE (TPM_RC)(RC_FMT1 + 0x007) #define TPM_RCS_KEY_SIZE (TPM_RCS)(RC_FMT1 + 0x007) #define TPM_RC_MGF (TPM_RC)(RC_FMT1 + 0x008) #define TPM_RCS_MGF (TPM_RCS)(RC_FMT1 + 0x008) #define TPM_RC_MODE (TPM_RC)(RC_FMT1 + 0x009) #define TPM_RCS_MODE (TPM_RCS)(RC_FMT1 + 0x009) #define TPM_RC_TYPE (TPM_RC)(RC_FMT1 + 0x00A) #define TPM_RCS_TYPE (TPM_RCS)(RC_FMT1 + 0x00A) #define TPM_RC_HANDLE (TPM_RC)(RC_FMT1 + 0x00B) #define TPM_RCS_HANDLE (TPM_RCS)(RC_FMT1 + 0x00B) #define TPM_RC_KDF (TPM_RC)(RC_FMT1 + 0x00C) #define TPM_RCS_KDF (TPM_RCS)(RC_FMT1 + 0x00C) #define TPM_RC_RANGE (TPM_RC)(RC_FMT1 + 0x00D) #define TPM_RCS_RANGE (TPM_RCS)(RC_FMT1 + 0x00D) #define TPM_RC_AUTH_FAIL (TPM_RC)(RC_FMT1 + 0x00E) #define TPM_RCS_AUTH_FAIL (TPM_RCS)(RC_FMT1 + 0x00E) #define TPM_RC_NONCE (TPM_RC)(RC_FMT1 + 0x00F) #define TPM_RCS_NONCE (TPM_RCS)(RC_FMT1 + 0x00F) #define TPM_RC_PP (TPM_RC)(RC_FMT1 + 0x010) #define TPM_RCS_PP (TPM_RCS)(RC_FMT1 + 0x010) #define TPM_RC_SCHEME (TPM_RC)(RC_FMT1 + 0x012) #define TPM_RCS_SCHEME (TPM_RCS)(RC_FMT1 + 0x012) #define TPM_RC_SIZE (TPM_RC)(RC_FMT1 + 0x015) #define TPM_RCS_SIZE (TPM_RCS)(RC_FMT1 + 0x015) #define TPM_RC_SYMMETRIC (TPM_RC)(RC_FMT1 + 0x016) #define TPM_RCS_SYMMETRIC (TPM_RCS)(RC_FMT1 + 0x016) #define TPM_RC_TAG (TPM_RC)(RC_FMT1 + 0x017) #define TPM_RCS_TAG (TPM_RCS)(RC_FMT1 + 0x017) #define TPM_RC_SELECTOR (TPM_RC)(RC_FMT1 + 0x018) #define TPM_RCS_SELECTOR (TPM_RCS)(RC_FMT1 + 0x018) #define TPM_RC_INSUFFICIENT (TPM_RC)(RC_FMT1 + 0x01A) #define TPM_RCS_INSUFFICIENT (TPM_RCS)(RC_FMT1 + 0x01A) #define TPM_RC_SIGNATURE (TPM_RC)(RC_FMT1 + 0x01B) #define TPM_RCS_SIGNATURE (TPM_RCS)(RC_FMT1 + 0x01B) #define TPM_RC_KEY (TPM_RC)(RC_FMT1 + 0x01C) #define TPM_RCS_KEY (TPM_RCS)(RC_FMT1 + 0x01C) #define TPM_RC_POLICY_FAIL (TPM_RC)(RC_FMT1 + 0x01D) #define TPM_RCS_POLICY_FAIL (TPM_RCS)(RC_FMT1 + 0x01D) #define TPM_RC_INTEGRITY (TPM_RC)(RC_FMT1 + 0x01F) #define TPM_RCS_INTEGRITY (TPM_RCS)(RC_FMT1 + 0x01F) #define TPM_RC_TICKET (TPM_RC)(RC_FMT1 + 0x020) #define TPM_RCS_TICKET (TPM_RCS)(RC_FMT1 + 0x020) #define TPM_RC_RESERVED_BITS (TPM_RC)(RC_FMT1 + 0x021) #define TPM_RCS_RESERVED_BITS (TPM_RCS)(RC_FMT1 + 0x021) #define TPM_RC_BAD_AUTH (TPM_RC)(RC_FMT1 + 0x022) #define TPM_RCS_BAD_AUTH (TPM_RCS)(RC_FMT1 + 0x022) #define TPM_RC_EXPIRED (TPM_RC)(RC_FMT1 + 0x023) #define TPM_RCS_EXPIRED (TPM_RCS)(RC_FMT1 + 0x023) #define TPM_RC_POLICY_CC (TPM_RC)(RC_FMT1 + 0x024 ) #define TPM_RCS_POLICY_CC (TPM_RCS)(RC_FMT1 + 0x024 ) #define TPM_RC_BINDING (TPM_RC)(RC_FMT1 + 0x025) #define TPM_RCS_BINDING (TPM_RCS)(RC_FMT1 + 0x025) #define TPM_RC_CURVE (TPM_RC)(RC_FMT1 + 0x026) #define TPM_RCS_CURVE (TPM_RCS)(RC_FMT1 + 0x026) #define TPM_RC_ECC_POINT (TPM_RC)(RC_FMT1 + 0x027) #define TPM_RCS_ECC_POINT (TPM_RCS)(RC_FMT1 + 0x027) #define RC_WARN (TPM_RC)(0x900) #define TPM_RC_CONTEXT_GAP (TPM_RC)(RC_WARN + 0x001) #define TPM_RC_OBJECT_MEMORY (TPM_RC)(RC_WARN + 0x002) #define TPM_RC_SESSION_MEMORY (TPM_RC)(RC_WARN + 0x003) #define TPM_RC_MEMORY (TPM_RC)(RC_WARN + 0x004) #define TPM_RC_SESSION_HANDLES (TPM_RC)(RC_WARN + 0x005) #define TPM_RC_OBJECT_HANDLES (TPM_RC)(RC_WARN + 0x006) #define TPM_RC_LOCALITY (TPM_RC)(RC_WARN + 0x007) #define TPM_RC_YIELDED (TPM_RC)(RC_WARN + 0x008) #define TPM_RC_CANCELLED (TPM_RC)(RC_WARN + 0x009) #define TPM_RC_TESTING (TPM_RC)(RC_WARN + 0x00A) #define TPM_RC_REFERENCE_H0 (TPM_RC)(RC_WARN + 0x010) #define TPM_RC_REFERENCE_H1 (TPM_RC)(RC_WARN + 0x011) #define TPM_RC_REFERENCE_H2 (TPM_RC)(RC_WARN + 0x012) #define TPM_RC_REFERENCE_H3 (TPM_RC)(RC_WARN + 0x013) #define TPM_RC_REFERENCE_H4 (TPM_RC)(RC_WARN + 0x014) #define TPM_RC_REFERENCE_H5 (TPM_RC)(RC_WARN + 0x015) #define TPM_RC_REFERENCE_H6 (TPM_RC)(RC_WARN + 0x016) #define TPM_RC_REFERENCE_S0 (TPM_RC)(RC_WARN + 0x018) #define TPM_RC_REFERENCE_S1 (TPM_RC)(RC_WARN + 0x019) #define TPM_RC_REFERENCE_S2 (TPM_RC)(RC_WARN + 0x01A) #define TPM_RC_REFERENCE_S3 (TPM_RC)(RC_WARN + 0x01B) #define TPM_RC_REFERENCE_S4 (TPM_RC)(RC_WARN + 0x01C) #define TPM_RC_REFERENCE_S5 (TPM_RC)(RC_WARN + 0x01D) #define TPM_RC_REFERENCE_S6 (TPM_RC)(RC_WARN + 0x01E) #define TPM_RC_NV_RATE (TPM_RC)(RC_WARN + 0x020) #define TPM_RC_LOCKOUT (TPM_RC)(RC_WARN + 0x021) #define TPM_RC_RETRY (TPM_RC)(RC_WARN + 0x022) #define TPM_RC_NV_UNAVAILABLE (TPM_RC)(RC_WARN + 0x023) #define TPM_RC_NOT_USED (TPM_RC)(RC_WARN + 0x7F) #define TPM_RC_H (TPM_RC)(0x000) #define TPM_RC_P (TPM_RC)(0x040) #define TPM_RC_S (TPM_RC)(0x800) #define TPM_RC_1 (TPM_RC)(0x100) #define TPM_RC_2 (TPM_RC)(0x200) #define TPM_RC_3 (TPM_RC)(0x300) #define TPM_RC_4 (TPM_RC)(0x400) #define TPM_RC_5 (TPM_RC)(0x500) #define TPM_RC_6 (TPM_RC)(0x600) #define TPM_RC_7 (TPM_RC)(0x700) #define TPM_RC_8 (TPM_RC)(0x800) #define TPM_RC_9 (TPM_RC)(0x900) #define TPM_RC_A (TPM_RC)(0xA00) #define TPM_RC_B (TPM_RC)(0xB00) #define TPM_RC_C (TPM_RC)(0xC00) #define TPM_RC_D (TPM_RC)(0xD00) #define TPM_RC_E (TPM_RC)(0xE00) #define TPM_RC_F (TPM_RC)(0xF00) #define TPM_RC_N_MASK (TPM_RC)(0xF00) // Table 18 -- TPM_ST Constants typedef u16 TPM_ST; #define TPM_ST_RSP_COMMAND (TPM_ST)(0x00C4) #define TPM_ST_NULL (TPM_ST)(0X8000) #define TPM_ST_NO_SESSIONS (TPM_ST)(0x8001) #define TPM_ST_SESSIONS (TPM_ST)(0x8002) #define TPM_ST_ATTEST_NV (TPM_ST)(0x8014) #define TPM_ST_ATTEST_COMMAND_AUDIT (TPM_ST)(0x8015) #define TPM_ST_ATTEST_SESSION_AUDIT (TPM_ST)(0x8016) #define TPM_ST_ATTEST_CERTIFY (TPM_ST)(0x8017) #define TPM_ST_ATTEST_QUOTE (TPM_ST)(0x8018) #define TPM_ST_ATTEST_TIME (TPM_ST)(0x8019) #define TPM_ST_ATTEST_CREATION (TPM_ST)(0x801A) #define TPM_ST_CREATION (TPM_ST)(0x8021) #define TPM_ST_VERIFIED (TPM_ST)(0x8022) #define TPM_ST_AUTH_SECRET (TPM_ST)(0x8023) #define TPM_ST_HASHCHECK (TPM_ST)(0x8024) #define TPM_ST_AUTH_SIGNED (TPM_ST)(0x8025) #define TPM_ST_FU_MANIFEST (TPM_ST)(0x8029) // Table 19 -- TPM_SU Constants typedef u16 TPM_SU; #define TPM_SU_CLEAR (TPM_SU)(0x0000) #define TPM_SU_STATE (TPM_SU)(0x0001) // Table 21 -- TPM_CAP Constants typedef u32 TPM_CAP; #define TPM_CAP_FIRST (TPM_CAP)(0x00000000) #define TPM_CAP_ALGS (TPM_CAP)(0x00000000) #define TPM_CAP_HANDLES (TPM_CAP)(0x00000001) #define TPM_CAP_COMMANDS (TPM_CAP)(0x00000002) #define TPM_CAP_PP_COMMANDS (TPM_CAP)(0x00000003) #define TPM_CAP_AUDIT_COMMANDS (TPM_CAP)(0x00000004) #define TPM_CAP_PCRS (TPM_CAP)(0x00000005) #define TPM_CAP_TPM_PROPERTIES (TPM_CAP)(0x00000006) #define TPM_CAP_PCR_PROPERTIES (TPM_CAP)(0x00000007) #define TPM_CAP_ECC_CURVES (TPM_CAP)(0x00000008) #define TPM_CAP_LAST (TPM_CAP)(0x00000008) #define TPM_CAP_VENDOR_PROPERTY (TPM_CAP)(0x00000100) // Table 25 -- Handles Types typedef u32 TPM_HANDLE; typedef u8 TPM_HT; #define TPM_HT_PCR (TPM_HT)(0x00) #define TPM_HT_NV_INDEX (TPM_HT)(0x01) #define TPM_HT_HMAC_SESSION (TPM_HT)(0x02) #define TPM_HT_LOADED_SESSION (TPM_HT)(0x02) #define TPM_HT_POLICY_SESSION (TPM_HT)(0x03) #define TPM_HT_ACTIVE_SESSION (TPM_HT)(0x03) #define TPM_HT_PERMANENT (TPM_HT)(0x40) #define TPM_HT_TRANSIENT (TPM_HT)(0x80) #define TPM_HT_PERSISTENT (TPM_HT)(0x81) // Table 27 -- TPM_RH Constants typedef u32 TPM_RH; #define TPM_RH_FIRST (TPM_RH)(0x40000000) #define TPM_RH_SRK (TPM_RH)(0x40000000) #define TPM_RH_OWNER (TPM_RH)(0x40000001) #define TPM_RH_REVOKE (TPM_RH)(0x40000002) #define TPM_RH_TRANSPORT (TPM_RH)(0x40000003) #define TPM_RH_OPERATOR (TPM_RH)(0x40000004) #define TPM_RH_ADMIN (TPM_RH)(0x40000005) #define TPM_RH_EK (TPM_RH)(0x40000006) #define TPM_RH_NULL (TPM_RH)(0x40000007) #define TPM_RH_UNASSIGNED (TPM_RH)(0x40000008) #define TPM_RS_PW (TPM_RH)(0x40000009) #define TPM_RH_LOCKOUT (TPM_RH)(0x4000000A) #define TPM_RH_ENDORSEMENT (TPM_RH)(0x4000000B) #define TPM_RH_PLATFORM (TPM_RH)(0x4000000C) #define TPM_RH_LAST (TPM_RH)(0x4000000C) #define RC_ContextSave_saveHandle (TPM_RC_P + TPM_RC_1) #define RC_ContextLoad_context (TPM_RC_P + TPM_RC_1) #define RC_FlushContext_flushHandle (TPM_RC_P + TPM_RC_1) // Table 29 -- TPMA_ALGORITHM Bits typedef struct { unsigned int asymmetric : 1; unsigned int symmetric : 1; unsigned int hash : 1; unsigned int object : 1; unsigned int reserved5 : 4; unsigned int signing : 1; unsigned int encrypting : 1; unsigned int method : 1; unsigned int reserved9 : 21; } TPMA_ALGORITHM ; // Table 30 -- TPMA_OBJECT Bits typedef struct { unsigned int reserved1 : 1; unsigned int fixedTPM : 1; unsigned int stClear : 1; unsigned int reserved4 : 1; unsigned int fixedParent : 1; unsigned int sensitiveDataOrigin : 1; unsigned int userWithAuth : 1; unsigned int adminWithPolicy : 1; unsigned int reserved9 : 2; unsigned int noDA : 1; unsigned int encryptedDuplication : 1; unsigned int reserved12 : 4; unsigned int restricted : 1; // Start of 2nd dword unsigned int decrypt : 1; unsigned int sign : 1; unsigned int reserved16 : 13; } TPMA_OBJECT ; // Table 31 -- TPMA_SESSION Bits typedef struct { unsigned int continueSession : 1; unsigned int auditExclusive : 1; unsigned int auditReset : 1; unsigned int reserved4 : 2; unsigned int decrypt : 1; unsigned int encrypt : 1; unsigned int audit : 1; } TPMA_SESSION; // Table 32 -- TPMA_LOCALITY Bits typedef struct { unsigned int TPM_LOC_ZERO : 1; unsigned int TPM_LOC_ONE : 1; unsigned int TPM_LOC_TWO : 1; unsigned int TPM_LOC_THREE : 1; unsigned int TPM_LOC_FOUR : 1; unsigned int reserved6 : 3; } TPMA_LOCALITY; // Table 47 Definition of TPMI_DH_CONTEXT Type typedef TPM_HANDLE TPMI_DH_CONTEXT; // Table 48 Definition of TPMI_RH_HIERARCHY Type typedef TPM_HANDLE TPMI_RH_HIERARCHY; // Table 66 -- TPMU_HA Union typedef union { #ifdef TPM_ALG_SHA1 u8 sha1[SHA1_DIGEST_SIZE]; #endif #ifdef TPM_ALG_SHA256 u8 sha256[SHA256_DIGEST_SIZE]; #endif #ifdef TPM_ALG_SM3_256 u8 sm3_256[SM3_256_DIGEST_SIZE]; #endif #ifdef TPM_ALG_SHA384 u8 sha384[SHA384_DIGEST_SIZE]; #endif #ifdef TPM_ALG_SHA512 u8 sha512[SHA512_DIGEST_SIZE]; #endif } TPMU_HA ; // Table 67 -- TPMT_HA Structure typedef struct { u16 hash_alg; TPMU_HA digest; } TPMT_HA; // Table 68 -- TPM2B_DIGEST Structure typedef struct { u16 size; u8 buffer[sizeof(TPMU_HA)]; } DIGEST_2B; typedef union { DIGEST_2B t; TPM2B b; } TPM2B_DIGEST; // Table 69 -- TPM2B_DATA Structure typedef struct { u16 size; u8 buffer[sizeof(TPMT_HA)]; } DATA_2B; typedef union { DATA_2B t; TPM2B b; } TPM2B_DATA; // Table 70 -- TPM2B_NONCE Types typedef TPM2B_DIGEST TPM2B_NONCE; // Table 71 -- TPM2B_AUTH Types typedef TPM2B_DIGEST TPM2B_AUTH; // Table 73 -- TPM2B_EVENT Structure typedef struct { u16 size; u8 buffer[1024]; } EVENT_2B; typedef union { EVENT_2B t; TPM2B b; } TPM2B_EVENT; // Table 74 -- TPM2B_MAX_BUFFER Structure typedef struct { u16 size; u8 buffer[MAX_DIGEST_BUFFER]; } MAX_BUFFER_2B; typedef union { MAX_BUFFER_2B t; TPM2B b; } TPM2B_MAX_BUFFER; // Table 75 -- TPM2B_MAX_NV_BUFFER Structure typedef struct { u16 size; u8 buffer[MAX_NV_INDEX_SIZE]; } MAX_NV_BUFFER_2B; typedef union { MAX_NV_BUFFER_2B t; TPM2B b; } TPM2B_MAX_NV_BUFFER; // Table 79 -- TPMU_NAME Structure typedef union { TPMT_HA digest; u32 handle; } TPMU_NAME ; // Table 79 -- TPM2B_NAME Structure typedef struct { u16 size; u8 name[sizeof(TPMU_NAME)]; } NAME_2B; typedef union { NAME_2B t; TPM2B b; } TPM2B_NAME; // Table 80 -- TPMS_PCR_SELECTION Structure typedef struct { u16 hash; u8 size_of_select; u8 pcr_select[PCR_SELECT_MAX]; } TPMS_PCR_SELECTION; // Table 84 -- TPMT_TK_CREATION Structure typedef struct { u16 tag; u32 hierarchy; TPM2B_DIGEST digest; } TPMT_TK_CREATION; // Table 86 -- TPMT_TK_HASHCHECK Structure typedef struct { u16 tag; u32 hierarchy; TPM2B_DIGEST digest; } TPMT_TK_HASHCHECK; // Table 88 -- TPMS_ALG_PROPERTY Structure typedef struct { u16 alg; TPMA_ALGORITHM alg_pro; } TPMS_ALG_PROPERTY; // Table 95 -- TPML_DIGEST Structure typedef struct { u32 count; TPM2B_DIGEST digests[8]; } TPML_DIGEST; // Table 96 -- TPML_DIGEST_VALUES Structure typedef struct { u32 count; TPMT_HA digests[HASH_COUNT]; } TPML_DIGEST_VALUES; // Table 98 -- TPML_PCR_SELECTION Structure typedef struct { u32 count; TPMS_PCR_SELECTION selections[HASH_COUNT]; } TPML_PCR_SELECTION; #define MAX_CAP_DATA (MAX_CAP_BUFFER-sizeof(u32)-sizeof(u32)) #define MAX_CAP_ALGS (MAX_CAP_DATA/sizeof(TPMS_ALG_PROPERTY)) // Table 99 -- TPML_ALG_PROPERTY Structure typedef struct { u32 count; TPMS_ALG_PROPERTY alg_pros[MAX_CAP_ALGS]; } TPML_ALG_PROPERTY; // Table 103 -- TPMU_CAPABILITIES Union typedef union { TPML_ALG_PROPERTY algs; } TPMU_CAPABILITIES; // Table 104 -- TPMS_CAPABILITY_DATA Structure typedef struct { u32 capability; TPMU_CAPABILITIES data; } TPMS_CAPABILITY_DATA; // Table 122 -- TPMU_SYM_KEY_BITS Union typedef union { #ifdef TPM_ALG_AES u16 aes; #endif #ifdef TPM_ALG_SM4 u16 sm4; #endif u16 sym; #ifdef TPM_ALG_XOR u16 xor; #endif } TPMU_SYM_KEY_BITS ; // Table 122 -- TPMU_SYM_MODE Union typedef union { #ifdef TPM_ALG_AES u16 aes; #endif #ifdef TPM_ALG_SM4 u16 sm4; #endif u16 sym; } TPMU_SYM_MODE ; // Table 126 -- TPMT_SYM_DEF_OBJECT Structure typedef struct { u16 alg; TPMU_SYM_KEY_BITS key_bits; TPMU_SYM_MODE mode; } TPMT_SYM_DEF_OBJECT; // Table 126 -- TPM2B_SYM_KEY Structure typedef struct { u16 size; u8 buffer[MAX_SYM_KEY_BYTES]; } SYM_KEY_2B; typedef union { SYM_KEY_2B t; TPM2B b; } TPM2B_SYM_KEY; // Table 129 -- TPM2B_SENSITIVE_DATA Structure typedef struct { u16 size; u8 buffer[MAX_SYM_DATA]; } SENSITIVE_DATA_2B; typedef union { SENSITIVE_DATA_2B t; TPM2B b; } TPM2B_SENSITIVE_DATA; // Table 130 -- TPMS_SENSITIVE_CREATE Structure typedef struct { TPM2B_AUTH user_auth; TPM2B_SENSITIVE_DATA data; } TPMS_SENSITIVE_CREATE; // Table 131 -- TPM2B_SENSITIVE_CREATE Structure typedef struct { u16 size; TPMS_SENSITIVE_CREATE sensitive; } SENSITIVE_CREATE_2B; typedef union { SENSITIVE_CREATE_2B t; TPM2B b; } TPM2B_SENSITIVE_CREATE; // Table 132 -- TPMS_SCHEME_SIGHASH Structure typedef struct { u16 hash_alg; } TPMS_SCHEME_SIGHASH; // Table 134 -- HMAC_SIG_SCHEME Types typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_HMAC; // Table 135 -- TPMS_SCHEME_XOR Structure typedef struct { u16 hash_alg; u16 kdf; } TPMS_SCHEME_XOR; // Table 136 -- TPMU_SCHEME_KEYEDHASH Union typedef union { #ifdef TPM_ALG_HMAC TPMS_SCHEME_HMAC hmac; #endif #ifdef TPM_ALG_XOR TPMS_SCHEME_XOR xor; #endif } TPMU_SCHEME_KEYEDHASH; // Table 137 -- TPMT_KEYEDHASH_SCHEME Structure typedef struct { u16 scheme; TPMU_SCHEME_KEYEDHASH details; } TPMT_KEYEDHASH_SCHEME; // Table 138 -- RSA_SIG_SCHEMES Types typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSASSA; typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSAPSS; // Table 139 -- ECC_SIG_SCHEMES Types typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_ECDSA; typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_SM2; typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_ECSCHNORR; // Table 140 -- TPMS_SCHEME_ECDAA Structure typedef struct { u16 hash_alg; u16 count; } TPMS_SCHEME_ECDAA; // Table 141 -- TPMU_SIG_SCHEME Union typedef union { #ifdef TPM_ALG_RSASSA TPMS_SCHEME_RSASSA rsassa; #endif #ifdef TPM_ALG_RSAPSS TPMS_SCHEME_RSAPSS rsapss; #endif #ifdef TPM_ALG_ECDSA TPMS_SCHEME_ECDSA ecdsa; #endif #ifdef TPM_ALG_SM2 TPMS_SCHEME_SM2 sm2; #endif #ifdef TPM_ALG_ECDAA TPMS_SCHEME_ECDAA ecdaa; #endif #ifdef TPM_ALG_ECSCHNORR TPMS_SCHEME_ECSCHNORR ec_schnorr; #endif #ifdef TPM_ALG_HMAC TPMS_SCHEME_HMAC hmac; #endif TPMS_SCHEME_SIGHASH any; } TPMU_SIG_SCHEME ; // Table 143 -- TPMS_SCHEME_OAEP Structure typedef struct { u16 hash_alg; } TPMS_SCHEME_OAEP; // Table 145 -- TPMS_SCHEME_MGF1 Structure typedef struct { u16 hash_alg; } TPMS_SCHEME_MGF1; // Table 146 -- TPMS_SCHEME_KDF1_SP800_56a Structure typedef struct { u16 hash_alg; } TPMS_SCHEME_KDF1_SP800_56a; // Table 147 -- TPMS_SCHEME_KDF2 Structure typedef struct { u16 hash_alg; } TPMS_SCHEME_KDF2; // Table 148 -- TPMS_SCHEME_KDF1_SP800_108 Structure typedef struct { u16 hash_alg; } TPMS_SCHEME_KDF1_SP800_108; // Table 149 -- TPMU_KDF_SCHEME Union typedef union { #ifdef TPM_ALG_MGF1 TPMS_SCHEME_MGF1 mgf1; #endif #ifdef TPM_ALG_KDF1_SP800_56a TPMS_SCHEME_KDF1_SP800_56a kdf1_SP800_56a; #endif #ifdef TPM_ALG_KDF2 TPMS_SCHEME_KDF2 kdf2; #endif #ifdef TPM_ALG_KDF1_SP800_108 TPMS_SCHEME_KDF1_SP800_108 kdf1_sp800_108; #endif } TPMU_KDF_SCHEME ; // Table 150 -- TPMT_KDF_SCHEME Structure typedef struct { u16 scheme; TPMU_KDF_SCHEME details; } TPMT_KDF_SCHEME; // Table 152 -- TPMU_ASYM_SCHEME Union typedef union { #ifdef TPM_ALG_RSASSA TPMS_SCHEME_RSASSA rsassa; #endif #ifdef TPM_ALG_RSAPSS TPMS_SCHEME_RSAPSS rsapss; #endif #ifdef TPM_ALG_OAEP TPMS_SCHEME_OAEP oaep; #endif #ifdef TPM_ALG_ECDSA TPMS_SCHEME_ECDSA ecdsa; #endif #ifdef TPM_ALG_SM2 TPMS_SCHEME_SM2 sm2; #endif #ifdef TPM_ALG_ECDAA TPMS_SCHEME_ECDAA ecdaa; #endif #ifdef TPM_ALG_ECSCHNORR TPMS_SCHEME_ECSCHNORR ec_schnorr; #endif TPMS_SCHEME_SIGHASH any; } TPMU_ASYM_SCHEME; // Table 153 -- TPMT_ASYM_SCHEME Structure <> typedef struct { u16 scheme; TPMU_ASYM_SCHEME details; } TPMT_ASYM_SCHEME; // Table 155 -- TPMT_RSA_SCHEME Structure typedef struct { u16 scheme; TPMU_ASYM_SCHEME details; } TPMT_RSA_SCHEME; // Table 158 -- TPM2B_PUBLIC_KEY_RSA Structure typedef struct { u16 size; u8 buffer[MAX_RSA_KEY_BYTES]; } PUBLIC_KEY_RSA_2B; typedef union { PUBLIC_KEY_RSA_2B t; TPM2B b; } TPM2B_PUBLIC_KEY_RSA; // Table 160 -- TPM2B_PRIVATE_KEY_RSA Structure typedef struct { u16 size; u8 buffer[MAX_RSA_KEY_BYTES/2]; } PRIVATE_KEY_RSA_2B; typedef union { PRIVATE_KEY_RSA_2B t; TPM2B b; } TPM2B_PRIVATE_KEY_RSA; // Table 161 -- TPM2B_ECC_PARAMETER Structure typedef struct { u16 size; u8 buffer[MAX_ECC_KEY_BYTES]; } ECC_PARAMETER_2B; typedef union { ECC_PARAMETER_2B t; TPM2B b; } TPM2B_ECC_PARAMETER; // Table 162 -- TPMS_ECC_POINT Structure typedef struct { TPM2B_ECC_PARAMETER x; TPM2B_ECC_PARAMETER y; } TPMS_ECC_POINT; // Table 166 -- TPMT_ECC_SCHEME Structure typedef struct { u16 scheme; TPMU_SIG_SCHEME details; } TPMT_ECC_SCHEME; // Table 176 -- TPMU_PUBLIC_ID Union typedef union { #ifdef TPM_ALG_KEYEDHASH TPM2B_DIGEST keyed_hash; #endif #ifdef TPM_ALG_SYMCIPHER TPM2B_DIGEST sym; #endif #ifdef TPM_ALG_RSA TPM2B_PUBLIC_KEY_RSA rsa; #endif #ifdef TPM_ALG_ECC TPMS_ECC_POINT ecc; #endif } TPMU_PUBLIC_ID; // Table 177 -- TPMS_KEYEDHASH_PARMS Structure typedef struct { TPMT_KEYEDHASH_SCHEME scheme; } TPMS_KEYEDHASH_PARMS; // Table 178 -- TPMS_ASYM_PARMS Structure typedef struct { TPMT_SYM_DEF_OBJECT symmetric; TPMT_ASYM_SCHEME scheme; } TPMS_ASYM_PARMS; // Table 179 -- TPMS_RSA_PARMS Structure typedef struct { TPMT_SYM_DEF_OBJECT symmetric; TPMT_RSA_SCHEME scheme; u16 key_bits; u32 exponent; } TPMS_RSA_PARMS; // Table 180 -- TPMS_ECC_PARMS Structure typedef struct { TPMT_SYM_DEF_OBJECT symmetric; TPMT_ECC_SCHEME scheme; u16 curve_id; TPMT_KDF_SCHEME kdf; } TPMS_ECC_PARMS; // Table 181 -- TPMU_PUBLIC_PARMS Union typedef union { #ifdef TPM_ALG_KEYEDHASH TPMS_KEYEDHASH_PARMS keyed_hash; #endif #ifdef TPM_ALG_SYMCIPHER TPMT_SYM_DEF_OBJECT sym; #endif #ifdef TPM_ALG_RSA TPMS_RSA_PARMS rsa; #endif #ifdef TPM_ALG_ECC TPMS_ECC_PARMS ecc; #endif TPMS_ASYM_PARMS asym; } TPMU_PUBLIC_PARMS; // Table 184 -- TPMT_PUBLIC Structure typedef struct { u16 type; u16 name_alg; TPMA_OBJECT object_attr; TPM2B_DIGEST auth_policy; TPMU_PUBLIC_PARMS param; TPMU_PUBLIC_ID unique; } TPMT_PUBLIC; // Table 185 -- TPM2B_PUBLIC Structure typedef struct { u16 size; TPMT_PUBLIC public_area; } PUBLIC_2B; typedef union { PUBLIC_2B t; TPM2B b; } TPM2B_PUBLIC; // Table 186 -- TPMU_SENSITIVE_COMPOSITE Union typedef union { #ifdef TPM_ALG_RSA TPM2B_PRIVATE_KEY_RSA rsa; #endif #ifdef TPM_ALG_ECC TPM2B_ECC_PARAMETER ecc; #endif #ifdef TPM_ALG_KEYEDHASH TPM2B_SENSITIVE_DATA bits; #endif #ifdef TPM_ALG_SYMCIPHER TPM2B_SYM_KEY sym; #endif TPM2B_SENSITIVE_DATA any; } TPMU_SENSITIVE_COMPOSITE ; // Table 187 -- TPMT_SENSITIVE Structure typedef struct { u16 type; TPM2B_AUTH auth_value; TPM2B_DIGEST seedValue; TPMU_SENSITIVE_COMPOSITE sensitive; } TPMT_SENSITIVE; // Table 189 -- _PRIVATE Structure <> typedef struct { TPM2B_DIGEST integrity_outer; TPM2B_DIGEST integrity_inner; TPMT_SENSITIVE sensitive; } _PRIVATE; // Table 190 -- TPM2B_PRIVATE Structure typedef struct { u16 size; u8 buffer[sizeof(_PRIVATE)]; } PRIVATE_2B; typedef union { PRIVATE_2B t; TPM2B b; } TPM2B_PRIVATE; // Table 195 -- TPMA_NV Bits typedef struct { unsigned int TPMA_NV_PPWRITE : 1; unsigned int TPMA_NV_OWNERWRITE : 1; unsigned int TPMA_NV_AUTHWRITE : 1; unsigned int TPMA_NV_POLICYWRITE : 1; unsigned int TPMA_NV_COUNTER : 1; unsigned int TPMA_NV_BITS : 1; unsigned int TPMA_NV_EXTEND : 1; unsigned int reserved8 : 3; unsigned int TPMA_NV_POLICY_DELETE : 1; unsigned int TPMA_NV_WRITELOCKED : 1; unsigned int TPMA_NV_WRITEALL : 1; unsigned int TPMA_NV_WRITEDEFINE : 1; unsigned int TPMA_NV_WRITE_STCLEAR : 1; unsigned int TPMA_NV_GLOBALLOCK : 1; unsigned int TPMA_NV_PPREAD : 1; unsigned int TPMA_NV_OWNERREAD : 1; unsigned int TPMA_NV_AUTHREAD : 1; unsigned int TPMA_NV_POLICYREAD : 1; unsigned int reserved19 : 5; unsigned int TPMA_NV_NO_DA : 1; unsigned int TPMA_NV_ORDERLY : 1; unsigned int TPMA_NV_CLEAR_STCLEAR : 1; unsigned int TPMA_NV_READLOCKED : 1; unsigned int TPMA_NV_WRITTEN : 1; unsigned int TPMA_NV_PLATFORMCREATE : 1; unsigned int TPMA_NV_READ_STCLEAR : 1; } TPMA_NV ; // Table 196 -- TPMS_NV_PUBLIC Structure typedef struct { u32 index; u16 name_alg; TPMA_NV attr; TPM2B_DIGEST auth_policy; u16 data_size; } TPMS_NV_PUBLIC; // Table 197 -- TPM2B_NV_PUBLIC Structure typedef struct { u16 size; TPMS_NV_PUBLIC nv_public; } NV_PUBLIC_2B; typedef union { NV_PUBLIC_2B t; TPM2B b; } TPM2B_NV_PUBLIC; // Table 198 Definition of TPM2B_CONTEXT_SENSITIVE Structure < IN/OUT> typedef union { struct { u16 size; u8 buffer[MAX_CONTEXT_SIZE]; } t; TPM2B b; } TPM2B_CONTEXT_SENSITIVE; // Table 199 Definition of TPMS_CONTEXT_DATA Structure < IN/OUT, S> typedef struct { TPM2B_DIGEST integrity; TPM2B_CONTEXT_SENSITIVE encrypted; } TPMS_CONTEXT_DATA; // Table 200 Definition of TPM2B_CONTEXT_DATA Structure < IN/OUT> typedef union { struct { u16 size; u8 buffer[sizeof(TPMS_CONTEXT_DATA)]; } t; TPM2B b; } TPM2B_CONTEXT_DATA; // Table 201 Definition of TPMS_CONTEXT Structure typedef struct { u64 sequence; TPMI_DH_CONTEXT savedHandle; TPMI_RH_HIERARCHY hierarchy; TPM2B_CONTEXT_DATA contextBlob; } TPMS_CONTEXT; // Table 203 -- TPMS_CREATION_DATA Structure typedef struct { TPML_PCR_SELECTION pcr_select; TPM2B_DIGEST pcr_digest; TPMA_LOCALITY locality; u16 parent_name_alg; TPM2B_NAME parent_name; TPM2B_NAME parent_qualified_name; TPM2B_DATA outside_info; } TPMS_CREATION_DATA; // Table 204 -- TPM2B_CREATION_DATA Structure typedef struct { u16 size; TPMS_CREATION_DATA data; } CREATION_DATA_2B; typedef union { CREATION_DATA_2B t; TPM2B b; } TPM2B_CREATION_DATA; #define MAX_SESSIONS 3 // Input structure for session data for a single session, typedef struct { u32 session_handle; TPM2B_NONCE nonce; TPMA_SESSION session_attr; TPM2B_AUTH hmac; } TPM_CMD_SESSION_DATA_IN ; // Input structure for sessions data. typedef struct { u8 num_sessions; TPM_CMD_SESSION_DATA_IN sessions[MAX_SESSION_NUM]; } TPM_CMD_SESSIONS_IN; // Output structure for session data for a single session. typedef struct { TPM2B_NONCE nonce; TPMA_SESSION session_attr; TPM2B_AUTH hmac; } TPM_CMD_SESSION_DATA_OUT; // Output structure for sessions data. typedef struct { u8 num_sessions; TPM_CMD_SESSION_DATA_OUT sessions[MAX_SESSION_NUM]; } TPM_CMD_SESSIONS_OUT; /* * command parameter related structure */ typedef struct { TPML_PCR_SELECTION pcr_selection; } tpm_pcr_read_in; typedef struct { u32 pcr_update_counter; TPML_PCR_SELECTION pcr_selection; TPML_DIGEST pcr_values; } tpm_pcr_read_out; typedef struct { u32 pcr_handle; TPM_CMD_SESSIONS_IN sessions; TPML_DIGEST_VALUES digests; } tpm_pcr_extend_in; typedef struct { TPM_CMD_SESSIONS_OUT sessions; } tpm_pcr_extend_out; typedef struct { u32 pcr_handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_EVENT data; } tpm_pcr_event_in; typedef struct { TPML_DIGEST_VALUES digests; TPM_CMD_SESSIONS_OUT sessions; } tpm_pcr_event_out; typedef struct { u32 pcr_handle; TPM_CMD_SESSIONS_IN sessions; } tpm_pcr_reset_in; typedef struct { TPM_CMD_SESSIONS_OUT sessions; } tpm_pcr_reset_out; typedef struct { TPM2B_AUTH auth; u16 hash_alg; } tpm_sequence_start_in; typedef struct { u32 handle; } tpm_sequence_start_out; typedef struct { u32 handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_MAX_BUFFER buf; } tpm_sequence_update_in; typedef struct { TPM_CMD_SESSIONS_OUT sessions; } tpm_sequence_update_out; typedef struct { u32 pcr_handle; u32 seq_handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_MAX_BUFFER buf; } tpm_sequence_complete_in; typedef struct { TPML_DIGEST_VALUES results; TPM_CMD_SESSIONS_OUT sessions; } tpm_sequence_complete_out; typedef struct { u32 seq_handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_MAX_BUFFER buf; u32 hierarchy; } tpm_sequence_complete2_in; typedef struct { TPML_DIGEST_VALUES results; TPMT_TK_HASHCHECK validation; TPM_CMD_SESSIONS_OUT sessions; } tpm_sequence_complete2_out; typedef struct { u32 handle; u32 index; TPM_CMD_SESSIONS_IN sessions; u16 size; u16 offset; } tpm_nv_read_in; typedef struct { TPM2B_MAX_NV_BUFFER data; TPM_CMD_SESSIONS_OUT sessions; } tpm_nv_read_out; typedef struct { u32 handle; u32 index; TPM_CMD_SESSIONS_IN sessions; TPM2B_MAX_NV_BUFFER data; u16 offset; } tpm_nv_write_in; typedef struct { TPM_CMD_SESSIONS_OUT sessions; } tpm_nv_write_out; typedef struct { u32 handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_AUTH auth; TPM2B_NV_PUBLIC public_info; } tpm_nv_define_space_in; typedef struct { TPM_CMD_SESSIONS_OUT sessions; } tpm_nv_define_space_out; typedef struct { u32 handle; u32 index; TPM_CMD_SESSIONS_IN sessions; } tpm_nv_undefine_space_in; typedef struct { TPM_CMD_SESSIONS_OUT sessions; } tpm_nv_undefine_space_out; typedef struct { u32 index; } tpm_nv_read_public_in; typedef struct { TPM2B_NV_PUBLIC nv_public; TPM2B_NAME nv_name; } tpm_nv_read_public_out; typedef struct { u16 bytes_req; } tpm_get_random_in; typedef struct { TPM2B_DIGEST random_bytes; } tpm_get_random_out; typedef struct { u32 capability; u32 property; u32 property_count; } tpm_get_capability_in; typedef struct { u8 more_data; TPMS_CAPABILITY_DATA data; } tpm_get_capability_out; typedef struct { u32 primary_handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_SENSITIVE_CREATE sensitive; TPM2B_PUBLIC public; TPM2B_DATA outside_info; TPML_PCR_SELECTION creation_pcr; } tpm_create_primary_in; typedef struct { u32 obj_handle; TPM2B_PUBLIC public; TPM2B_CREATION_DATA creation_data; TPM2B_DIGEST creation_hash; TPMT_TK_CREATION creation_ticket; TPM2B_NAME name; TPM_CMD_SESSIONS_OUT sessions; } tpm_create_primary_out; typedef struct { u32 parent_handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_SENSITIVE_CREATE sensitive; TPM2B_PUBLIC public; TPM2B_DATA outside_info; TPML_PCR_SELECTION creation_pcr; } tpm_create_in; typedef struct { TPM2B_PRIVATE private; TPM2B_PUBLIC public; TPM2B_CREATION_DATA creation_data; TPM2B_DIGEST creation_hash; TPMT_TK_CREATION creation_ticket; TPM_CMD_SESSIONS_OUT sessions; } tpm_create_out; typedef struct { u32 parent_handle; TPM_CMD_SESSIONS_IN sessions; TPM2B_PRIVATE private; TPM2B_PUBLIC public; } tpm_load_in; typedef struct { u32 obj_handle; TPM2B_NAME name; TPM_CMD_SESSIONS_OUT sessions; } tpm_load_out; typedef struct { u32 item_handle; TPM_CMD_SESSIONS_IN sessions; } tpm_unseal_in; typedef struct { TPM2B_SENSITIVE_DATA data; TPM_CMD_SESSIONS_OUT sessions; } tpm_unseal_out; typedef struct { TPMI_DH_CONTEXT saveHandle; } tpm_contextsave_in; typedef struct { TPMS_CONTEXT context; } tpm_contextsave_out; typedef struct { TPMS_CONTEXT context; } tpm_contextload_in; typedef struct { TPMI_DH_CONTEXT loadedHandle; } tpm_contextload_out; typedef struct { TPMI_DH_CONTEXT flushHandle; } tpm_flushcontext_in; #endif /* __TPM20_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/acmod.h0000644000000000000000000001430014210363175015700 0ustar 00000000000000/* * acmod.c: support functions for use of Intel(r) TXT Authenticated * Code (AC) Modules * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_ACMOD_H__ #define __TXT_ACMOD_H__ /* * authenticated code (AC) module header (ver 0.0) */ typedef union { uint16_t _raw; struct { uint16_t reserved : 14; uint16_t pre_production : 1; uint16_t debug_signed : 1; }; } acm_flags_t; typedef struct { uint16_t module_type; uint16_t module_subtype; uint32_t header_len; uint32_t header_ver; /* currently 0.0 */ uint16_t chipset_id; acm_flags_t flags; uint32_t module_vendor; uint32_t date; uint32_t size; uint16_t txt_svn; uint16_t se_svn; uint32_t code_control; uint32_t error_entry_point; uint32_t gdt_limit; uint32_t gdt_base; uint32_t seg_sel; uint32_t entry_point; uint8_t reserved2[64]; uint32_t key_size; uint32_t scratch_size; uint8_t rsa2048_pubkey[256]; uint32_t pub_exp; uint8_t rsa2048_sig[256]; uint32_t scratch[143];// uint8_t user_area[]; } acm_hdr_t; extern acm_hdr_t *g_sinit; /* value of module_type field */ #define ACM_TYPE_CHIPSET 0x02 /* value of module_subtype field */ #define ACM_SUBTYPE_RESET 0x01 /* value of module_vendor field */ #define ACM_VENDOR_INTEL 0x8086 /* ranges of padding present in TXTCR_SINIT_SIZE reg */ #define ACM_SIZE_MIN_PADDING 0x10000 #define ACM_SIZE_MAX_PADDING 0x40000 typedef union { uint32_t _raw; struct { uint32_t ext_policy : 2; uint32_t tpm_family : 4; uint32_t tpm_nv_index_set : 1; uint32_t reserved : 25; }; } tpm_cap_t; /* ext_policy field values */ #define TPM_EXT_POLICY_ILLEGAL 0x00 #define TPM_EXT_POLICY_ALG_AGILE_CMD 0x01 #define TPM_EXT_POLICY_EMBEDED_ALGS 0x10 #define TPM_EXT_POLICY_BOTH 0x11 /* tpm_family field values */ #define TPM_FAMILY_ILLEGAL 0x0000 #define TPM_FAMILY_DTPM_12 0x0001 #define TPM_FAMILY_DTPM_20 0x0010 #define TPM_FAMILY_DTPM_BOTH 0x0011 #define TPM_FAMILY_PTT_20 0x1000 typedef struct { tpm_cap_t capabilities; uint16_t count; uint16_t alg_id[]; } tpm_info_list_t; typedef struct __packed { uuid_t uuid; uint8_t chipset_acm_type; uint8_t version; /* currently 7 */ uint16_t length; uint32_t chipset_id_list; uint32_t os_sinit_data_ver; uint32_t min_mle_hdr_ver; txt_caps_t capabilities; uint8_t acm_ver; uint8_t acm_revision[3]; /* versions >= 4 */ uint32_t processor_id_list; /* versions >= 5 */ uint32_t tpm_info_list_off; } acm_info_table_t; /* ACM UUID value */ #define ACM_UUID_V3 {0x7fc03aaa, 0x46a7, 0x18db, 0xac2e, \ {0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a}} /* chipset_acm_type field values */ #define ACM_CHIPSET_TYPE_BIOS 0x00 #define ACM_CHIPSET_TYPE_SINIT 0x01 #define ACM_CHIPSET_TYPE_BIOS_REVOC 0x08 #define ACM_CHIPSET_TYPE_SINIT_REVOC 0x09 typedef struct __packed { uint32_t flags; uint16_t vendor_id; uint16_t device_id; uint16_t revision_id; uint16_t reserved; uint32_t extended_id; } acm_chipset_id_t; typedef struct __packed { uint32_t count; acm_chipset_id_t chipset_ids[]; } acm_chipset_id_list_t; typedef struct __packed { uint32_t fms; uint32_t fms_mask; uint64_t platform_id; uint64_t platform_mask; } acm_processor_id_t; typedef struct __packed { uint32_t count; acm_processor_id_t processor_ids[]; } acm_processor_id_list_t; extern void print_txt_caps(const char *prefix, txt_caps_t caps); extern bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern acm_hdr_t *copy_racm(const acm_hdr_t *racm); extern bool verify_racm(const acm_hdr_t *acm_hdr); extern bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern bool does_acmod_match_platform(const acm_hdr_t* hdr); extern acm_hdr_t *copy_sinit(const acm_hdr_t *sinit); extern bool verify_acmod(const acm_hdr_t *acm_hdr); extern uint32_t get_supported_os_sinit_data_ver(const acm_hdr_t* hdr); extern txt_caps_t get_sinit_capabilities(const acm_hdr_t* hdr); extern tpm_info_list_t *get_tpm_info_list(const acm_hdr_t* hdr); extern void verify_IA32_se_svn_status(const acm_hdr_t *acm_hdr); #endif /* __TXT_ACMOD_H__ */ /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/config_regs.h0000644000000000000000000001617514210363175017116 0ustar 00000000000000/* * config_regs.h: Intel(r) TXT configuration register -related definitions * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_CONFIG_REGS_H__ #define __TXT_CONFIG_REGS_H__ /* * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE) */ #define TXT_PUB_CONFIG_REGS_BASE 0xfed30000 #define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 #define TXT_CONFIG_REGS_SIZE (TXT_PUB_CONFIG_REGS_BASE - \ TXT_PRIV_CONFIG_REGS_BASE) /* offsets to config regs (from either public or private _BASE) */ #define TXTCR_STS 0x0000 #define TXTCR_ESTS 0x0008 #define TXTCR_ERRORCODE 0x0030 #define TXTCR_CMD_RESET 0x0038 #define TXTCR_CMD_CLOSE_PRIVATE 0x0048 #define TXTCR_VER_FSBIF 0x0100 #define TXTCR_DIDVID 0x0110 #define TXTCR_VER_QPIIF 0x0200 #define TXTCR_CMD_UNLOCK_MEM_CONFIG 0x0218 #define TXTCR_SINIT_BASE 0x0270 #define TXTCR_SINIT_SIZE 0x0278 #define TXTCR_MLE_JOIN 0x0290 #define TXTCR_HEAP_BASE 0x0300 #define TXTCR_HEAP_SIZE 0x0308 #define TXTCR_MSEG_BASE 0x0310 #define TXTCR_MSEG_SIZE 0x0318 #define TXTCR_DPR 0x0330 #define TXTCR_CMD_OPEN_LOCALITY1 0x0380 #define TXTCR_CMD_CLOSE_LOCALITY1 0x0388 #define TXTCR_CMD_OPEN_LOCALITY2 0x0390 #define TXTCR_CMD_CLOSE_LOCALITY2 0x0398 #define TXTCR_PUBLIC_KEY 0x0400 #define TXTCR_CMD_SECRETS 0x08e0 #define TXTCR_CMD_NO_SECRETS 0x08e8 #define TXTCR_E2STS 0x08f0 /* * format of ERRORCODE register */ typedef union { uint64_t _raw; struct { uint64_t type : 30; /* external-specific error code */ uint64_t external : 1; /* 0=from proc, 1=from external SW */ uint64_t valid : 1; /* 1=valid */ }; } txt_errorcode_t; /* * format of ESTS register */ typedef union { uint64_t _raw; struct { uint64_t txt_reset_sts : 1; }; } txt_ests_t; /* * format of E2STS register */ typedef union { uint64_t _raw; struct { uint64_t reserved : 1; uint64_t secrets_sts : 1; }; } txt_e2sts_t; /* * format of STS register */ typedef union { uint64_t _raw; struct { uint64_t senter_done_sts : 1; uint64_t sexit_done_sts : 1; uint64_t reserved1 : 4; uint64_t mem_config_lock_sts : 1; uint64_t private_open_sts : 1; uint64_t reserved2 : 7; uint64_t locality_1_open_sts : 1; uint64_t locality_2_open_sts : 1; }; } txt_sts_t; /* * format of DIDVID register */ typedef union { uint64_t _raw; struct { uint16_t vendor_id; uint16_t device_id; uint16_t revision_id; uint16_t reserved; }; } txt_didvid_t; /* * format of VER.FSBIF and VER.QPIIF registers */ typedef union { uint64_t _raw; struct { uint64_t reserved : 31; uint64_t prod_fused : 1; }; } txt_ver_fsbif_qpiif_t; /* * format of DPR register */ typedef union { uint64_t _raw; struct { uint64_t lock : 1; uint64_t reserved1 : 3; uint64_t size : 8; uint64_t reserved2 : 8; uint64_t top : 12; uint64_t reserved3 : 32; }; } txt_dpr_t; /* * RLP JOIN structure for GETSEC[WAKEUP] and MLE_JOIN register */ typedef struct { uint32_t gdt_limit; uint32_t gdt_base; uint32_t seg_sel; /* cs (ds, es, ss are seg_sel+8) */ uint32_t entry_point; /* phys addr */ } mle_join_t; /* * format of MSEG header */ typedef struct { uint32_t revision_id; uint32_t smm_mon_feat; uint32_t gdtr_limit; uint32_t gdtr_base_offset; uint32_t cs_sel; uint32_t eip_offset; uint32_t esp_offset; uint32_t cr3_offset; } mseg_hdr_t; /* * fns to read/write TXT config regs */ static inline uint64_t read_reg64(uint32_t config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(unsigned long)(config_regs_base + reg); } static inline uint32_t read_reg32(uint32_t config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint32_t *)(unsigned long)(config_regs_base + reg); } static inline void write_reg64(uint32_t config_regs_base, uint32_t reg, uint64_t val) { /* these are MMIO so make sure compiler doesn't optimize */ *(volatile uint64_t *)(unsigned long)(config_regs_base + reg) = val; } static inline void write_reg32(uint32_t config_regs_base, uint32_t reg, uint32_t val) { /* these are MMIO so make sure compiler doesn't optimize */ *(volatile uint32_t *)(unsigned long)(config_regs_base + reg) = val; } static inline uint64_t read_pub_config_reg(uint32_t reg) { return read_reg64(TXT_PUB_CONFIG_REGS_BASE, reg); } static inline void write_pub_config_reg(uint32_t reg, uint64_t val) { write_reg64(TXT_PUB_CONFIG_REGS_BASE, reg, val); } static inline uint64_t read_priv_config_reg(uint32_t reg) { return read_reg64(TXT_PRIV_CONFIG_REGS_BASE, reg); } static inline void write_priv_config_reg(uint32_t reg, uint64_t val) { write_reg64(TXT_PRIV_CONFIG_REGS_BASE, reg, val); } #endif /* __TXT_CONFIG_REGS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/errorcode.h0000644000000000000000000000744114210363175016611 0ustar 00000000000000/* * errorcode.h: Intel(r) TXT error definitions for ERRORCODE config register * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_ERRORCODE_H__ #define __TXT_ERRORCODE_H__ /* * error values for processor error codes (ERRORCODE.external = 0) */ #define TXT_ERR_PROC_LEGACY_SHUTDOWN 0 #define TXT_ERR_PROC_INVALID_ACM_MEM_TYPE 5 #define TXT_ERR_PROC_UNSUPPORTED_ACM 6 #define TXT_ERR_PROC_AUTH_FAIL 7 #define TXT_ERR_PROC_INVALID_ACM_FORMAT 8 #define TXT_ERR_PROC_UNEXPECTED_HITM 9 #define TXT_ERR_PROC_INVALID_EVENT 10 #define TXT_ERR_PROC_INVALID_JOIN_FORMAT 11 #define TXT_ERR_PROC_UNRECOVERABLE_MCE 12 #define TXT_ERR_PROC_VMX_ABORT 13 #define TXT_ERR_PROC_ACM_CORRUPT 14 #define TXT_ERR_PROC_INVALID_VIDB_RATIO 15 /* * for SW errors (ERRORCODE.external = 1) */ typedef union { uint32_t _raw; struct { uint32_t err1 : 15; /* specific to src */ uint32_t src : 1; /* 0=ACM, 1=other */ uint32_t err2 : 14; /* specific to src */ uint32_t external : 1; /* always 1 for this type */ uint32_t valid : 1; /* always 1 */ }; } txt_errorcode_sw_t; /* * ACM errors (txt_errorcode_sw_t.src=0), format of err1+src+err2 fields */ typedef union __attribute__((packed)){ uint32_t _raw; struct __attribute__((packed)){ uint32_t acm_type : 4; /* 0000=BIOS ACM, 0001=SINIT, */ /* 0010-1111=reserved */ uint32_t progress : 6; uint32_t error : 5; uint32_t src : 1; /* above value */ union __attribute__((packed)){ struct __attribute__((packed)) { /* progress=0x0d, error=1010 */ uint32_t tpm_err : 9; uint32_t reserved1 : 5; }; struct __attribute__((packed)) { /* progress=0x10 */ uint32_t lcp_minor : 6; uint32_t lcp_index : 3; uint32_t reserved2 : 5; }; }; /* sub-error */ }; } acmod_error_t; #endif /* __TXT_ERRORCODE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/heap.h0000644000000000000000000003267414210363175015550 0ustar 00000000000000/* * heap.h: Intel(r) TXT heap definitions * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_HEAP_H__ #define __TXT_HEAP_H__ /* * Extensible TXT heap data structure */ typedef struct __packed { uint32_t type; uint32_t size; uint8_t data[]; } heap_ext_data_element_t; /* * HEAP_END_ELEMENT */ #define HEAP_EXTDATA_TYPE_END 0 /* size == 8; there is no data[] */ /* * HEAP_BIOS_SPEC_VER_ELEMENT */ #define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1 typedef struct __packed { uint16_t spec_ver_major; uint16_t spec_ver_minor; uint16_t spec_ver_rev; } heap_bios_spec_ver_elt_t; /* * HEAP_ACM_ELEMENT */ #define HEAP_EXTDATA_TYPE_ACM 2 typedef struct __packed { uint32_t num_acms; uint64_t acm_addrs[]; } heap_acm_elt_t; /* * HEAP_CUSTOM_ELEMENT */ #define HEAP_EXTDATA_TYPE_CUSTOM 4 typedef struct __packed { uuid_t uuid; uint8_t data[]; } heap_custom_elt_t; /* * HEAP_EVENT_LOG_POINTER_ELEMENT */ #define HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5 typedef struct __packed { uint64_t event_log_phys_addr; } heap_event_log_ptr_elt_t; typedef struct __packed { uint32_t pcr_index; uint32_t type; sha1_hash_t digest; uint32_t data_size; uint8_t data[]; } tpm12_pcr_event_t; //Event Log Header /* To allow parsers to identify the log format based on the content of the log, the first event of the log is formatted as a TCG_PCR_EVENT structure independent of the format for the rest of the log. A parser may read the first event of type TCG_PCR_EVENT and because of its fixed size, easily find the event data. The fields of the event log header are defined to be PCRIndex of 0, EventType of EV_NO_ACTION, Digest of 20 bytes of 0, and Event content defined as TCG_EfiSpecIDEventStruct. This first event is the event log header. */ typedef struct __packed { uint32_t pcr_index; //pcr_index event extended to uint32_t event_type; //Type of event (see EFI specs) uint8_t digest[20];//Value extended into pcr_index uint32_t event_data_size; //Size of the event data uint8_t event_data[]; //The event data Structure to be added to the Event Log } tcg_pcr_event; typedef struct { uint16_t hash_alg; uint8_t digest[]; } TPMT_HA_1; typedef struct { uint32_t count; TPMT_HA_1 digests[5]; } TPML_DIGEST_VALUES_1; //TCG compliant TPM event log typedef struct __packed { uint32_t pcr_index; uint32_t event_type; TPML_DIGEST_VALUES_1 digest; //List of digests extended to pcr_index banks uint32_t event_size; uint8_t event[]; } tcg_pcr_event2; typedef struct __packed { uint16_t algorithm_id; uint16_t digest_size; } tcg_efi_spec_id_event_algorithm_size; typedef struct __packed { uint8_t signature[16]; uint32_t platform_class; uint8_t spec_version_minor; uint8_t spec_version_major; uint8_t spec_errata; uint8_t uintn_size; uint32_t number_of_algorithms; tcg_efi_spec_id_event_algorithm_size digestSizes[5]; uint8_t vendor_info_size; uint8_t vendor_info[]; } tcg_efi_specid_event_strcut; #define EVTLOG_SIGNATURE "TXT Event Container\0" #define EVTLOG_CNTNR_MAJOR_VER 1 #define EVTLOG_CNTNR_MINOR_VER 0 #define EVTLOG_EVT_MAJOR_VER 1 #define EVTLOG_EVT_MINOR_VER 0 typedef struct __packed { uint8_t signature[20]; uint8_t reserved[12]; uint8_t container_ver_major; uint8_t container_ver_minor; uint8_t pcr_event_ver_major; uint8_t pcr_event_ver_minor; uint32_t size; uint32_t pcr_events_offset; uint32_t next_event_offset; tpm12_pcr_event_t pcr_events[]; } event_log_container_t; /* * HEAP_EVENT_LOG_POINTER_ELEMENT2 */ #define HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2 7 #define HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2_1 8 #define DIGEST_ALG_ID_SHA_1 0x00000001 #define DIGEST_ALG_ID_SHA_256 0x00000002 #define DIGEST_ALG_ID_SHA_384 0x00000003 #define DIGEST_ALG_ID_SHA_512 0x00000004 #define DIGEST_ALG_ID_SM3 0x00000005 static inline unsigned int get_evtlog_digest_id(uint16_t hash_alg) { if ( hash_alg == TB_HALG_SHA1 ) return DIGEST_ALG_ID_SHA_1; else if ( hash_alg == TB_HALG_SHA256 ) return DIGEST_ALG_ID_SHA_256; else if ( hash_alg == TB_HALG_SM3 ) return DIGEST_ALG_ID_SM3; else if ( hash_alg == TB_HALG_SHA384 ) return DIGEST_ALG_ID_SHA_384; else if ( hash_alg == TB_HALG_SHA512 ) return DIGEST_ALG_ID_SHA_512; else return 0; } typedef struct __packed { uint8_t signature[16]; uint32_t revision; uint32_t digest_id; uint32_t digest_size; } tpm20_log_descr_t; typedef struct __packed { uint16_t alg; uint16_t reserved; uint64_t phys_addr; uint32_t size; uint32_t pcr_events_offset; uint32_t next_event_offset; } heap_event_log_descr_t; typedef struct __packed { uint32_t count; heap_event_log_descr_t event_log_descr[]; } heap_event_log_ptr_elt2_t; typedef struct { uint64_t phys_addr; uint32_t allcoated_event_container_size; uint32_t first_record_offset; uint32_t next_record_offset; } heap_event_log_ptr_elt2_1_t; /* * data-passing structures contained in TXT heap: * - BIOS * - OS/loader to MLE * - OS/loader to SINIT * - SINIT to MLE */ /* * BIOS structure */ #define PLATFORM_TYPE_CLIENT 0x01 #define PLATFORM_TYPE_SERVER 0x02 typedef struct __packed { uint32_t sinit; struct { /* versions >= 5 */ uint32_t ppi_supported : 1; /* versions >= 6 */ uint32_t platform_type : 2; uint32_t reserved : 29; } mle; } bios_data_flags_t; typedef struct __packed { uint32_t version; /* currently 2-6 */ uint32_t bios_sinit_size; uint64_t lcp_pd_base; uint64_t lcp_pd_size; uint32_t num_logical_procs; /* versions >= 3 */ union { uint64_t raw; bios_data_flags_t bits; /* For TPM2, it is divided into sinit_flag and mle_flag */ } flags; /* versions >= 4 */ heap_ext_data_element_t ext_data_elts[]; } bios_data_t; /* * OS/loader to MLE structure * - private to tboot (so can be any format we need) */ #define MAX_LCP_PO_DATA_SIZE 64*1024 /* 64k */ #define MAX_EVENT_LOG_SIZE 5*4*1024 /* 4k*5 */ typedef struct __packed { uint32_t version; /* currently 3 */ mtrr_state_t saved_mtrr_state; /* saved prior to changes for SINIT */ void *lctx_addr; /* needs to be restored to ebx */ uint32_t saved_misc_enable_msr; /* saved prior to SENTER */ /* PO policy data */ uint8_t lcp_po_data[MAX_LCP_PO_DATA_SIZE]; /* buffer for tpm event log */ uint8_t event_log_buffer[MAX_EVENT_LOG_SIZE]; } os_mle_data_t; #define MIN_OS_SINIT_DATA_VER 4 #define MAX_OS_SINIT_DATA_VER 7 #define OS_SINIT_FLAGS_EXTPOL_MASK 0x00000001 /* * OS/loader to SINIT structure */ typedef struct __packed { uint32_t version; /* currently 4-7 */ uint32_t flags; /* For TPM2: BIT0:= PCR Extend Policy Control */ uint64_t mle_ptab; uint64_t mle_size; uint64_t mle_hdr_base; uint64_t vtd_pmr_lo_base; uint64_t vtd_pmr_lo_size; uint64_t vtd_pmr_hi_base; uint64_t vtd_pmr_hi_size; uint64_t lcp_po_base; uint64_t lcp_po_size; txt_caps_t capabilities; /* versions >= 5 */ uint64_t efi_rsdt_ptr; /* versions >= 6 */ heap_ext_data_element_t ext_data_elts[]; } os_sinit_data_t; /* * SINIT to MLE structure */ #define MDR_MEMTYPE_GOOD 0x00 #define MDR_MEMTYPE_SMM_OVERLAY 0x01 #define MDR_MEMTYPE_SMM_NONOVERLAY 0x02 #define MDR_MEMTYPE_PCIE_CONFIG_SPACE 0x03 #define MDR_MEMTYPE_PROTECTED 0x04 typedef struct __packed { uint64_t base; uint64_t length; uint8_t mem_type; uint8_t reserved[7]; } sinit_mdr_t; typedef struct __packed { uint32_t version; /* currently 6-9 */ sha1_hash_t bios_acm_id; /* only for tpm1.2 */ uint32_t edx_senter_flags; /* only for tpm1.2 */ uint64_t mseg_valid; /* only for tpm1.2 */ sha1_hash_t sinit_hash; /* only for tpm1.2 */ sha1_hash_t mle_hash; /* only for tpm1.2 */ sha1_hash_t stm_hash; /* only for tpm1.2 */ sha1_hash_t lcp_policy_hash; /* only for tpm1.2 */ uint32_t lcp_policy_control; /* only for tpm1.2 */ uint32_t rlp_wakeup_addr; uint32_t reserved; uint32_t num_mdrs; uint32_t mdrs_off; uint32_t num_vtd_dmars; uint32_t vtd_dmars_off; /* versions >= 8 */ uint32_t proc_scrtm_status; /* only for tpm1.2 */ /* versions >= 9 */ heap_ext_data_element_t ext_data_elts[]; } sinit_mle_data_t; /* * TXT heap data format and field accessor fns */ /* * offset length field * ------ ------ ----- * 0 8 bios_data_size * 8 bios_data_size - 8 bios_data * * bios_data_size 8 os_mle_data_size * bios_data_size + os_mle_data_size - 8 os_mle_data * 8 * * bios_data_size + 8 os_sinit_data_size * os_mle_data_size * bios_data_size + os_sinit_data_size - 8 os_sinit_data * os_mle_data_size + * 8 * * bios_data_size + 8 sinit_mle_data_size * os_mle_data_size + * os_sinit_data_size * bios_data_size + sinit_mle_data_size - 8 sinit_mle_data * os_mle_data_size + * os_sinit_data_size + * 8 */ typedef void txt_heap_t; /* this is a common use with annoying casting, so make it an inline */ static inline txt_heap_t *get_txt_heap(void) { return (txt_heap_t *)(unsigned long)read_pub_config_reg(TXTCR_HEAP_BASE); } static inline uint64_t get_bios_data_size(const txt_heap_t *heap) { return *(uint64_t *)heap; } static inline bios_data_t *get_bios_data_start(const txt_heap_t *heap) { return (bios_data_t *)((char*)heap + sizeof(uint64_t)); } static inline uint64_t get_os_mle_data_size(const txt_heap_t *heap) { return *(uint64_t *)(heap + get_bios_data_size(heap)); } static inline os_mle_data_t *get_os_mle_data_start(const txt_heap_t *heap) { return (os_mle_data_t *)(heap + get_bios_data_size(heap) + sizeof(uint64_t)); } static inline uint64_t get_os_sinit_data_size(const txt_heap_t *heap) { return *(uint64_t *)(heap + get_bios_data_size(heap) + get_os_mle_data_size(heap)); } static inline os_sinit_data_t *get_os_sinit_data_start(const txt_heap_t *heap) { return (os_sinit_data_t *)(heap + get_bios_data_size(heap) + get_os_mle_data_size(heap) + sizeof(uint64_t)); } static inline uint64_t get_sinit_mle_data_size(const txt_heap_t *heap) { return *(uint64_t *)(heap + get_bios_data_size(heap) + get_os_mle_data_size(heap) + get_os_sinit_data_size(heap)); } static inline sinit_mle_data_t *get_sinit_mle_data_start(const txt_heap_t *heap) { return (sinit_mle_data_t *)(heap + get_bios_data_size(heap) + get_os_mle_data_size(heap) + get_os_sinit_data_size(heap) + sizeof(uint64_t)); } extern uint64_t calc_os_sinit_data_size(uint32_t version); extern bool verify_txt_heap(const txt_heap_t *txt_heap, bool bios_data_only); extern bool verify_bios_data(const txt_heap_t *txt_heap); extern void print_os_sinit_data(const os_sinit_data_t *os_sinit_data); extern void print_os_sinit_data_vtdpmr(const os_sinit_data_t *os_sinit_data); #endif /* __TXT_HEAP_H__ */ /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/mtrrs.h0000644000000000000000000001130014210363175015761 0ustar 00000000000000/* * mtrrs.c: Intel(r) TXT MTRR-related definitions * * Copyright (c) 2003-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_MTRRS_H__ #define __TXT_MTRRS_H__ #include enum fix_mtrr_t { MTRR_FIX64K_00000 = 0x250, MTRR_FIX16K_80000 = 0x258, MTRR_FIX16K_A0000 = 0x259, MTRR_FIX4K_C0000 = 0x268, MTRR_FIX4K_C8000 = 0x269, MTRR_FIX4K_D0000 = 0x26A, MTRR_FIX4K_D8000 = 0x26B, MTRR_FIX4K_E0000 = 0x26C, MTRR_FIX4K_E8000 = 0x26D, MTRR_FIX4K_F0000 = 0x26E, MTRR_FIX4K_F8000 = 0x26F }; typedef union { uint64_t raw; uint8_t type[8]; } mtrr_fix_types_t; enum var_mtrr_t { MTRR_PHYS_BASE0_MSR = 0x200, MTRR_PHYS_MASK0_MSR = 0x201, MTRR_PHYS_BASE1_MSR = 0x202, MTRR_PHYS_MASK1_MSR = 0x203, MTRR_PHYS_BASE2_MSR = 0x204, MTRR_PHYS_MASK2_MSR = 0x205, MTRR_PHYS_BASE3_MSR = 0x206, MTRR_PHYS_MASK3_MSR = 0x207, MTRR_PHYS_BASE4_MSR = 0x208, MTRR_PHYS_MASK4_MSR = 0x209, MTRR_PHYS_BASE5_MSR = 0x20A, MTRR_PHYS_MASK5_MSR = 0x20B, MTRR_PHYS_BASE6_MSR = 0x20C, MTRR_PHYS_MASK6_MSR = 0x20D, MTRR_PHYS_BASE7_MSR = 0x20E, MTRR_PHYS_MASK7_MSR = 0x20F }; typedef union { uint64_t raw; struct { uint64_t vcnt : 8; /* num variable MTRR pairs */ uint64_t fix : 1; /* fixed range MTRRs are supported */ uint64_t reserved1 : 1; uint64_t wc : 1; /* write-combining mem type supported */ uint64_t reserved2 : 53; }; } mtrr_cap_t; typedef union { uint64_t raw; struct { uint64_t type : 8; uint64_t reserved1 : 2; uint64_t fe : 1; /* fixed MTRR enable */ uint64_t e : 1; /* (all) MTRR enable */ uint64_t reserved2 : 52; }; } mtrr_def_type_t; typedef union { uint64_t raw; struct { uint64_t type : 8; uint64_t reserved1 : 4; uint64_t base : 52; /* define as max width and mask w/ */ /* MAXPHYADDR when using */ }; } mtrr_physbase_t; typedef union { uint64_t raw; struct { uint64_t reserved1 : 11; uint64_t v : 1; /* valid */ uint64_t mask : 52; /* define as max width and mask w/ */ /* MAXPHYADDR when using */ }; } mtrr_physmask_t; /* current procs only have 8, so this should hold us for a while */ #define MAX_VARIABLE_MTRRS 16 typedef struct { mtrr_def_type_t mtrr_def_type; unsigned int num_var_mtrrs; mtrr_physbase_t mtrr_physbases[MAX_VARIABLE_MTRRS]; mtrr_physmask_t mtrr_physmasks[MAX_VARIABLE_MTRRS]; } mtrr_state_t; extern bool set_mtrrs_for_acmod(const acm_hdr_t *hdr); extern void save_mtrrs(mtrr_state_t *saved_state); extern void set_all_mtrrs(bool enable); extern bool set_mem_type(const void *base, uint32_t size, uint32_t mem_type); extern void restore_mtrrs(const mtrr_state_t *saved_state); extern bool validate_mtrrs(const mtrr_state_t *saved_state); #endif /*__TXT_MTRRS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/smx.h0000644000000000000000000001203114210363175015423 0ustar 00000000000000/* * smx.h: Intel(r) TXT SMX architecture-related definitions * * Copyright (c) 2003-2008, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_SMX_H__ #define __TXT_SMX_H__ /* * GETSEC[] instructions */ /* GETSEC instruction opcode */ #define IA32_GETSEC_OPCODE ".byte 0x0f,0x37" /* GETSEC leaf function codes */ #define IA32_GETSEC_CAPABILITIES 0 #define IA32_GETSEC_ENTERACCS 2 #define IA32_GETSEC_SENTER 4 #define IA32_GETSEC_SEXIT 5 #define IA32_GETSEC_PARAMETERS 6 #define IA32_GETSEC_SMCTRL 7 #define IA32_GETSEC_WAKEUP 8 /* * GETSEC[] leaf functions */ typedef union { uint32_t _raw; struct { uint32_t chipset_present : 1; uint32_t undefined1 : 1; uint32_t enteraccs : 1; uint32_t exitac : 1; uint32_t senter : 1; uint32_t sexit : 1; uint32_t parameters : 1; uint32_t smctrl : 1; uint32_t wakeup : 1; uint32_t undefined9 : 22; uint32_t extended_leafs : 1; }; } capabilities_t; static inline capabilities_t __getsec_capabilities(uint32_t index) { uint32_t cap; __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : "=a"(cap) : "a"(IA32_GETSEC_CAPABILITIES), "b"(index)); return (capabilities_t)cap; } /* helper fn. for getsec_capabilities */ /* this is arbitrary and can be increased when needed */ #define MAX_SUPPORTED_ACM_VERSIONS 16 typedef struct { struct { uint32_t mask; uint32_t version; } acm_versions[MAX_SUPPORTED_ACM_VERSIONS]; int n_versions; uint32_t acm_max_size; uint32_t acm_mem_types; uint32_t senter_controls; bool proc_based_scrtm; bool preserve_mce; } getsec_parameters_t; extern bool get_parameters(getsec_parameters_t *params); static inline void __getsec_senter(uint32_t sinit_base, uint32_t sinit_size) { __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : : "a"(IA32_GETSEC_SENTER), "b"(sinit_base), "c"(sinit_size), "d"(0x0)); } static inline void __getsec_sexit(void) { __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : : "a"(IA32_GETSEC_SEXIT)); } static inline void __getsec_wakeup(void) { __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : : "a"(IA32_GETSEC_WAKEUP)); } static inline void __getsec_smctrl(void) { __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : : "a"(IA32_GETSEC_SMCTRL), "b"(0x0)); } static inline void __getsec_parameters(uint32_t index, int* param_type, uint32_t* peax, uint32_t* pebx, uint32_t* pecx) { uint32_t eax=0, ebx=0, ecx=0; __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : "=a"(eax), "=b"(ebx), "=c"(ecx) : "a"(IA32_GETSEC_PARAMETERS), "b"(index)); if ( param_type != NULL ) *param_type = eax & 0x1f; if ( peax != NULL ) *peax = eax; if ( pebx != NULL ) *pebx = ebx; if ( pecx != NULL ) *pecx = ecx; } static inline void __getsec_enteraccs(uint32_t acm_base, uint32_t acm_size, uint32_t fn) { __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n" : : "a"(IA32_GETSEC_ENTERACCS), "b"(acm_base), "c"(acm_size), "D"(0), "S"(fn)); } #endif /* __TXT_SMX_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/txt.h0000644000000000000000000000534414210363175015444 0ustar 00000000000000/* * txt.h: Intel(r) TXT support functions * * Copyright (c) 2003-2008, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_TXT_H__ #define __TXT_TXT_H__ // #include /* TPM event log types */ #define EVTLOG_UNKNOWN 0 #define EVTLOG_TPM12 1 #define EVTLOG_TPM2_LEGACY 2 #define EVTLOG_TPM2_TCG 3 extern bool txt_is_launched(void); extern void txt_display_errors(void); extern bool txt_has_error(void); extern void txt_get_racm_error(void); extern tb_error_t supports_txt(void); extern tb_error_t txt_verify_platform(void); extern bool txt_prepare_cpu(void); extern tb_error_t txt_launch_environment(loader_ctx *lctx); extern tb_error_t txt_launch_racm(loader_ctx *lctx); extern void txt_post_launch(void); extern tb_error_t txt_protect_mem_regions(void); extern tb_error_t txt_post_launch_verify_platform(void); extern bool txt_s3_launch_environment(void); extern void txt_shutdown(void); extern bool txt_is_powercycle_required(void); extern void ap_wait(unsigned int cpuid); extern int get_evtlog_type(void); extern uint32_t g_using_da; #endif /* __TXT_TXT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/verify.h0000644000000000000000000000427714210363175016135 0ustar 00000000000000/* * verify.h: support functions for platform Intel(r) TXT verification * * Copyright (c) 2003-2008, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_VERIFY_H__ #define __TXT_VERIFY_H__ extern void set_vtd_pmrs(os_sinit_data_t *os_sinit_data, uint64_t min_lo_ram, uint64_t max_lo_ram, uint64_t min_hi_ram, uint64_t max_hi_ram); extern bool verify_e820_map(sinit_mdr_t* mdrs_base, uint32_t num_mdrs); extern bool verify_stm(unsigned int cpuid); extern bool use_mwait(void); #endif /* __TXT_VERIFY_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/txt/vmcs.h0000644000000000000000000003144314210363175015574 0ustar 00000000000000/* * vmcs.h: VMCS definitions for creation of APs mini-guests * * Copyright (c) 2003-2009, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TXT_VMCS_H__ #define __TXT_VMCS_H__ struct vmcs_struct { uint32_t vmcs_revision_id; unsigned char data[0]; /* vmcs size is read from MSR */ }; union vmcs_arbytes { struct arbyte_fields { unsigned int seg_type : 4, s : 1, dpl : 2, p : 1, reserved0 : 4, avl : 1, reserved1 : 1, default_ops_size: 1, g : 1, null_bit : 1, reserved2 : 15; } fields; unsigned int bytes; }; #define CPU_BASED_HLT_EXITING 0x00000080 #define CPU_BASED_INVDPG_EXITING 0x00000200 #define CPU_BASED_MWAIT_EXITING 0x00000400 #define PIN_BASED_EXT_INTR_MASK 0x00000001 #define PIN_BASED_NMI_EXITING 0x00000008 #define VM_EXIT_IA32E_MODE 0x00000200 #define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 #define VM_ENTRY_IA32E_MODE 0x00000200 #define VM_ENTRY_SMM 0x00000400 #define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 /* VMCS Encordings */ enum vmcs_field { GUEST_ES_SELECTOR = 0x00000800, GUEST_CS_SELECTOR = 0x00000802, GUEST_SS_SELECTOR = 0x00000804, GUEST_DS_SELECTOR = 0x00000806, GUEST_FS_SELECTOR = 0x00000808, GUEST_GS_SELECTOR = 0x0000080a, GUEST_LDTR_SELECTOR = 0x0000080c, GUEST_TR_SELECTOR = 0x0000080e, HOST_ES_SELECTOR = 0x00000c00, HOST_CS_SELECTOR = 0x00000c02, HOST_SS_SELECTOR = 0x00000c04, HOST_DS_SELECTOR = 0x00000c06, HOST_FS_SELECTOR = 0x00000c08, HOST_GS_SELECTOR = 0x00000c0a, HOST_TR_SELECTOR = 0x00000c0c, IO_BITMAP_A = 0x00002000, IO_BITMAP_A_HIGH = 0x00002001, IO_BITMAP_B = 0x00002002, IO_BITMAP_B_HIGH = 0x00002003, VM_EXIT_MSR_STORE_ADDR = 0x00002006, VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, VM_EXIT_MSR_LOAD_ADDR = 0x00002008, VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, TSC_OFFSET = 0x00002010, TSC_OFFSET_HIGH = 0x00002011, VIRTUAL_APIC_PAGE_ADDR = 0x00002012, VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, VMCS_LINK_POINTER = 0x00002800, VMCS_LINK_POINTER_HIGH = 0x00002801, GUEST_IA32_DEBUGCTL = 0x00002802, GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, PIN_BASED_VM_EXEC_CONTROL = 0x00004000, CPU_BASED_VM_EXEC_CONTROL = 0x00004002, EXCEPTION_BITMAP = 0x00004004, PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, CR3_TARGET_COUNT = 0x0000400a, VM_EXIT_CONTROLS = 0x0000400c, VM_EXIT_MSR_STORE_COUNT = 0x0000400e, VM_EXIT_MSR_LOAD_COUNT = 0x00004010, VM_ENTRY_CONTROLS = 0x00004012, VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, VM_ENTRY_INTR_INFO_FIELD = 0x00004016, VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, TPR_THRESHOLD = 0x0000401c, SECONDARY_VM_EXEC_CONTROL = 0x0000401e, VM_INSTRUCTION_ERROR = 0x00004400, VM_EXIT_REASON = 0x00004402, VM_EXIT_INTR_INFO = 0x00004404, VM_EXIT_INTR_ERROR_CODE = 0x00004406, IDT_VECTORING_INFO_FIELD = 0x00004408, IDT_VECTORING_ERROR_CODE = 0x0000440a, VM_EXIT_INSTRUCTION_LEN = 0x0000440c, VMX_INSTRUCTION_INFO = 0x0000440e, GUEST_ES_LIMIT = 0x00004800, GUEST_CS_LIMIT = 0x00004802, GUEST_SS_LIMIT = 0x00004804, GUEST_DS_LIMIT = 0x00004806, GUEST_FS_LIMIT = 0x00004808, GUEST_GS_LIMIT = 0x0000480a, GUEST_LDTR_LIMIT = 0x0000480c, GUEST_TR_LIMIT = 0x0000480e, GUEST_GDTR_LIMIT = 0x00004810, GUEST_IDTR_LIMIT = 0x00004812, GUEST_ES_AR_BYTES = 0x00004814, GUEST_CS_AR_BYTES = 0x00004816, GUEST_SS_AR_BYTES = 0x00004818, GUEST_DS_AR_BYTES = 0x0000481a, GUEST_FS_AR_BYTES = 0x0000481c, GUEST_GS_AR_BYTES = 0x0000481e, GUEST_LDTR_AR_BYTES = 0x00004820, GUEST_TR_AR_BYTES = 0x00004822, GUEST_INTERRUPTIBILITY_INFO = 0x00004824, GUEST_ACTIVITY_STATE = 0x00004826, GUEST_SYSENTER_CS = 0x0000482A, HOST_IA32_SYSENTER_CS = 0x00004c00, CR0_GUEST_HOST_MASK = 0x00006000, CR4_GUEST_HOST_MASK = 0x00006002, CR0_READ_SHADOW = 0x00006004, CR4_READ_SHADOW = 0x00006006, CR3_TARGET_VALUE0 = 0x00006008, CR3_TARGET_VALUE1 = 0x0000600a, CR3_TARGET_VALUE2 = 0x0000600c, CR3_TARGET_VALUE3 = 0x0000600e, EXIT_QUALIFICATION = 0x00006400, GUEST_LINEAR_ADDRESS = 0x0000640a, GUEST_CR0 = 0x00006800, GUEST_CR3 = 0x00006802, GUEST_CR4 = 0x00006804, GUEST_ES_BASE = 0x00006806, GUEST_CS_BASE = 0x00006808, GUEST_SS_BASE = 0x0000680a, GUEST_DS_BASE = 0x0000680c, GUEST_FS_BASE = 0x0000680e, GUEST_GS_BASE = 0x00006810, GUEST_LDTR_BASE = 0x00006812, GUEST_TR_BASE = 0x00006814, GUEST_GDTR_BASE = 0x00006816, GUEST_IDTR_BASE = 0x00006818, GUEST_DR7 = 0x0000681a, GUEST_RSP = 0x0000681c, GUEST_RIP = 0x0000681e, GUEST_RFLAGS = 0x00006820, GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, GUEST_SYSENTER_ESP = 0x00006824, GUEST_SYSENTER_EIP = 0x00006826, HOST_CR0 = 0x00006c00, HOST_CR3 = 0x00006c02, HOST_CR4 = 0x00006c04, HOST_FS_BASE = 0x00006c06, HOST_GS_BASE = 0x00006c08, HOST_TR_BASE = 0x00006c0a, HOST_GDTR_BASE = 0x00006c0c, HOST_IDTR_BASE = 0x00006c0e, HOST_IA32_SYSENTER_ESP = 0x00006c10, HOST_IA32_SYSENTER_EIP = 0x00006c12, HOST_RSP = 0x00006c14, HOST_RIP = 0x00006c16, }; enum guest_activity_state { GUEST_STATE_ACTIVE = 0, GUEST_STATE_HALT = 1, GUEST_STATE_SHUTDOWN = 2, GUEST_STATE_WAIT_SIPI = 3, }; #define VMCALL_OPCODE ".byte 0x0f,0x01,0xc1\n" #define VMCLEAR_OPCODE ".byte 0x66,0x0f,0xc7\n" /* reg/opcode: /6 */ #define VMLAUNCH_OPCODE ".byte 0x0f,0x01,0xc2\n" #define VMPTRLD_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /6 */ #define VMPTRST_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /7 */ #define VMREAD_OPCODE ".byte 0x0f,0x78\n" #define VMRESUME_OPCODE ".byte 0x0f,0x01,0xc3\n" #define VMWRITE_OPCODE ".byte 0x0f,0x79\n" #define VMXOFF_OPCODE ".byte 0x0f,0x01,0xc4\n" #define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7\n" #define MODRM_EAX_06 ".byte 0x30\n" /* [EAX], with reg/opcode: /6 */ #define MODRM_EAX_07 ".byte 0x38\n" /* [EAX], with reg/opcode: /7 */ #define MODRM_EAX_ECX ".byte 0xc1\n" /* [EAX], [ECX] */ /* * Exit Reasons */ #define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 #define EXIT_REASON_INIT 3 #define EXIT_REASON_SIPI 4 #define EXIT_REASON_VMCALL 18 #define EXIT_REASON_INVALID_GUEST_STATE 33 #define EXIT_REASON_MSR_LOADING 34 #define EXIT_REASON_MACHINE_CHECK 41 static inline void __vmptrld(uint64_t addr) { /* TBD: do not crash on failure */ __asm__ __volatile__ ( VMPTRLD_OPCODE MODRM_EAX_06 /* CF==1 or ZF==1 --> crash (ud2) */ "ja 1f ; ud2 ; 1:\n" : : "a" (&addr) : "memory"); } static inline void __vmptrst(uint64_t addr) { __asm__ __volatile__ ( VMPTRST_OPCODE MODRM_EAX_07 : : "a" (&addr) : "memory"); } static inline void __vmpclear(uint64_t addr) { /* TBD: do not crash on failure */ __asm__ __volatile__ ( VMCLEAR_OPCODE MODRM_EAX_06 /* CF==1 or ZF==1 --> crash (ud2) */ "ja 1f ; ud2 ; 1:\n" : : "a" (&addr) : "memory"); } static inline unsigned long __vmread(unsigned long field) { unsigned long ecx; /* TBD: do not crash on failure */ __asm__ __volatile__ ( VMREAD_OPCODE MODRM_EAX_ECX /* CF==1 or ZF==1 --> crash (ud2) */ "ja 1f ; ud2 ; 1:\n" : "=c" (ecx) : "a" (field) : "memory"); return ecx; } static inline void __vmwrite(unsigned long field, unsigned long value) { /* TBD: do not crash on failure */ __asm__ __volatile__ ( VMWRITE_OPCODE MODRM_EAX_ECX /* CF==1 or ZF==1 --> crash (ud2) */ "ja 1f ; ud2 ; 1:\n" : : "a" (field) , "c" (value) : "memory"); } static inline void __vmlaunch (void) { __asm__ __volatile__ ( VMLAUNCH_OPCODE ::: "memory"); } static inline void __vmresume (void) { __asm__ __volatile__ ( VMRESUME_OPCODE ::: "memory"); } static inline void __vmxoff (void) { __asm__ __volatile__ ( VMXOFF_OPCODE ::: "memory"); } static inline int __vmxon (uint64_t addr) { int rc; __asm__ __volatile__ ( VMXON_OPCODE MODRM_EAX_06 /* CF==1 or ZF==1 --> rc = -1 */ "setna %b0 ; neg %0" : "=q" (rc) : "0" (0), "a" (&addr) : "memory"); return rc; } extern void handle_init_sipi_sipi(unsigned int cpuid); extern void force_aps_exit(void); #endif /* __TXT_VMCS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/types.h0000644000000000000000000000552414210363175015152 0ustar 00000000000000/* * types.h: defines size-based types for 32b builds * * Copyright (c) 2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TYPES_H__ #define __TYPES_H__ /* Need for other later defines. */ #include #define NULL ((void*)0) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef signed short s16; typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned char u_int8_t; typedef unsigned short u_int16_t; typedef unsigned int u_int32_t; /* * This should be unsigned int but gets an error in * policy.c that expects it to be an unsigned long. */ typedef unsigned long size_t; /* * This is specifically for IA32. */ typedef unsigned int uintptr_t; typedef unsigned long long u64; typedef unsigned long long uint64_t; typedef unsigned long long u_int64_t; #define BYTES_PER_LONG 4 #if __GNUC__ > 3 #define offsetof(type, field) __builtin_offsetof(type, field) #else #define offsetof(type, member) ((size_t) &((type *)0)->member) #endif #endif /* __TYPES_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/vga.h0000644000000000000000000000626414210363175014565 0ustar 00000000000000/* * vga.h: definitions of and supports functions for VGA * * Copyright (c) 2006-2010, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __VGA_H__ #define __VGA_H__ #include #define VGA_BASE 0xb8000 /* 80*25 text mode*/ #define MAX_LINES 25 #define MAX_COLS 80 #define SCREEN_BUFFER (MAX_LINES*MAX_COLS*2) #define VGA_ADDR(x, y) (VGA_BASE + 2*(MAX_COLS*(y) + (x))) /* registers */ #define CTL_ADDR_REG 0x3D4 #define CTL_DATA_REG 0x3D5 #define START_ADD_HIGH_REG 0x0C #define START_ADD_LOW_REG 0x0D /* colors */ #define COLOR_BLACK 0x00 #define COLOR_BLUE 0x01 #define COLOR_GREEN 0x02 #define COLOR_CYAN 0x03 #define COLOR_RED 0x04 #define COLOR_MAGENTA 0x05 #define COLOR_BROWN 0x06 #define COLOR_LTGRAY 0x07 #define COLOR_DKGRAY 0x08 #define COLOR_LTBLUE 0x09 #define COLOR_LTGREEN 0x0A #define COLOR_LTCYAN 0x0B #define COLOR_LTRED 0x0C #define COLOR_LTMAGENTA 0x0D #define COLOR_LTBROWN 0x0E #define COLOR_WHITE 0x0F #define COLOR ((COLOR_BLACK << 4) | COLOR_LTGRAY) /* Framebuffer */ #define FB_SIZE (FB_MAX_HRES * FB_MAX_VRES) #define FB_COLOR 0xffa8a8a8 void vga_init(void); void vga_puts(const char *s, unsigned int cnt); #endif /* __VGA_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/include/vga/LICENSE0000644000000000000000000000325214210363175015413 0ustar 00000000000000font.h is generated from u_vga16.sfn that is a part of UNI-VGA project. u_vga16.sfn is converted from u_vga16.bfd with sfnconv tool. UNI-VGA was created by Dmitry Bolkhovityanov and is distributed under X license. Copyright (c) 2000 Dmitry Bolkhovityanov, bolkhov@inp.nsk.su Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. tboot-1.10.5/tboot/include/vga/font.h0000644000000000000000000131111614210363175015527 0ustar 00000000000000static const unsigned char u_vga16_sfn[] = { 0x53, 0x46, 0x4e, 0x32, 0x3b, 0xe7, 0x00, 0x00, 0x03, 0x00, 0x08, 0x10, 0x0c, 0x0d, 0x7d, 0x00, 0x41, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x67, 0x61, 0x20, 0x55, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x00, 0x56, 0x47, 0x41, 0x00, 0x4d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x00, 0x00, 0x42, 0x6f, 0x6c, 0x6b, 0x68, 0x6f, 0x76, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x30, 0x20, 0x44, 0x6d, 0x69, 0x74, 0x72, 0x79, 0x20, 0x42, 0x6f, 0x6c, 0x6b, 0x68, 0x6f, 0x76, 0x69, 0x74, 0x79, 0x61, 0x6e, 0x6f, 0x76, 0x2c, 0x20, 0x62, 0x6f, 0x6c, 0x6b, 0x68, 0x6f, 0x76, 0x40, 0x69, 0x6e, 0x70, 0x2e, 0x6e, 0x73, 0x6b, 0x2e, 0x73, 0x75, 0x00, 0x80, 0x00, 0x10, 0x80, 0x00, 0x7f, 0x80, 0x01, 0x18, 0x18, 0x80, 0x00, 0x28, 0x80, 0x00, 0x3e, 0x80, 0x01, 0x0c, 0x0c, 0x80, 0x01, 0x30, 0x18, 0x80, 0x01, 0x36, 0x36, 0x80, 0x01, 0x6e, 0x3b, 0x80, 0x06, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x06, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x00, 0x08, 0x80, 0x00, 0x7e, 0x80, 0x00, 0xff, 0x80, 0x00, 0x20, 0x80, 0x06, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x01, 0x36, 0x1c, 0x80, 0x06, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x00, 0x50, 0x80, 0x01, 0x06, 0x0c, 0x80, 0x02, 0x18, 0x18, 0x0c, 0x80, 0x06, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x01, 0x66, 0x66, 0x80, 0x03, 0x02, 0x81, 0x81, 0x7e, 0x80, 0x02, 0x10, 0x10, 0xef, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1f, 0x80, 0x00, 0x18, 0x80, 0x02, 0x08, 0x1c, 0x36, 0x80, 0x03, 0x10, 0x20, 0x20, 0x1f, 0x80, 0x02, 0x36, 0x1c, 0x08, 0x80, 0x01, 0x33, 0x66, 0x80, 0x04, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x80, 0x05, 0x20, 0x40, 0x40, 0x20, 0x18, 0x06, 0x80, 0x06, 0x30, 0x48, 0x70, 0x40, 0x20, 0x18, 0x06, 0x80, 0x03, 0x08, 0x38, 0x28, 0x1c, 0x80, 0x01, 0x77, 0x77, 0x80, 0x08, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x08, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x80, 0x04, 0x36, 0x51, 0x32, 0x14, 0x13, 0x80, 0x01, 0x7f, 0x7f, 0x80, 0x08, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x08, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x06, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x06, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3e, 0x80, 0x00, 0x36, 0x80, 0x06, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x04, 0x60, 0x92, 0xa1, 0xc1, 0x7e, 0x80, 0x09, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x33, 0x1e, 0x80, 0x08, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x01, 0x1c, 0x36, 0x80, 0x03, 0x02, 0x01, 0x81, 0x7e, 0x80, 0x06, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x06, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x80, 0x00, 0x3c, 0x80, 0x02, 0x1c, 0x36, 0x1c, 0x80, 0x01, 0x66, 0x33, 0x80, 0x05, 0x82, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x06, 0xe0, 0x10, 0x11, 0x61, 0x81, 0x81, 0x7e, 0x80, 0x00, 0x3f, 0x80, 0x09, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x06, 0x7f, 0x33, 0x18, 0x0c, 0x06, 0x63, 0x7f, 0x80, 0x01, 0x0c, 0x18, 0x80, 0x08, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x01, 0xc0, 0xc0, 0x80, 0x02, 0x18, 0x18, 0x18, 0x80, 0x06, 0x60, 0x90, 0x8c, 0x79, 0x11, 0x11, 0x0e, 0x80, 0x03, 0x1c, 0xe2, 0x18, 0x07, 0x80, 0x03, 0x0e, 0xf1, 0x4c, 0x83, 0x80, 0x06, 0x30, 0x48, 0xf0, 0x40, 0x20, 0x18, 0x06, 0x80, 0x09, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x01, 0x60, 0x60, 0x80, 0x07, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x00, 0x14, 0x80, 0x08, 0x0e, 0xf1, 0x0c, 0x02, 0x01, 0x01, 0x01, 0x82, 0x7c, 0x80, 0x05, 0x80, 0xa8, 0x11, 0x21, 0x21, 0x1e, 0x80, 0x01, 0x28, 0x10, 0x80, 0x04, 0x70, 0x1c, 0x07, 0x1c, 0x70, 0x80, 0x04, 0x07, 0x1c, 0x70, 0x1c, 0x07, 0x80, 0x09, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x80, 0x09, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x09, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x09, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x09, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63, 0x80, 0x09, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x09, 0x70, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x06, 0x37, 0x7f, 0x6b, 0x6b, 0x6b, 0x6b, 0x63, 0x80, 0x06, 0x63, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63, 0x80, 0x01, 0x18, 0x0c, 0x80, 0x08, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x06, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x70, 0x80, 0x06, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x63, 0x73, 0x7b, 0x7f, 0x6f, 0x67, 0x63, 0x80, 0x01, 0x03, 0x03, 0x80, 0x04, 0x18, 0x24, 0x44, 0x44, 0x38, 0x80, 0x09, 0x0e, 0x01, 0x31, 0x0e, 0x02, 0x01, 0x01, 0x01, 0x82, 0x7c, 0x80, 0x00, 0x02, 0x80, 0x03, 0x08, 0x08, 0x08, 0x08, 0x80, 0x08, 0x20, 0x90, 0x48, 0x20, 0x10, 0x22, 0x41, 0x41, 0x3e, 0x80, 0x02, 0x1c, 0x30, 0x18, 0x80, 0x04, 0x10, 0x10, 0x20, 0x62, 0x9c, 0x80, 0x04, 0xe0, 0x11, 0xe1, 0x81, 0x7e, 0x80, 0x04, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x80, 0x09, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x66, 0x67, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x60, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x63, 0x63, 0x36, 0x3e, 0x1c, 0x1c, 0x3e, 0x36, 0x63, 0x63, 0x80, 0x09, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x7f, 0x63, 0x61, 0x30, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x80, 0x02, 0x0c, 0x0c, 0x18, 0x80, 0x09, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x09, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x80, 0x03, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x80, 0x06, 0x33, 0x6e, 0x6c, 0x7e, 0x1b, 0x1b, 0x76, 0x80, 0x08, 0x3c, 0x66, 0x43, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x80, 0x06, 0x67, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x00, 0x33, 0x80, 0x06, 0x3e, 0x63, 0x60, 0x60, 0x7f, 0x63, 0x3e, 0x80, 0x07, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x3e, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x3e, 0x80, 0x08, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x00, 0x04, 0x80, 0x08, 0x60, 0x90, 0x90, 0xe2, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x06, 0x98, 0x84, 0x98, 0x84, 0x80, 0x81, 0x7e, 0x80, 0x03, 0x30, 0x0c, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0xc8, 0x80, 0x08, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x77, 0x36, 0x80, 0x03, 0x70, 0xc8, 0x5c, 0x36, 0x80, 0x07, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x08, 0x80, 0x02, 0x38, 0x38, 0x38, 0x80, 0x04, 0x30, 0x48, 0x50, 0x60, 0x3f, 0x80, 0x04, 0x30, 0x48, 0x48, 0x30, 0xcf, 0x80, 0x04, 0x20, 0xe0, 0x20, 0x18, 0x06, 0x80, 0x03, 0x60, 0x94, 0x8c, 0x7b, 0x80, 0x03, 0x18, 0x18, 0x18, 0x0c, 0x80, 0x09, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x80, 0x09, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x08, 0x80, 0x09, 0x07, 0x06, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x80, 0x04, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x09, 0x1f, 0x36, 0x66, 0x66, 0x6f, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x80, 0x09, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x18, 0x30, 0x1c, 0x80, 0x01, 0x33, 0x33, 0x80, 0x02, 0x18, 0x0c, 0x0c, 0x80, 0x08, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x80, 0x08, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x60, 0x80, 0x09, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x80, 0x00, 0x0c, 0x80, 0x09, 0x7f, 0x60, 0x30, 0x18, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x06, 0x3e, 0x63, 0x03, 0x1e, 0x03, 0x63, 0x3e, 0x80, 0x06, 0x3e, 0x63, 0x60, 0x3c, 0x60, 0x63, 0x3e, 0x80, 0x06, 0x36, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x36, 0x80, 0x08, 0x63, 0x63, 0x73, 0x7b, 0x7f, 0x6f, 0x67, 0x63, 0x63, 0x80, 0x06, 0x6b, 0x6b, 0x6b, 0x3e, 0x6b, 0x6b, 0x6b, 0x80, 0x06, 0x36, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x80, 0x01, 0x18, 0x66, 0x80, 0x00, 0x66, 0x80, 0x01, 0x06, 0x06, 0x80, 0x04, 0x18, 0x24, 0x04, 0x78, 0x04, 0x80, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x80, 0x03, 0x18, 0x04, 0x38, 0x04, 0x80, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x41, 0x41, 0x21, 0x1e, 0x80, 0x00, 0x24, 0x80, 0x02, 0x60, 0x94, 0x7a, 0x80, 0x05, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x80, 0x08, 0x0e, 0xf1, 0x0c, 0x02, 0x29, 0x01, 0x11, 0x82, 0x7c, 0x80, 0x08, 0x04, 0x1c, 0x14, 0x0e, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x80, 0x00, 0x40, 0x80, 0x03, 0x10, 0x10, 0x10, 0x10, 0x80, 0x01, 0x10, 0x28, 0x80, 0x06, 0xe0, 0x10, 0x11, 0x61, 0x81, 0x41, 0x3e, 0x80, 0x03, 0x18, 0x3c, 0x3c, 0x18, 0x80, 0x06, 0x7f, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x7f, 0x80, 0x04, 0x57, 0x54, 0x72, 0x71, 0x77, 0x80, 0x01, 0xdb, 0xdb, 0x80, 0x06, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x07, 0x08, 0x08, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x63, 0x80, 0x01, 0x3b, 0x6e, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x01, 0xff, 0xff, 0x80, 0x04, 0x60, 0x92, 0x91, 0x61, 0xbe, 0x80, 0x03, 0x38, 0x04, 0x38, 0x04, 0x80, 0x06, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x80, 0x09, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x80, 0x09, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x77, 0x36, 0x80, 0x03, 0x08, 0x1c, 0x36, 0x63, 0x80, 0x06, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x7f, 0x80, 0x03, 0x1c, 0x36, 0x36, 0x1c, 0x80, 0x05, 0x0e, 0x1b, 0x0c, 0x06, 0x13, 0x1f, 0x80, 0x05, 0x0e, 0x1b, 0x0c, 0x18, 0x1b, 0x0e, 0x80, 0x09, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6f, 0x03, 0x03, 0x03, 0x80, 0x05, 0x0c, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x80, 0x0b, 0x08, 0x1c, 0x36, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x09, 0x7c, 0x36, 0x33, 0x33, 0x7f, 0x33, 0x33, 0x33, 0x33, 0x73, 0x80, 0x0c, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x18, 0x30, 0x1c, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x5e, 0x23, 0x73, 0x6b, 0x67, 0x62, 0x3d, 0x80, 0x08, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x80, 0x09, 0x30, 0x7c, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x09, 0x06, 0x1f, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x01, 0x66, 0x3c, 0x80, 0x08, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x08, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x00, 0x1e, 0x80, 0x08, 0x7f, 0x63, 0x31, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x80, 0x09, 0x1e, 0x33, 0x61, 0x60, 0x60, 0x60, 0x60, 0x61, 0x33, 0x1e, 0x80, 0x09, 0x3e, 0x63, 0x60, 0x60, 0x60, 0x7f, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3e, 0x63, 0x43, 0x03, 0x1e, 0x03, 0x03, 0x43, 0x63, 0x3e, 0x80, 0x0b, 0xc0, 0xc0, 0x5e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0xc0, 0xc0, 0x60, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0x7f, 0x63, 0x46, 0x0c, 0x18, 0x18, 0x0c, 0x46, 0x63, 0x7f, 0x80, 0x0b, 0xc0, 0xc0, 0x73, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0xc0, 0xc0, 0x60, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x09, 0x77, 0x36, 0x36, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x7c, 0x36, 0x33, 0x33, 0x7f, 0x33, 0x33, 0x33, 0x73, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x09, 0x1c, 0x18, 0x18, 0xfe, 0x9b, 0x5b, 0x5b, 0x5b, 0x3b, 0xf6, 0x80, 0x01, 0x3c, 0x66, 0x80, 0x09, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x18, 0x30, 0x1c, 0x80, 0x09, 0x4e, 0x39, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x63, 0x62, 0x36, 0x34, 0x34, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0c, 0x08, 0x08, 0x08, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x08, 0x80, 0x06, 0x3f, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x3f, 0x80, 0x06, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x03, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x02, 0x18, 0x0c, 0x06, 0x80, 0x02, 0x18, 0x30, 0x18, 0x80, 0x02, 0x0e, 0x18, 0x0c, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x08, 0x08, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x63, 0x63, 0x7f, 0x80, 0x09, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x09, 0x08, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x36, 0x36, 0x77, 0x80, 0x08, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x06, 0x7f, 0x66, 0x46, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x06, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x80, 0x06, 0xc3, 0xc3, 0xc3, 0xcf, 0xdb, 0xdb, 0xcf, 0x80, 0x06, 0x3e, 0x63, 0x60, 0x7c, 0x60, 0x63, 0x3e, 0x80, 0x06, 0x43, 0x63, 0x26, 0x36, 0x1c, 0x1c, 0x08, 0x80, 0x02, 0x20, 0x3e, 0x02, 0x80, 0x01, 0x3e, 0x2a, 0x80, 0x01, 0x66, 0x18, 0x80, 0x0b, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0xe3, 0xc0, 0x80, 0x80, 0x08, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0xe3, 0xc0, 0x80, 0x80, 0x02, 0x30, 0x30, 0x3c, 0x80, 0x02, 0x18, 0x0c, 0x18, 0x80, 0x07, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x40, 0x3c, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x80, 0x08, 0x18, 0x04, 0x38, 0x04, 0x10, 0x10, 0x10, 0x10, 0x10, 0x80, 0x0a, 0x38, 0x04, 0x38, 0x04, 0x30, 0x48, 0x70, 0x40, 0x20, 0x18, 0x06, 0x80, 0x04, 0x28, 0x02, 0x81, 0x81, 0x7e, 0x80, 0x08, 0x0e, 0xf1, 0x0c, 0x02, 0x01, 0x11, 0x01, 0x82, 0x7c, 0x80, 0x06, 0x04, 0x04, 0x04, 0x34, 0x4c, 0x45, 0x3e, 0x80, 0x06, 0x24, 0x04, 0x04, 0x34, 0x4c, 0x45, 0x3e, 0x80, 0x09, 0x30, 0x48, 0x48, 0x3c, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x80, 0x05, 0x02, 0x0c, 0x72, 0x92, 0x9c, 0x67, 0x80, 0x04, 0x30, 0x48, 0x53, 0x34, 0x0e, 0x80, 0x04, 0x10, 0x28, 0x30, 0x10, 0x08, 0x80, 0x03, 0x50, 0x54, 0x34, 0x08, 0x80, 0x02, 0x18, 0x24, 0x18, 0x80, 0x03, 0x30, 0x08, 0x30, 0x08, 0x80, 0x08, 0x04, 0x0e, 0x0e, 0x1c, 0x18, 0x18, 0x10, 0x10, 0x10, 0x80, 0x08, 0x22, 0x3f, 0x1f, 0x06, 0x0c, 0x0c, 0x08, 0x08, 0x08, 0x80, 0x08, 0x52, 0x7f, 0x2f, 0x06, 0x0c, 0x0c, 0x08, 0x08, 0x08, 0x80, 0x08, 0x41, 0x63, 0x63, 0x36, 0x14, 0x1c, 0x08, 0x08, 0x08, 0x80, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x14, 0x36, 0x63, 0x63, 0x41, 0x80, 0x08, 0x0e, 0x1f, 0x11, 0x1f, 0x1e, 0x10, 0x30, 0x70, 0x60, 0x80, 0x07, 0x08, 0x08, 0x1c, 0x7f, 0x3e, 0x1c, 0x36, 0x22, 0x80, 0x04, 0x20, 0x20, 0x20, 0x20, 0x20, 0x80, 0x02, 0x60, 0x14, 0x7a, 0x80, 0x03, 0xc0, 0x20, 0xc0, 0x20, 0x80, 0x0b, 0xc4, 0x2a, 0xcc, 0x24, 0x02, 0x30, 0x48, 0x70, 0x40, 0x20, 0x18, 0x06, 0x80, 0x08, 0x0e, 0xf1, 0x0c, 0x02, 0x01, 0x29, 0x01, 0x82, 0x7c, 0x80, 0x08, 0x0e, 0xf1, 0x0c, 0x02, 0x11, 0x01, 0x11, 0x82, 0x7c, 0x80, 0x08, 0x0e, 0xf1, 0x0c, 0x02, 0x29, 0x01, 0x29, 0x82, 0x7c, 0x80, 0x05, 0x80, 0xa8, 0x11, 0x11, 0x09, 0xa6, 0x80, 0x00, 0x0a, 0x80, 0x07, 0x80, 0x40, 0x20, 0x10, 0x22, 0x41, 0x41, 0x3e, 0x80, 0x06, 0x94, 0x80, 0x98, 0x84, 0x98, 0x85, 0x7e, 0x80, 0x08, 0x25, 0x90, 0x48, 0x20, 0x10, 0x22, 0x41, 0x41, 0x3e, 0x80, 0x08, 0x1c, 0x02, 0x1c, 0x02, 0x18, 0x24, 0x44, 0x44, 0x38, 0x80, 0x06, 0x30, 0x48, 0x70, 0x40, 0x3c, 0x18, 0x06, 0x80, 0x0b, 0x08, 0x14, 0x18, 0x08, 0x04, 0x30, 0x48, 0x70, 0x40, 0x20, 0x18, 0x06, 0x80, 0x04, 0x10, 0x28, 0x06, 0x01, 0x7f, 0x80, 0x03, 0xa8, 0x51, 0x09, 0x06, 0x80, 0x04, 0x30, 0x30, 0x08, 0x08, 0x08, 0x80, 0x03, 0x08, 0x0c, 0x02, 0x7c, 0x80, 0x04, 0x10, 0x28, 0x44, 0x28, 0x10, 0x80, 0x08, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x80, 0x03, 0x30, 0x18, 0x6e, 0x3b, 0x80, 0x08, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x08, 0x63, 0x63, 0x36, 0x3e, 0x1c, 0x3e, 0x36, 0x63, 0x63, 0x80, 0x03, 0xc0, 0x64, 0x0e, 0x1b, 0x80, 0x03, 0x03, 0x26, 0x70, 0xd8, 0x80, 0x03, 0x66, 0x66, 0x66, 0x33, 0x80, 0x09, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x80, 0x06, 0x49, 0x22, 0x14, 0x49, 0x14, 0x22, 0x49, 0x80, 0x05, 0x0e, 0x1b, 0x1b, 0x1b, 0x1b, 0x0e, 0x80, 0x05, 0x18, 0x1c, 0x1e, 0x1b, 0x3f, 0x18, 0x80, 0x05, 0x1f, 0x03, 0x0f, 0x18, 0x1b, 0x0e, 0x80, 0x05, 0x1e, 0x03, 0x0f, 0x1b, 0x1b, 0x0e, 0x80, 0x05, 0x1f, 0x1b, 0x0c, 0x0c, 0x06, 0x06, 0x80, 0x05, 0x0e, 0x1b, 0x0e, 0x1b, 0x1b, 0x0e, 0x80, 0x05, 0x0e, 0x1b, 0x1b, 0x1e, 0x18, 0x0f, 0x80, 0x04, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x80, 0x05, 0x0c, 0x06, 0x06, 0x06, 0x06, 0x0c, 0x80, 0x05, 0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x06, 0x80, 0x04, 0x0d, 0x1b, 0x1b, 0x1b, 0x1b, 0x80, 0x01, 0xa0, 0xa0, 0x80, 0x06, 0x0f, 0x07, 0x0d, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x02, 0x0c, 0x06, 0xff, 0x80, 0x02, 0xff, 0x06, 0x0c, 0x80, 0x02, 0x30, 0x60, 0xff, 0x80, 0x02, 0xff, 0x60, 0x30, 0x80, 0x04, 0x0c, 0x06, 0x7f, 0x06, 0x0c, 0x80, 0x04, 0x18, 0x30, 0x7f, 0x30, 0x18, 0x80, 0x03, 0x18, 0x24, 0x24, 0x18, 0x80, 0x06, 0x40, 0x60, 0x38, 0x0f, 0x38, 0x60, 0x40, 0x80, 0x06, 0x01, 0x03, 0x0e, 0x78, 0x0e, 0x03, 0x01, 0x80, 0x05, 0x7e, 0x03, 0x03, 0x03, 0x03, 0x7e, 0x80, 0x05, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x3f, 0x80, 0x05, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x80, 0x05, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x7f, 0x80, 0x06, 0x60, 0x78, 0x6e, 0x63, 0x6e, 0x78, 0x60, 0x80, 0x06, 0x03, 0x0f, 0x3b, 0x63, 0x3b, 0x0f, 0x03, 0x80, 0x01, 0x08, 0x08, 0x80, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x80, 0x0f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x80, 0x01, 0xff, 0xc3, 0x80, 0x01, 0xc3, 0xff, 0x80, 0x0f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x80, 0x03, 0x38, 0x38, 0x38, 0x38, 0x80, 0x06, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x07, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x06, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x80, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x02, 0x54, 0x7e, 0x55, 0x80, 0x05, 0x20, 0x20, 0x20, 0x20, 0x20, 0xc0, 0x80, 0x06, 0x60, 0x18, 0x04, 0x08, 0x10, 0x10, 0x0f, 0x80, 0x06, 0x60, 0x18, 0x04, 0x04, 0x08, 0x10, 0xef, 0x80, 0x08, 0x20, 0x90, 0x48, 0x20, 0x10, 0x12, 0x21, 0x41, 0xbe, 0x80, 0x08, 0x30, 0x0c, 0x62, 0x18, 0x04, 0x08, 0x10, 0x10, 0x0f, 0x80, 0x08, 0x30, 0x0c, 0x62, 0x18, 0x04, 0x04, 0x08, 0x10, 0xef, 0x80, 0x05, 0x80, 0x82, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x06, 0x08, 0x1c, 0x32, 0x4a, 0x4c, 0xbc, 0x02, 0x80, 0x03, 0xe0, 0x18, 0x04, 0xfc, 0x80, 0x01, 0x10, 0x08, 0x80, 0x02, 0x60, 0x18, 0x06, 0x80, 0x03, 0x30, 0x08, 0x70, 0x08, 0x80, 0x05, 0x08, 0x08, 0x16, 0x11, 0x2e, 0xc0, 0x80, 0x08, 0x0e, 0xf1, 0x4c, 0x82, 0x01, 0x01, 0x01, 0x02, 0x7c, 0x80, 0x02, 0x80, 0xa8, 0x57, 0x80, 0x01, 0x54, 0xab, 0x80, 0x09, 0x78, 0x44, 0x38, 0x44, 0x82, 0x01, 0x01, 0x01, 0x82, 0x7c, 0x80, 0x03, 0x70, 0x08, 0x08, 0x7f, 0x80, 0x03, 0x78, 0x44, 0x38, 0xc7, 0x80, 0x07, 0x42, 0x44, 0x48, 0x50, 0x20, 0x30, 0x48, 0x3c, 0x80, 0x06, 0x44, 0x48, 0x48, 0x50, 0x50, 0x70, 0xbc, 0x80, 0x09, 0x5b, 0x40, 0x01, 0x41, 0x40, 0x01, 0x41, 0x40, 0x01, 0x6d, 0x80, 0x03, 0x66, 0x66, 0x66, 0x24, 0x80, 0x08, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x80, 0x0d, 0x18, 0x18, 0x3e, 0x63, 0x43, 0x03, 0x3e, 0x60, 0x60, 0x61, 0x63, 0x3e, 0x18, 0x18, 0x80, 0x07, 0x43, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x63, 0x61, 0x80, 0x09, 0x1c, 0x36, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x03, 0x0c, 0x0c, 0x0c, 0x04, 0x80, 0x09, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x80, 0x09, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x80, 0x04, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x80, 0x07, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x80, 0x09, 0x1c, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x63, 0x63, 0x36, 0x1c, 0x80, 0x09, 0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x80, 0x09, 0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x63, 0x7f, 0x80, 0x09, 0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x09, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x78, 0x80, 0x09, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x09, 0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e, 0x80, 0x08, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x80, 0x08, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x80, 0x06, 0x3e, 0x63, 0x63, 0x30, 0x18, 0x18, 0x18, 0x80, 0x08, 0x3e, 0x63, 0x63, 0x7b, 0x7b, 0x7b, 0x3b, 0x03, 0x3e, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x0b, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x7b, 0x3e, 0x30, 0x70, 0x80, 0x09, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x80, 0x08, 0x01, 0x03, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0x60, 0x40, 0x80, 0x09, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x80, 0x09, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0x78, 0x80, 0x09, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x80, 0x09, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x80, 0x06, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x80, 0x0a, 0x18, 0x18, 0x3c, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x18, 0x18, 0x80, 0x0a, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x67, 0x3f, 0x80, 0x06, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x80, 0x09, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x80, 0x0b, 0x3e, 0x63, 0x06, 0x1c, 0x36, 0x63, 0x63, 0x36, 0x1c, 0x30, 0x63, 0x3e, 0x80, 0x09, 0x3c, 0x42, 0x99, 0xa5, 0x85, 0x85, 0xa5, 0x99, 0x42, 0x3c, 0x80, 0x03, 0x3c, 0x36, 0x36, 0x7c, 0x80, 0x04, 0x6c, 0x36, 0x1b, 0x36, 0x6c, 0x80, 0x04, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x80, 0x06, 0x1c, 0x22, 0x5d, 0x4d, 0x55, 0x22, 0x1c, 0x80, 0x09, 0xfe, 0xdb, 0xdb, 0xdb, 0xde, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x80, 0x02, 0x18, 0x30, 0x1c, 0x80, 0x04, 0x1b, 0x36, 0x6c, 0x36, 0x1b, 0x80, 0x0c, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x66, 0x73, 0x79, 0x7c, 0x60, 0x60, 0x80, 0x0c, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x61, 0x30, 0x18, 0x7c, 0x80, 0x0c, 0x07, 0x0c, 0x46, 0x6c, 0x37, 0x18, 0x0c, 0x66, 0x73, 0x79, 0x7c, 0x60, 0x60, 0x80, 0x06, 0x0c, 0x0c, 0x06, 0x03, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x1c, 0x36, 0x1c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x0b, 0x18, 0x3c, 0x42, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x04, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x80, 0x09, 0x5e, 0x23, 0x73, 0x73, 0x6b, 0x6b, 0x67, 0x67, 0x62, 0x3d, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x0f, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x0f, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x36, 0x66, 0x66, 0x66, 0x66, 0x37, 0x80, 0x09, 0x6e, 0x38, 0x3c, 0x60, 0x7e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0c, 0x07, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x80, 0x0c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x30, 0x18, 0x70, 0x80, 0x09, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x30, 0x18, 0x70, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x0b, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x18, 0x0c, 0x38, 0x80, 0x09, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x3c, 0x66, 0x43, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x80, 0x01, 0x08, 0x1c, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x07, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x09, 0x66, 0xff, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x0b, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x18, 0x0c, 0x38, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x18, 0x0c, 0x38, 0x80, 0x09, 0xef, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 0x77, 0x80, 0x09, 0x77, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6f, 0x60, 0x66, 0x3c, 0x80, 0x0b, 0x10, 0x38, 0x44, 0x78, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x02, 0x20, 0x70, 0xd8, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x0f, 0x06, 0x06, 0x06, 0x66, 0x66, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x09, 0x0e, 0x0c, 0x0c, 0x0c, 0x6c, 0x6c, 0x0c, 0x0c, 0x0c, 0x1e, 0x80, 0x09, 0x0f, 0x06, 0x06, 0x06, 0x1e, 0x07, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x18, 0x78, 0x1e, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x80, 0x02, 0x06, 0x06, 0x03, 0x80, 0x0c, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x38, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x38, 0x80, 0x09, 0x76, 0x1b, 0x1b, 0x1b, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x76, 0x80, 0x06, 0x36, 0x6b, 0x6b, 0x7b, 0x1b, 0x1b, 0x76, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x63, 0x3e, 0x18, 0x30, 0x1c, 0x80, 0x09, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3e, 0x18, 0x30, 0x1c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x63, 0x3e, 0x80, 0x0c, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x18, 0x30, 0x1c, 0x80, 0x0c, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x18, 0x30, 0x1c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x08, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x09, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x3f, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x01, 0x33, 0x1e, 0x80, 0x0b, 0x1c, 0x36, 0x1c, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x09, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x0c, 0x06, 0x1c, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x77, 0x36, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x7f, 0x63, 0x31, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x80, 0x09, 0x1c, 0x36, 0x26, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x06, 0x1f, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x80, 0x09, 0x7e, 0xcd, 0xcd, 0xcc, 0x7c, 0xcc, 0xcc, 0xcc, 0xcc, 0x7e, 0x80, 0x09, 0x3f, 0x26, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x09, 0x7e, 0x46, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x80, 0x09, 0x3e, 0x67, 0x67, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x09, 0x06, 0x07, 0x07, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x80, 0x0a, 0xc0, 0x7c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x80, 0x07, 0xc0, 0x7e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x09, 0x3e, 0x6d, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x6c, 0x3e, 0x80, 0x09, 0x7e, 0x32, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x7e, 0x80, 0x09, 0x3e, 0x32, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x0c, 0x18, 0x33, 0x1e, 0x80, 0x09, 0x7f, 0x33, 0x31, 0x34, 0x3c, 0x34, 0x30, 0x31, 0x33, 0x7f, 0x80, 0x0c, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x80, 0x0c, 0x38, 0x6c, 0x4c, 0x0c, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x07, 0x80, 0x0a, 0xc0, 0x7c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x80, 0x0b, 0x63, 0x63, 0x63, 0x36, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x1c, 0x36, 0x1c, 0x80, 0x09, 0x03, 0x03, 0x03, 0xcf, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x73, 0x80, 0x09, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x09, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x67, 0xb6, 0x36, 0x1e, 0x0e, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x09, 0x1c, 0x36, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x13, 0x1c, 0x0e, 0x0b, 0x1c, 0x1c, 0x36, 0x26, 0x63, 0x43, 0x80, 0x09, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x37, 0x80, 0x0c, 0x66, 0x66, 0x6e, 0x7e, 0x7e, 0x76, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x03, 0x80, 0x0c, 0xce, 0xfb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xce, 0xc0, 0xc0, 0xc0, 0x80, 0x09, 0xce, 0xfb, 0xdb, 0xdb, 0xdb, 0xdb, 0xce, 0xc0, 0xc0, 0xc0, 0x80, 0x09, 0x7e, 0xcd, 0xcd, 0xcc, 0x7c, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x80, 0x0c, 0x1c, 0x36, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x80, 0x0a, 0x0f, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x1e, 0x36, 0x36, 0x67, 0x60, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x30, 0x1c, 0x06, 0x03, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x3e, 0x63, 0x30, 0x1c, 0x06, 0x63, 0x3e, 0x80, 0x0c, 0x0e, 0x1b, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x80, 0x0c, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x30, 0x36, 0x1c, 0x80, 0x09, 0x7e, 0x7f, 0x59, 0x1a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x38, 0x6c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x0c, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x70, 0x80, 0x09, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x33, 0x1e, 0x80, 0x09, 0xc6, 0xcd, 0xcd, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x30, 0x78, 0x80, 0x0b, 0x60, 0xb0, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x18, 0x0f, 0x80, 0x09, 0x7f, 0x63, 0x61, 0x30, 0x7e, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x80, 0x06, 0x7f, 0x33, 0x18, 0x3f, 0x06, 0x63, 0x7f, 0x80, 0x0b, 0x7f, 0x60, 0x30, 0x18, 0x0c, 0x3e, 0x60, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x0b, 0x7f, 0x03, 0x06, 0x0c, 0x18, 0x3e, 0x03, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x09, 0x7f, 0x03, 0x06, 0x0c, 0x1e, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x09, 0x7f, 0x60, 0x30, 0x18, 0x3c, 0x60, 0x3e, 0x03, 0x63, 0x3e, 0x80, 0x09, 0x3e, 0x63, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x63, 0x7f, 0x80, 0x09, 0x7f, 0x06, 0x06, 0x1e, 0x30, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x80, 0x06, 0x7f, 0x06, 0x1e, 0x30, 0x60, 0x66, 0x3c, 0x80, 0x09, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x18, 0x32, 0x36, 0x1c, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x36, 0x1e, 0x0e, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0b, 0xd8, 0x70, 0x20, 0xef, 0x9b, 0x9b, 0x5b, 0x5b, 0x5b, 0x3b, 0x3b, 0xef, 0x80, 0x09, 0xaf, 0x5b, 0x1b, 0xfb, 0x9b, 0x5b, 0x5b, 0x5b, 0x3b, 0xef, 0x80, 0x09, 0xbc, 0x58, 0x18, 0xfe, 0x9b, 0x5b, 0x5b, 0x5b, 0x3b, 0xf6, 0x80, 0x09, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xd3, 0x6f, 0x80, 0x0c, 0xcf, 0xc6, 0x06, 0xe6, 0xc6, 0xc6, 0xc6, 0xe6, 0xf6, 0xff, 0xc0, 0xd8, 0x70, 0x80, 0x0c, 0xc7, 0xc6, 0x06, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcf, 0xc0, 0xcc, 0x78, 0x80, 0x09, 0xdb, 0xdb, 0xdf, 0xdf, 0xdf, 0xdb, 0xdb, 0xdb, 0xdb, 0x7b, 0x80, 0x0c, 0xdb, 0xdb, 0x1f, 0xff, 0xdf, 0xdf, 0xdb, 0xdb, 0xdb, 0xdb, 0xc0, 0xcc, 0x78, 0x80, 0x09, 0xed, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xc0, 0xcc, 0x78, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x02, 0x10, 0x08, 0x36, 0x80, 0x02, 0x14, 0x08, 0x36, 0x80, 0x01, 0x1e, 0x0c, 0x80, 0x02, 0x04, 0x08, 0x36, 0x80, 0x09, 0x36, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x0b, 0x3e, 0x0c, 0x0c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x09, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0xfb, 0x66, 0x5c, 0x80, 0x09, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x7c, 0x33, 0x1e, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x3c, 0x66, 0x43, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x07, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x80, 0x0c, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x0b, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x0d, 0x36, 0x1c, 0x08, 0x7f, 0x30, 0x18, 0x0c, 0x3e, 0x60, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x02, 0xd8, 0x70, 0x20, 0x80, 0x09, 0xef, 0x9b, 0x9b, 0x5b, 0x5b, 0x5b, 0x5b, 0x3b, 0x3b, 0xef, 0x80, 0x09, 0x0f, 0x1b, 0x1b, 0xfb, 0x9b, 0x5b, 0x5b, 0x5b, 0x3b, 0xef, 0x80, 0x09, 0x1b, 0x1b, 0x1b, 0xdb, 0xdf, 0xdb, 0xdb, 0xdb, 0xdb, 0x73, 0x80, 0x0c, 0x3f, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1e, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x07, 0x80, 0x0b, 0x30, 0x18, 0x1c, 0x36, 0x1c, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x0b, 0x30, 0x18, 0x1c, 0x36, 0x1c, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x08, 0x5e, 0x23, 0x73, 0x73, 0x6b, 0x67, 0x67, 0x62, 0x3d, 0x80, 0x01, 0x1e, 0x33, 0x80, 0x0b, 0x3e, 0x63, 0x61, 0x60, 0x38, 0x2e, 0x60, 0x60, 0x60, 0x60, 0x38, 0x0f, 0x80, 0x08, 0x3e, 0x63, 0x60, 0x70, 0x3c, 0x60, 0x60, 0x38, 0x0f, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x80, 0x0b, 0x36, 0x1c, 0x08, 0x07, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x09, 0x36, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x24, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x0b, 0x7f, 0x63, 0x61, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x3f, 0x60, 0x30, 0x80, 0x08, 0x7f, 0x33, 0x18, 0x0c, 0x06, 0x03, 0x3f, 0x60, 0x30, 0x80, 0x0c, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f, 0x18, 0x30, 0x1c, 0x80, 0x06, 0x3b, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x80, 0x06, 0x2e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x06, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x80, 0x09, 0x1c, 0x36, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x80, 0x06, 0x3e, 0x63, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x07, 0x3e, 0x63, 0x03, 0x03, 0x3b, 0x67, 0x3e, 0x01, 0x80, 0x0c, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0xb0, 0x60, 0x80, 0x09, 0x60, 0xb0, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x06, 0x3e, 0x63, 0x7f, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x06, 0xdc, 0x36, 0x71, 0x68, 0x64, 0x36, 0x1c, 0x80, 0x06, 0x5e, 0xb3, 0xb0, 0x1c, 0x30, 0x33, 0x1e, 0x80, 0x06, 0x3e, 0x63, 0x63, 0x3b, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x70, 0x60, 0x60, 0xf8, 0x60, 0x60, 0x60, 0x66, 0x66, 0x3c, 0x80, 0x0b, 0x60, 0xb0, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x33, 0x1e, 0x80, 0x06, 0x3e, 0x63, 0x03, 0x73, 0x63, 0x63, 0x5e, 0x80, 0x06, 0x43, 0x26, 0x14, 0x1c, 0x1c, 0x36, 0x1c, 0x80, 0x09, 0x73, 0x33, 0x33, 0x33, 0x33, 0x3b, 0x36, 0x30, 0x30, 0x70, 0x80, 0x09, 0x1c, 0x36, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x0c, 0x1c, 0x36, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x60, 0x60, 0x38, 0x80, 0x06, 0x1c, 0x18, 0x18, 0x3c, 0x18, 0x18, 0x3c, 0x80, 0x06, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x18, 0xde, 0x7b, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x18, 0x1e, 0x1a, 0x7c, 0x18, 0x18, 0x3c, 0x80, 0x0c, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x80, 0x0c, 0x07, 0x06, 0x06, 0xfe, 0xc6, 0x66, 0x36, 0x7e, 0xc6, 0xcf, 0xc0, 0xcc, 0x78, 0x80, 0x06, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x76, 0x80, 0x09, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x76, 0x60, 0x60, 0x60, 0x80, 0x09, 0x37, 0x7f, 0x6b, 0x6b, 0x6b, 0x6b, 0x63, 0x60, 0x60, 0x38, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x03, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0xc0, 0x80, 0x06, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x80, 0x06, 0x76, 0x1b, 0x1b, 0x7b, 0x1b, 0x1b, 0x76, 0x80, 0x06, 0x78, 0x30, 0x30, 0x30, 0x33, 0x3b, 0x6e, 0x80, 0x09, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x3b, 0x6e, 0x80, 0x09, 0x78, 0x30, 0x30, 0x30, 0x33, 0x3b, 0x36, 0x30, 0xb0, 0x60, 0x80, 0x09, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x36, 0x1c, 0x80, 0x06, 0x3c, 0x66, 0x66, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x06, 0x1e, 0x33, 0x33, 0x30, 0x30, 0x30, 0x78, 0x80, 0x06, 0x3f, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x67, 0x80, 0x06, 0x67, 0x66, 0x36, 0x3e, 0x66, 0x66, 0x3f, 0x80, 0x09, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3f, 0x03, 0x1b, 0x0e, 0x80, 0x0c, 0x70, 0xd8, 0x98, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x1b, 0x0e, 0x80, 0x0c, 0x70, 0xd8, 0x98, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x19, 0x1b, 0x0e, 0x80, 0x07, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x80, 0x0a, 0x70, 0xd8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x1b, 0x0e, 0x80, 0x09, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x08, 0x80, 0x0c, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x06, 0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0xdc, 0x80, 0x06, 0x77, 0x36, 0x36, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x06, 0x36, 0x7f, 0x6b, 0x6b, 0x6b, 0x63, 0x63, 0x80, 0x09, 0x7c, 0x06, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x06, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x7f, 0x33, 0x18, 0x0c, 0x06, 0x63, 0x7f, 0x60, 0x60, 0xc0, 0x80, 0x07, 0x7f, 0x33, 0x18, 0x0c, 0x66, 0xd3, 0x7f, 0x08, 0x80, 0x09, 0x7f, 0x60, 0x30, 0x18, 0x3c, 0x60, 0x60, 0x7e, 0xe3, 0x3e, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x60, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x03, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x80, 0x09, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x38, 0x60, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x09, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x80, 0x06, 0x3e, 0x63, 0x63, 0x6e, 0x63, 0x63, 0x3e, 0x80, 0x07, 0xc0, 0x7e, 0x63, 0x03, 0x73, 0x63, 0x63, 0x5e, 0x80, 0x01, 0x30, 0x30, 0x80, 0x09, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x33, 0x1e, 0x80, 0x09, 0x73, 0x33, 0x36, 0x3c, 0x3c, 0x36, 0x33, 0x30, 0x30, 0x70, 0x80, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0x60, 0xb0, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0x78, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x60, 0x38, 0x18, 0x7e, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x03, 0x0e, 0x0c, 0x3f, 0x0c, 0x0c, 0x1e, 0x80, 0x0c, 0x1c, 0x18, 0x18, 0xfe, 0xdb, 0xdb, 0x7b, 0x7b, 0xdb, 0xd6, 0xc0, 0xd8, 0x70, 0x80, 0x0a, 0x1c, 0x18, 0x18, 0xfe, 0x9b, 0x5b, 0x5b, 0xdb, 0xbb, 0xf6, 0x20, 0x80, 0x09, 0x04, 0x06, 0x06, 0x6f, 0xb6, 0x36, 0x66, 0xc6, 0xd6, 0x6c, 0x80, 0x0c, 0x64, 0xb6, 0x36, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3c, 0x30, 0x34, 0x18, 0x80, 0x09, 0x04, 0x06, 0x06, 0x6f, 0xb6, 0x36, 0x36, 0x76, 0xb6, 0x6c, 0x80, 0x0c, 0x0e, 0x1b, 0x03, 0x7f, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xc0, 0xc0, 0x70, 0x80, 0x09, 0x07, 0x06, 0x06, 0x66, 0xb6, 0x36, 0x66, 0xc6, 0xd6, 0x6f, 0x80, 0x09, 0x07, 0x06, 0x06, 0xf6, 0xd6, 0xc6, 0x66, 0x36, 0xb6, 0xff, 0x80, 0x09, 0x63, 0x6b, 0x3e, 0x36, 0x14, 0x63, 0x6b, 0x3e, 0x36, 0x14, 0x80, 0x05, 0x03, 0x03, 0x0f, 0x1b, 0x1b, 0x1b, 0x80, 0x05, 0x0e, 0x03, 0x0f, 0x1b, 0x1b, 0x1b, 0x80, 0x04, 0x1c, 0x18, 0x18, 0x1b, 0x0e, 0x80, 0x03, 0x0d, 0x1b, 0x03, 0x03, 0x80, 0x03, 0x18, 0x18, 0x1b, 0x16, 0x80, 0x04, 0x18, 0x18, 0x1b, 0x16, 0x30, 0x80, 0x05, 0x1b, 0x1b, 0x0f, 0x1b, 0x1b, 0x0f, 0x80, 0x03, 0x63, 0x6b, 0x3e, 0x36, 0x80, 0x04, 0x1b, 0x1b, 0x1e, 0x18, 0x0e, 0x80, 0x02, 0x6c, 0x36, 0x1b, 0x80, 0x02, 0x0c, 0x06, 0x0c, 0x80, 0x04, 0x0e, 0x1b, 0x18, 0x0c, 0x0c, 0x80, 0x04, 0x0e, 0x1b, 0x03, 0x06, 0x06, 0x80, 0x04, 0x18, 0x0e, 0x03, 0x0e, 0x18, 0x80, 0x04, 0x03, 0x0e, 0x18, 0x0e, 0x03, 0x80, 0x05, 0x04, 0x04, 0x0e, 0x0e, 0x1b, 0x1b, 0x80, 0x05, 0x1b, 0x1b, 0x0e, 0x0e, 0x04, 0x04, 0x80, 0x01, 0x18, 0x30, 0x80, 0x01, 0x0c, 0x06, 0x80, 0x02, 0x18, 0x0c, 0x38, 0x80, 0x03, 0x36, 0x36, 0x36, 0x12, 0x80, 0x01, 0x2c, 0x1a, 0x80, 0x01, 0x03, 0x06, 0x80, 0x01, 0xc0, 0x60, 0x80, 0x02, 0x0c, 0x04, 0x02, 0x80, 0x02, 0x08, 0x04, 0x06, 0x80, 0x02, 0x0c, 0x2c, 0x18, 0x80, 0x01, 0x06, 0x03, 0x80, 0x0b, 0x06, 0x03, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x80, 0x0b, 0x06, 0x03, 0x7c, 0x4c, 0x0c, 0x2c, 0x3c, 0x2c, 0x0c, 0x0c, 0x4c, 0x7c, 0x80, 0x0b, 0x06, 0x03, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x80, 0x0b, 0x06, 0x03, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x06, 0x03, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x0b, 0x06, 0x03, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x06, 0x03, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x80, 0x09, 0x08, 0x08, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x63, 0x63, 0x63, 0x80, 0x05, 0x7f, 0x63, 0x41, 0x22, 0x3e, 0x22, 0x80, 0x02, 0x41, 0x63, 0x7f, 0x80, 0x09, 0x08, 0x49, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x80, 0x0c, 0x3c, 0x66, 0x66, 0x66, 0x36, 0x66, 0x66, 0x66, 0x66, 0x36, 0x06, 0x06, 0x06, 0x80, 0x09, 0x3c, 0x66, 0x0c, 0x18, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0c, 0x62, 0x3e, 0x18, 0x0c, 0x06, 0x06, 0x03, 0x03, 0x03, 0x3e, 0x60, 0x60, 0x38, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x03, 0x04, 0x0c, 0x08, 0x1c, 0x1c, 0x36, 0x26, 0x63, 0x43, 0x80, 0x06, 0x63, 0x63, 0x66, 0x36, 0x3c, 0x1c, 0x08, 0x80, 0x0c, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x06, 0x03, 0x03, 0x03, 0x3e, 0x60, 0x60, 0x38, 0x80, 0x06, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x66, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x80, 0x08, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x3e, 0x60, 0x60, 0x38, 0x80, 0x06, 0x7e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x06, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x70, 0x80, 0x09, 0x36, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x08, 0x80, 0x09, 0x61, 0x62, 0x34, 0x34, 0x18, 0x0c, 0x16, 0x16, 0x23, 0x43, 0x80, 0x09, 0x49, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x08, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x36, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x6c, 0x78, 0x63, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x43, 0xa6, 0x24, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x06, 0x03, 0x84, 0x4c, 0x48, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x80, 0x08, 0x43, 0xa6, 0x24, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x06, 0x7f, 0x36, 0x63, 0x6b, 0x6b, 0x6b, 0x36, 0x80, 0x08, 0x62, 0x65, 0x34, 0x1c, 0x16, 0x53, 0x23, 0x30, 0x18, 0x80, 0x0b, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x06, 0x3c, 0x60, 0x60, 0x38, 0x80, 0x09, 0x7e, 0x03, 0x03, 0x03, 0x03, 0x03, 0x3e, 0x60, 0x60, 0x38, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x06, 0x1e, 0x16, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x7e, 0x4c, 0x0c, 0x0c, 0x3c, 0x2c, 0x0c, 0x0c, 0x0c, 0x0c, 0x80, 0x0a, 0x06, 0x0c, 0x0c, 0x06, 0xc6, 0xff, 0x63, 0x60, 0x30, 0x30, 0x60, 0x80, 0x09, 0x0c, 0x0c, 0x06, 0x06, 0x7f, 0x7f, 0x30, 0x30, 0x18, 0x18, 0x80, 0x0c, 0x1e, 0x35, 0x64, 0x64, 0xd0, 0xd0, 0xd8, 0xd8, 0xd8, 0xd8, 0xc0, 0x40, 0x20, 0x80, 0x0a, 0x03, 0x06, 0x0c, 0x18, 0x14, 0x32, 0x28, 0x24, 0x60, 0x40, 0x40, 0x80, 0x0b, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xb6, 0xc0, 0x7c, 0x80, 0x08, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xb6, 0xc0, 0x7e, 0x80, 0x09, 0x6e, 0x6b, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x80, 0x09, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0x80, 0x0c, 0x03, 0x03, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x6e, 0x39, 0x80, 0x07, 0x10, 0x3e, 0x6b, 0x66, 0x60, 0x60, 0x66, 0x3d, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x60, 0x3c, 0x06, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x64, 0x38, 0x0e, 0x03, 0x43, 0x63, 0x3e, 0x80, 0x09, 0x63, 0x16, 0x1c, 0x0c, 0x1c, 0x1c, 0x32, 0x32, 0x61, 0x7f, 0x80, 0x06, 0x26, 0x5d, 0x0c, 0x1c, 0x14, 0x32, 0x3e, 0x80, 0x09, 0x7e, 0x03, 0x33, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x06, 0x7e, 0x03, 0x3b, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3c, 0x18, 0x7e, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x18, 0x38, 0x18, 0x7e, 0x1a, 0x18, 0x18, 0x18, 0x1c, 0x18, 0x80, 0x06, 0x62, 0x65, 0x34, 0x1c, 0x16, 0x53, 0x23, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3f, 0x03, 0x06, 0x3c, 0x60, 0x80, 0x0b, 0x7f, 0x4d, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc0, 0x60, 0x80, 0x08, 0x7f, 0x66, 0x46, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x3c, 0x66, 0x43, 0x03, 0x1f, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x80, 0x09, 0x1e, 0x1b, 0x1b, 0x1b, 0x7b, 0xdb, 0xdb, 0xdb, 0xdb, 0x7b, 0x80, 0x09, 0x1b, 0x1b, 0x1b, 0x1b, 0x7f, 0xdb, 0xdb, 0xdb, 0xdb, 0x7b, 0x80, 0x09, 0x7f, 0x4d, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x80, 0x0c, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x1c, 0x08, 0x08, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x0b, 0x3c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x7f, 0x63, 0x41, 0x80, 0x09, 0x6b, 0x6b, 0x6b, 0x3e, 0x1c, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x80, 0x09, 0x3e, 0x63, 0x61, 0x60, 0x3c, 0x60, 0x60, 0x61, 0x63, 0x3e, 0x80, 0x09, 0x63, 0x63, 0x63, 0x73, 0x7b, 0x7f, 0x6f, 0x67, 0x63, 0x63, 0x80, 0x0b, 0x36, 0x1c, 0x63, 0x63, 0x63, 0x73, 0x7b, 0x7f, 0x6f, 0x67, 0x63, 0x63, 0x80, 0x09, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x63, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x63, 0x3e, 0x80, 0x0b, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7f, 0x60, 0x40, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x80, 0x09, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x80, 0x0b, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0xff, 0xc0, 0x80, 0x80, 0x09, 0x1f, 0x0d, 0x0d, 0x0c, 0x3c, 0x6c, 0x6c, 0x6c, 0x6c, 0x3e, 0x80, 0x09, 0xc3, 0xc3, 0xc3, 0xc3, 0xcf, 0xdb, 0xdb, 0xdb, 0xdb, 0xcf, 0x80, 0x09, 0x0f, 0x06, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x09, 0x1e, 0x33, 0x61, 0x60, 0x7c, 0x60, 0x60, 0x61, 0x33, 0x1e, 0x80, 0x09, 0x39, 0x6d, 0x6d, 0x6d, 0x6f, 0x6d, 0x6d, 0x6d, 0x6d, 0x39, 0x80, 0x09, 0x7e, 0x33, 0x33, 0x33, 0x3e, 0x36, 0x36, 0x36, 0x36, 0x73, 0x80, 0x09, 0x60, 0x3e, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x08, 0x3c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x7f, 0x63, 0x41, 0x80, 0x06, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x63, 0x80, 0x06, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x80, 0x06, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x06, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0a, 0x08, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x08, 0x80, 0x08, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7f, 0x60, 0x40, 0x80, 0x06, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x80, 0x08, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0xff, 0xc0, 0x80, 0x80, 0x06, 0x1f, 0x0d, 0x0c, 0x3c, 0x6c, 0x6c, 0x3e, 0x80, 0x06, 0x0f, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3f, 0x80, 0x06, 0x39, 0x6d, 0x6d, 0x6f, 0x6d, 0x6d, 0x39, 0x80, 0x06, 0x7e, 0x33, 0x33, 0x3e, 0x36, 0x36, 0x73, 0x80, 0x0c, 0x06, 0x1f, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x60, 0x60, 0x38, 0x80, 0x06, 0x3e, 0x63, 0x03, 0x1f, 0x03, 0x63, 0x3e, 0x80, 0x06, 0x1e, 0x1b, 0x1b, 0x7b, 0xdb, 0xdb, 0x7b, 0x80, 0x06, 0x1b, 0x1b, 0x1b, 0x7f, 0xdb, 0xdb, 0x7b, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x1c, 0x08, 0x08, 0x80, 0x09, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x80, 0x09, 0x0c, 0x3f, 0x2d, 0x0c, 0x3c, 0x6c, 0x6c, 0x6c, 0x6c, 0x3e, 0x80, 0x09, 0x0c, 0x0c, 0x0c, 0x3f, 0x2d, 0x0c, 0x3c, 0x6c, 0x6c, 0x3e, 0x80, 0x09, 0x73, 0xdb, 0x9b, 0x1b, 0x7f, 0x1b, 0x1b, 0x9b, 0xdb, 0x73, 0x80, 0x06, 0x73, 0xdb, 0x1b, 0x7f, 0x1b, 0xdb, 0x73, 0x80, 0x09, 0x08, 0x1c, 0x1c, 0x36, 0x36, 0x36, 0x7f, 0x6b, 0x6b, 0x6b, 0x80, 0x06, 0x08, 0x1c, 0x1c, 0x36, 0x3e, 0x6b, 0x6b, 0x80, 0x09, 0x11, 0x31, 0x39, 0x69, 0x6f, 0x6d, 0xfd, 0xd5, 0xd7, 0xd7, 0x80, 0x06, 0x11, 0x31, 0x39, 0x6f, 0x7d, 0xd5, 0xd7, 0x80, 0x09, 0x7f, 0x63, 0x36, 0x36, 0x1c, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x80, 0x06, 0x7f, 0x63, 0x36, 0x3e, 0x6b, 0x6b, 0x6b, 0x80, 0x09, 0xff, 0xc5, 0x4d, 0x69, 0x3f, 0x39, 0x7d, 0x55, 0xd5, 0xd7, 0x80, 0x06, 0xfd, 0xc5, 0x69, 0x7f, 0xd5, 0xd5, 0xd7, 0x80, 0x0d, 0x36, 0x1c, 0x08, 0x3e, 0x63, 0x60, 0x60, 0x3e, 0x60, 0x60, 0x60, 0x3e, 0x03, 0x3e, 0x80, 0x08, 0x3e, 0x61, 0x60, 0x3e, 0x60, 0x60, 0x3e, 0x03, 0x3e, 0x80, 0x09, 0x08, 0x69, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x80, 0x0c, 0x08, 0x08, 0x08, 0x69, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x08, 0x08, 0x80, 0x09, 0x43, 0x63, 0x63, 0x23, 0x33, 0x36, 0x16, 0x1e, 0x1c, 0x0c, 0x80, 0x08, 0x43, 0x63, 0x23, 0x23, 0x36, 0x16, 0x1e, 0x1c, 0x0c, 0x80, 0x0c, 0x0e, 0x1b, 0x1b, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xf6, 0xc0, 0x60, 0x38, 0x80, 0x09, 0xce, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xf6, 0xc0, 0x60, 0x38, 0x80, 0x0b, 0x08, 0x3e, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x3e, 0x08, 0x80, 0x08, 0x08, 0x3e, 0x6b, 0x63, 0x63, 0x63, 0x6b, 0x3e, 0x08, 0x80, 0x0b, 0x20, 0x3e, 0x02, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x80, 0x08, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x80, 0x0c, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x3c, 0x30, 0x30, 0x30, 0x80, 0x08, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x03, 0x1e, 0x18, 0x18, 0x80, 0x09, 0x60, 0x60, 0x3c, 0xf0, 0x18, 0x18, 0x0f, 0x3c, 0x06, 0x06, 0x80, 0x02, 0x18, 0x24, 0x22, 0x80, 0x02, 0x02, 0x3e, 0x02, 0x80, 0x02, 0x20, 0x3e, 0x20, 0x80, 0x00, 0xc3, 0x80, 0x02, 0x10, 0x0a, 0x62, 0x80, 0x01, 0x41, 0x82, 0x80, 0x02, 0x46, 0x50, 0x08, 0x80, 0x0d, 0x36, 0x1c, 0x63, 0x63, 0x63, 0x73, 0x7b, 0x7f, 0x6f, 0x67, 0x63, 0xe3, 0xc0, 0x80, 0x80, 0x08, 0x63, 0x73, 0x7b, 0x7f, 0x6f, 0x67, 0xe3, 0xc0, 0x80, 0x80, 0x0a, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x07, 0x06, 0x0f, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3f, 0x80, 0x09, 0x3f, 0x66, 0x76, 0x26, 0x5e, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x76, 0x26, 0x5e, 0x06, 0x06, 0x0f, 0x80, 0x0b, 0x40, 0x60, 0x7f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x08, 0x40, 0x60, 0x7f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x06, 0x1f, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x06, 0x7f, 0x66, 0x46, 0x1f, 0x06, 0x06, 0x0f, 0x80, 0x0c, 0x7f, 0x66, 0x46, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x6f, 0x60, 0x68, 0x30, 0x80, 0x09, 0x7f, 0x66, 0x46, 0x1e, 0x36, 0x66, 0x6f, 0x60, 0x68, 0x30, 0x80, 0x0b, 0x6b, 0x6b, 0x6b, 0x3e, 0x1c, 0x3e, 0x6b, 0x6b, 0x6b, 0xeb, 0xc0, 0x80, 0x80, 0x08, 0x6b, 0x6b, 0x6b, 0x3e, 0x6b, 0x6b, 0xeb, 0xc0, 0x80, 0x80, 0x0c, 0x3e, 0x63, 0x61, 0x60, 0x3c, 0x60, 0x60, 0x61, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x09, 0x3e, 0x63, 0x60, 0x3c, 0x60, 0x63, 0x3e, 0x0c, 0x06, 0x1c, 0x80, 0x0b, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0xe7, 0xc0, 0x80, 0x80, 0x08, 0x67, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0xe7, 0xc0, 0x80, 0x80, 0x09, 0x63, 0x6b, 0x6b, 0x3b, 0x1f, 0x3b, 0x6b, 0x6b, 0x63, 0x63, 0x80, 0x06, 0x63, 0x6b, 0x3b, 0x1f, 0x3b, 0x6b, 0x63, 0x80, 0x09, 0x67, 0x66, 0x6f, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x09, 0x07, 0x06, 0x0f, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x80, 0x09, 0xcf, 0xcd, 0xcd, 0x6c, 0x3c, 0x3c, 0x6c, 0xcc, 0xcc, 0xce, 0x80, 0x06, 0xcf, 0x6d, 0x3d, 0x3c, 0x6c, 0xcc, 0xce, 0x80, 0x09, 0xfb, 0xdb, 0x9b, 0x1b, 0x1f, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x80, 0x06, 0xfb, 0xdb, 0x9b, 0x1f, 0x1b, 0x1b, 0x1b, 0x80, 0x0c, 0x1f, 0x1b, 0x1b, 0x1b, 0x7b, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xc0, 0xd0, 0x60, 0x80, 0x09, 0x1b, 0x1b, 0x1b, 0x7f, 0xdb, 0xdb, 0xdb, 0xc0, 0xd0, 0x60, 0x80, 0x09, 0x3e, 0x43, 0x33, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x33, 0x5e, 0x80, 0x06, 0x3e, 0x43, 0x33, 0x6b, 0x6b, 0x33, 0x5e, 0x80, 0x0b, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x30, 0x20, 0x80, 0x08, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x30, 0x20, 0x80, 0x09, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3c, 0x80, 0x0b, 0x63, 0x63, 0x36, 0x3e, 0x1c, 0x1c, 0x3e, 0x36, 0x63, 0xe3, 0xc0, 0x80, 0x80, 0x08, 0x63, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0xe3, 0xc0, 0x80, 0x80, 0x0b, 0x6f, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfe, 0xc0, 0x80, 0x80, 0x08, 0x6f, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfe, 0xc0, 0x80, 0x80, 0x0b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0xe0, 0xc0, 0x80, 0x80, 0x08, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0xe0, 0xc0, 0x80, 0x80, 0x09, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x7e, 0x68, 0x68, 0x60, 0x60, 0x80, 0x06, 0x63, 0x6b, 0x6b, 0x7e, 0x68, 0x68, 0x60, 0x80, 0x09, 0x03, 0x03, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x06, 0x03, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x80, 0x09, 0x78, 0xcc, 0xcd, 0xcd, 0xfe, 0x0c, 0x0c, 0x0c, 0xcc, 0x78, 0x80, 0x06, 0x79, 0xcd, 0xfe, 0x0c, 0x0c, 0xcc, 0x78, 0x80, 0x0c, 0x78, 0xcc, 0xcd, 0xcd, 0xfe, 0x0c, 0x0c, 0x0c, 0xcc, 0x78, 0x30, 0x18, 0x70, 0x80, 0x09, 0x79, 0xcd, 0xfe, 0x0c, 0x0c, 0xcc, 0x78, 0x30, 0x18, 0x70, 0x80, 0x0b, 0x36, 0x1c, 0x6b, 0x6b, 0x6b, 0x3e, 0x1c, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x80, 0x0c, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x60, 0x68, 0x30, 0x80, 0x09, 0x67, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x60, 0x68, 0x30, 0x80, 0x0b, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xe3, 0xc0, 0x80, 0x80, 0x08, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0xe3, 0xc0, 0x80, 0x80, 0x0c, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x68, 0x30, 0x80, 0x09, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x60, 0x68, 0x30, 0x80, 0x0b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x70, 0x30, 0x10, 0x80, 0x08, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x70, 0x30, 0x10, 0x80, 0x0b, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0xe3, 0xc0, 0x80, 0x80, 0x08, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0xe3, 0xc0, 0x80, 0x80, 0x08, 0x3e, 0x63, 0x60, 0x60, 0x7f, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x08, 0x6b, 0x6b, 0x6b, 0x3e, 0x1c, 0x3e, 0x6b, 0x6b, 0x6b, 0x80, 0x08, 0x3e, 0x63, 0x61, 0x60, 0x3c, 0x60, 0x61, 0x63, 0x3e, 0x80, 0x09, 0x7f, 0x60, 0x30, 0x18, 0x3c, 0x60, 0x60, 0x61, 0x63, 0x3e, 0x80, 0x08, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x08, 0x1e, 0x33, 0x61, 0x60, 0x7c, 0x60, 0x61, 0x33, 0x1e, 0x80, 0x08, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x80, 0x08, 0xc3, 0xc3, 0xc3, 0xcf, 0xdb, 0xdb, 0xdb, 0xdb, 0xcf, 0x80, 0x09, 0x78, 0x30, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x7e, 0x80, 0x09, 0x78, 0x30, 0x30, 0x30, 0x3e, 0xb3, 0xb3, 0xb3, 0xb3, 0x6e, 0x80, 0x09, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0xb3, 0xb3, 0xb3, 0x6e, 0x80, 0x09, 0x1e, 0x33, 0x31, 0x30, 0x1c, 0xb0, 0xb0, 0xb0, 0xb0, 0x60, 0x80, 0x06, 0x1e, 0x33, 0x30, 0x9c, 0xb0, 0xb0, 0x60, 0x80, 0x0b, 0x3e, 0x63, 0x61, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x60, 0xe0, 0xc0, 0x80, 0x80, 0x08, 0x3e, 0x63, 0x60, 0x3c, 0x60, 0x60, 0xe0, 0xc0, 0x80, 0x80, 0x09, 0x3c, 0x36, 0x36, 0x36, 0x36, 0xb6, 0xb6, 0xb6, 0xb6, 0x63, 0x80, 0x06, 0x3c, 0x36, 0x36, 0xb6, 0xb6, 0xb6, 0x63, 0x80, 0x09, 0x33, 0x33, 0x33, 0x33, 0x3f, 0xb3, 0xb3, 0xb3, 0xb3, 0x63, 0x80, 0x06, 0x33, 0x33, 0x33, 0xbf, 0xb3, 0xb3, 0x63, 0x80, 0x09, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x73, 0x63, 0x63, 0x66, 0x3c, 0x80, 0x06, 0x3e, 0x63, 0x03, 0x73, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x80, 0x06, 0x7e, 0x5a, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x80, 0x06, 0x18, 0x26, 0x29, 0x5d, 0x4a, 0x32, 0x0c, 0x80, 0x09, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xf3, 0xde, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x7e, 0x06, 0x06, 0x80, 0x09, 0x1e, 0x33, 0x33, 0x33, 0x33, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x80, 0x09, 0x1e, 0x33, 0x33, 0x33, 0x33, 0xf3, 0x30, 0x30, 0x30, 0x30, 0x80, 0x09, 0x06, 0x7e, 0x06, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x0a, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x30, 0x1b, 0x7f, 0xc3, 0x80, 0x0a, 0x06, 0x06, 0x7e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3e, 0x60, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x06, 0x7e, 0x80, 0x09, 0x3e, 0x63, 0xf3, 0x6b, 0x6b, 0x6b, 0x6b, 0x33, 0x03, 0x03, 0x80, 0x09, 0x30, 0x30, 0x30, 0x30, 0xfe, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x80, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3e, 0x60, 0x80, 0x09, 0x03, 0x03, 0x6f, 0x6b, 0x6b, 0x6b, 0x6b, 0x33, 0x03, 0x03, 0x80, 0x09, 0x03, 0xfe, 0x24, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x06, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x80, 0x0a, 0x18, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x0f, 0x3c, 0x70, 0x20, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x60, 0x60, 0x60, 0x36, 0x1b, 0x76, 0x80, 0x09, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, 0xf0, 0x80, 0x09, 0x78, 0x0c, 0x06, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x7e, 0x80, 0x09, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0x3c, 0x66, 0x60, 0x60, 0x3e, 0x60, 0x60, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x07, 0x06, 0x06, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x3c, 0x60, 0x7c, 0x66, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x60, 0x60, 0x60, 0x36, 0x1c, 0x70, 0x80, 0x09, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x60, 0x60, 0x80, 0x0a, 0x3c, 0x66, 0x66, 0x66, 0x6e, 0x78, 0x70, 0x30, 0x1b, 0x7f, 0xc3, 0x80, 0x09, 0x1e, 0x33, 0x33, 0x33, 0x33, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x80, 0x09, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x30, 0x30, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0xf0, 0x80, 0x09, 0x3e, 0x63, 0x63, 0x06, 0x0c, 0x18, 0x30, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x06, 0x06, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x80, 0x09, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x06, 0x06, 0x80, 0x09, 0x08, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x08, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x7f, 0x06, 0x06, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x0e, 0x0b, 0x0b, 0x0b, 0x3e, 0x68, 0x68, 0x68, 0x6b, 0x3e, 0x80, 0x03, 0x18, 0x0c, 0x0c, 0x18, 0x80, 0x03, 0x0c, 0x18, 0x18, 0x0c, 0x80, 0x02, 0x60, 0x3c, 0x06, 0x80, 0x02, 0x0c, 0x18, 0x30, 0x80, 0x02, 0x38, 0x6c, 0x36, 0x80, 0x02, 0x0e, 0x06, 0x7c, 0x80, 0x06, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x56, 0x80, 0x09, 0x3e, 0x66, 0x66, 0x66, 0x06, 0x06, 0x7e, 0x06, 0x06, 0x06, 0x80, 0x09, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x33, 0xfe, 0x30, 0x30, 0x30, 0x80, 0x09, 0x1f, 0x33, 0x33, 0x33, 0x33, 0x33, 0xf3, 0x30, 0x30, 0x30, 0x80, 0x09, 0x06, 0x06, 0x7e, 0x06, 0x06, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x80, 0x09, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0xf0, 0x80, 0x0b, 0x06, 0x06, 0x06, 0x3e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1e, 0x30, 0x18, 0x80, 0x09, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x7e, 0x80, 0x09, 0x3f, 0x63, 0x63, 0xf3, 0x6b, 0x6b, 0x33, 0x03, 0x03, 0x03, 0x80, 0x09, 0x30, 0x30, 0x30, 0xfe, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x80, 0x0c, 0x06, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x06, 0x80, 0x09, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x80, 0x0c, 0x03, 0x03, 0x03, 0x6f, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x53, 0x03, 0x03, 0x03, 0x80, 0x09, 0x06, 0x1c, 0x30, 0xfe, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0c, 0x06, 0x06, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x80, 0x09, 0x06, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x09, 0x0c, 0x38, 0x30, 0x18, 0x3c, 0x26, 0x66, 0x46, 0xc6, 0xbc, 0x80, 0x09, 0x1f, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0xf0, 0x80, 0x09, 0x70, 0x18, 0x0c, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x80, 0x09, 0xf0, 0x30, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x80, 0x09, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x80, 0x09, 0x07, 0x06, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x7c, 0x80, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x09, 0x30, 0x18, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x7c, 0x80, 0x09, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x7e, 0x60, 0x60, 0x60, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x6e, 0x38, 0x18, 0x0c, 0x06, 0x7c, 0x80, 0x06, 0x1f, 0x33, 0x33, 0x33, 0x33, 0x33, 0xf3, 0x80, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x80, 0x0c, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0xf0, 0x80, 0x06, 0x3b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6e, 0x80, 0x09, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x06, 0x06, 0x06, 0x80, 0x09, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x66, 0x3c, 0x80, 0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x80, 0x0c, 0x08, 0x08, 0x08, 0x3b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6e, 0x08, 0x08, 0x08, 0x80, 0x09, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x7f, 0x06, 0x06, 0x80, 0x06, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x0c, 0x0e, 0x0b, 0x0b, 0x3e, 0x68, 0x68, 0x68, 0x68, 0x6b, 0x3e, 0x08, 0x08, 0x08, 0x80, 0x09, 0x03, 0x03, 0x03, 0x03, 0x03, 0x33, 0x33, 0x33, 0x33, 0xee, 0x80, 0x02, 0x03, 0x63, 0x3e, 0x80, 0x03, 0x08, 0x08, 0x1c, 0x36, 0x80, 0x04, 0x10, 0x1c, 0x08, 0x1c, 0x04, 0x80, 0x02, 0x36, 0x06, 0x36, 0x80, 0x02, 0x08, 0x18, 0x30, 0x80, 0x02, 0x08, 0x1c, 0x08, 0x80, 0x02, 0x2e, 0x6b, 0x3a, 0x80, 0x02, 0x03, 0x06, 0x04, 0x80, 0x02, 0xc0, 0x60, 0xc0, 0x80, 0x02, 0x14, 0x18, 0x0c, 0x80, 0x02, 0x30, 0x18, 0x08, 0x80, 0x02, 0xc0, 0x60, 0x20, 0x80, 0x02, 0xd8, 0x6c, 0x24, 0x80, 0x03, 0x22, 0x55, 0x36, 0x14, 0x80, 0x03, 0x20, 0x50, 0x30, 0x10, 0x80, 0x03, 0x02, 0x0a, 0x07, 0x01, 0x80, 0x02, 0x08, 0x0c, 0x06, 0x80, 0x02, 0x24, 0x36, 0x1b, 0x80, 0x03, 0x18, 0x0c, 0x10, 0x0c, 0x80, 0x02, 0x06, 0x0c, 0x08, 0x80, 0x03, 0x02, 0x05, 0x06, 0x04, 0x80, 0x03, 0x36, 0x1c, 0x08, 0x08, 0x80, 0x02, 0x20, 0x60, 0xc0, 0x80, 0x02, 0x12, 0x15, 0x09, 0x80, 0x00, 0xdb, 0x80, 0x00, 0xcc, 0x80, 0x00, 0x6f, 0x80, 0x00, 0x60, 0x80, 0x02, 0x6f, 0x06, 0x66, 0x80, 0x02, 0x7e, 0x18, 0x18, 0x80, 0x02, 0x03, 0x18, 0xc0, 0x80, 0x01, 0x7e, 0x3f, 0x80, 0x07, 0x63, 0x63, 0x66, 0x6e, 0x3b, 0x33, 0x63, 0x63, 0x80, 0x07, 0x1f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7f, 0x80, 0x07, 0x1c, 0x30, 0x30, 0x30, 0x30, 0x38, 0x6c, 0x67, 0x80, 0x07, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x80, 0x07, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x63, 0x63, 0x63, 0x80, 0x07, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x07, 0x7e, 0x18, 0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0x80, 0x07, 0x3f, 0x66, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x07, 0x33, 0x6b, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x04, 0x0e, 0x18, 0x18, 0x18, 0x0c, 0x80, 0x0a, 0x3f, 0x60, 0x60, 0x60, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x70, 0x80, 0x07, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x3f, 0x80, 0x09, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x30, 0x18, 0x18, 0x80, 0x07, 0x3f, 0x66, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x80, 0x07, 0x3b, 0x6e, 0x66, 0x63, 0x63, 0x63, 0x63, 0x7b, 0x80, 0x0a, 0x1c, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0x80, 0x07, 0x1c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3e, 0x80, 0x07, 0x3f, 0x66, 0x63, 0x63, 0x63, 0x63, 0x33, 0x1e, 0x80, 0x07, 0x77, 0x66, 0x66, 0x66, 0x66, 0x66, 0x34, 0x1f, 0x80, 0x0a, 0x1f, 0x32, 0x33, 0x33, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x70, 0x80, 0x07, 0x3f, 0x62, 0x63, 0x63, 0x67, 0x60, 0x60, 0x7f, 0x80, 0x0a, 0x77, 0x66, 0x66, 0x36, 0x1e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0e, 0x80, 0x07, 0x77, 0x66, 0x66, 0x2c, 0x18, 0x30, 0x60, 0x7f, 0x80, 0x0a, 0x3f, 0x60, 0x60, 0x66, 0x26, 0x36, 0x76, 0x06, 0x06, 0x06, 0x06, 0x80, 0x07, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x80, 0x07, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6f, 0x63, 0x3e, 0x80, 0x07, 0x3f, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x80, 0x07, 0x33, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x07, 0x33, 0x66, 0x66, 0x66, 0x63, 0x60, 0x60, 0x60, 0x80, 0x04, 0x33, 0x66, 0x66, 0x66, 0x33, 0x80, 0x03, 0x10, 0x08, 0x18, 0x18, 0x80, 0x02, 0x30, 0x18, 0x18, 0x80, 0x05, 0x38, 0x44, 0x04, 0x08, 0x10, 0x10, 0x80, 0x0a, 0x0c, 0x02, 0x1c, 0x02, 0xe0, 0x10, 0x11, 0x61, 0x81, 0x41, 0x3e, 0x80, 0x02, 0x80, 0x7e, 0x01, 0x80, 0x02, 0x0c, 0x1e, 0x0c, 0x80, 0x08, 0x08, 0x04, 0x02, 0x0c, 0x08, 0x04, 0x42, 0x3e, 0x1c, 0x80, 0x08, 0x08, 0x1c, 0x34, 0x22, 0x42, 0x41, 0x41, 0x7f, 0x3e, 0x80, 0x08, 0x01, 0x1f, 0x1e, 0x10, 0x10, 0x10, 0x30, 0x70, 0x60, 0x80, 0x09, 0x06, 0x89, 0x49, 0x26, 0x10, 0x08, 0x64, 0x92, 0x91, 0x60, 0x80, 0x05, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x80, 0x04, 0x08, 0x1c, 0x18, 0x08, 0x04, 0x80, 0x03, 0xe0, 0x10, 0xe0, 0x10, 0x80, 0x08, 0xc0, 0x20, 0xc0, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x80, 0x07, 0x28, 0x02, 0x81, 0x81, 0x7e, 0x10, 0x28, 0x10, 0x80, 0x0c, 0x60, 0x10, 0x60, 0x10, 0x0e, 0xf1, 0x0c, 0x02, 0x01, 0x01, 0x01, 0x82, 0x7c, 0x80, 0x07, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x10, 0x28, 0x10, 0x80, 0x06, 0x20, 0x40, 0x40, 0x20, 0x38, 0x56, 0x20, 0x80, 0x05, 0x20, 0x40, 0x40, 0x20, 0x18, 0x46, 0x80, 0x05, 0x20, 0x40, 0x48, 0x20, 0x18, 0x46, 0x80, 0x05, 0x80, 0xa8, 0x11, 0x11, 0x51, 0x0e, 0x80, 0x06, 0x60, 0x90, 0x8c, 0x79, 0x11, 0x09, 0xa6, 0x80, 0x06, 0x54, 0x04, 0x04, 0x34, 0x4c, 0x45, 0x3e, 0x80, 0x06, 0x18, 0x04, 0x02, 0x7c, 0x80, 0x81, 0x7e, 0x80, 0x07, 0x80, 0x40, 0xa0, 0xd0, 0x12, 0x21, 0x41, 0x3e, 0x80, 0x08, 0x20, 0x90, 0x48, 0xa0, 0xd0, 0x12, 0x21, 0x41, 0x3e, 0x80, 0x08, 0x22, 0x90, 0x45, 0x20, 0x10, 0x22, 0x41, 0x41, 0x3e, 0x80, 0x0a, 0x28, 0x10, 0x40, 0x40, 0x40, 0x40, 0x42, 0x41, 0x41, 0x21, 0x1e, 0x80, 0x0a, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x41, 0x41, 0x21, 0x1e, 0x80, 0x0a, 0x08, 0x40, 0x54, 0x40, 0x40, 0x40, 0x42, 0x41, 0x41, 0x21, 0x1e, 0x80, 0x08, 0x82, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x10, 0x28, 0x10, 0x80, 0x06, 0x08, 0x1c, 0x32, 0x4a, 0x4c, 0x3c, 0x02, 0x80, 0x03, 0x1c, 0x02, 0x1c, 0x02, 0x80, 0x06, 0x30, 0x48, 0x70, 0x48, 0x34, 0x18, 0x06, 0x80, 0x07, 0x04, 0xe2, 0x11, 0x10, 0x61, 0x81, 0x81, 0x7e, 0x80, 0x08, 0x0a, 0x04, 0xe0, 0x10, 0x11, 0x61, 0x81, 0x81, 0x7e, 0x80, 0x08, 0x06, 0x01, 0x06, 0x01, 0x10, 0x28, 0x06, 0x01, 0x7f, 0x80, 0x06, 0x02, 0x02, 0xc2, 0xaa, 0x7e, 0x01, 0x3e, 0x80, 0x06, 0x54, 0x04, 0x64, 0x54, 0x3e, 0x01, 0x3e, 0x80, 0x03, 0x30, 0x70, 0x38, 0x06, 0x80, 0x04, 0x28, 0x28, 0x10, 0x28, 0x18, 0x80, 0x05, 0x18, 0x34, 0x08, 0x14, 0x44, 0x38, 0x80, 0x0d, 0x5a, 0xa5, 0x66, 0xda, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x5a, 0x66, 0xa5, 0x5a, 0x80, 0x0b, 0x18, 0x66, 0x42, 0x42, 0x81, 0x99, 0x99, 0x81, 0x42, 0x42, 0x66, 0x18, 0x80, 0x02, 0x10, 0x38, 0x10, 0x80, 0x03, 0x18, 0x64, 0x10, 0x0e, 0x80, 0x01, 0x4c, 0x34, 0x80, 0x05, 0x10, 0x28, 0x30, 0x20, 0x10, 0x0c, 0x80, 0x03, 0x10, 0x44, 0x44, 0x38, 0x80, 0x0d, 0x08, 0x14, 0x2a, 0x55, 0x49, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x41, 0x7f, 0x80, 0x03, 0x1c, 0x22, 0x22, 0x1c, 0x80, 0x08, 0x72, 0x0f, 0x7f, 0x3e, 0x0c, 0x0c, 0x08, 0x08, 0x08, 0x80, 0x08, 0x0c, 0x1c, 0x34, 0x22, 0x42, 0x41, 0x49, 0x7f, 0x36, 0x80, 0x08, 0x18, 0x3c, 0x06, 0x7e, 0x3c, 0x0c, 0x06, 0x02, 0x01, 0x80, 0x05, 0x80, 0xa8, 0x11, 0x11, 0x11, 0x4e, 0x80, 0x06, 0x60, 0x90, 0x8c, 0x79, 0x11, 0x11, 0x4e, 0x80, 0x09, 0x0e, 0x01, 0x31, 0x0e, 0x02, 0x01, 0x11, 0x01, 0x82, 0x7c, 0x80, 0x03, 0x28, 0x28, 0x28, 0x28, 0x80, 0x09, 0x30, 0x48, 0x48, 0x3c, 0x02, 0x2a, 0x2a, 0x2a, 0x2a, 0x02, 0x80, 0x09, 0x36, 0x49, 0x49, 0x49, 0x49, 0x49, 0x32, 0x0c, 0x32, 0x40, 0x80, 0x06, 0x36, 0x49, 0x49, 0x49, 0x49, 0x49, 0x26, 0x80, 0x09, 0x2a, 0x55, 0x55, 0x55, 0x41, 0x41, 0x02, 0x0c, 0x32, 0x40, 0x80, 0x06, 0x36, 0x49, 0x49, 0x49, 0x41, 0x41, 0x22, 0x80, 0x09, 0x36, 0x49, 0x49, 0x49, 0x41, 0x41, 0x02, 0x0c, 0x32, 0x40, 0x80, 0x08, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x3f, 0x80, 0x0a, 0x30, 0x37, 0x06, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x80, 0x0b, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x18, 0x30, 0x1c, 0x80, 0x08, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x80, 0x0b, 0x06, 0x06, 0x30, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x0c, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x0c, 0x18, 0x0e, 0x80, 0x0c, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x0c, 0x18, 0x0e, 0x80, 0x0c, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x08, 0x1c, 0x36, 0x80, 0x0c, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x08, 0x1c, 0x36, 0x80, 0x0c, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f, 0x08, 0x1c, 0x36, 0x80, 0x09, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x08, 0x1c, 0x36, 0x80, 0x0b, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x18, 0x30, 0x1c, 0x80, 0x08, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x0f, 0x80, 0x08, 0x1c, 0x36, 0x26, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x0b, 0x30, 0x30, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x08, 0x07, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x80, 0x0c, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x06, 0x0c, 0x07, 0x80, 0x0c, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x0c, 0x18, 0x0e, 0x80, 0x02, 0x30, 0x18, 0x66, 0x80, 0x07, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x03, 0x30, 0x18, 0x66, 0x66, 0x80, 0x0a, 0x30, 0x37, 0x06, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x80, 0x0c, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x08, 0x1c, 0x36, 0x80, 0x0c, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x08, 0x1c, 0x36, 0x80, 0x0c, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63, 0x08, 0x1c, 0x36, 0x80, 0x09, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x08, 0x1c, 0x36, 0x80, 0x0b, 0x30, 0x18, 0x4e, 0x39, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x02, 0x06, 0x0c, 0x3e, 0x80, 0x02, 0x30, 0x18, 0x3e, 0x80, 0x02, 0x06, 0x36, 0x18, 0x80, 0x07, 0x3e, 0x63, 0x63, 0x0e, 0x38, 0x63, 0x63, 0x3e, 0x80, 0x03, 0x06, 0x06, 0x30, 0x18, 0x80, 0x0b, 0x0c, 0x22, 0x1c, 0x08, 0x3e, 0x63, 0x63, 0x0e, 0x38, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x0c, 0x0c, 0x22, 0x1c, 0x08, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3e, 0x80, 0x08, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0a, 0x60, 0x68, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x0c, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x08, 0x1c, 0x36, 0x80, 0x0c, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x10, 0x38, 0x6c, 0x80, 0x0c, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x08, 0x1c, 0x36, 0x80, 0x09, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x08, 0x1c, 0x36, 0x80, 0x03, 0x30, 0x18, 0x4e, 0x39, 0x80, 0x06, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x08, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x08, 0x80, 0x0b, 0x08, 0x1c, 0x22, 0x7f, 0x63, 0x31, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x80, 0x08, 0x08, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x80, 0x08, 0x1c, 0x36, 0x26, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x80, 0x0b, 0x1c, 0x30, 0x18, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x80, 0x0b, 0xc0, 0x68, 0x1c, 0x36, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x03, 0xc0, 0x68, 0x1c, 0x36, 0x80, 0x0b, 0x03, 0x16, 0x38, 0x6c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x03, 0x03, 0x16, 0x38, 0x6c, 0x80, 0x0b, 0x70, 0xc8, 0x5c, 0x36, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x0b, 0x6e, 0x3b, 0x08, 0x14, 0x2a, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x0b, 0x6e, 0x3b, 0x08, 0x1c, 0x22, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x0b, 0x30, 0x18, 0x22, 0x1c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x03, 0x30, 0x18, 0x22, 0x1c, 0x80, 0x0b, 0x06, 0x0c, 0x22, 0x1c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x03, 0x06, 0x0c, 0x22, 0x1c, 0x80, 0x0b, 0x0c, 0x10, 0x2a, 0x1c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x03, 0x0c, 0x10, 0x2a, 0x1c, 0x80, 0x0b, 0x4e, 0x39, 0x22, 0x1c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x03, 0x4e, 0x39, 0x22, 0x1c, 0x80, 0x0b, 0x1c, 0x30, 0x18, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0xc4, 0x6e, 0x11, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0x23, 0x76, 0x88, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x66, 0x7f, 0x80, 0x0b, 0x6e, 0x3b, 0x08, 0x1c, 0x22, 0x7f, 0x46, 0x16, 0x1e, 0x16, 0x46, 0x7f, 0x80, 0x0b, 0x6e, 0x3b, 0x08, 0x1c, 0x22, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x80, 0x0b, 0x1c, 0x30, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x0b, 0x1c, 0x30, 0x18, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0xc4, 0x6e, 0x11, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x23, 0x76, 0x88, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x70, 0xc8, 0x5c, 0x22, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x6e, 0x3b, 0x08, 0x14, 0x22, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x6e, 0x3b, 0x08, 0x1c, 0x22, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x18, 0xcc, 0xc0, 0x5e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0xd8, 0xcc, 0x60, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0b, 0x06, 0xcc, 0xc0, 0x5e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0xc6, 0xcc, 0x60, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0b, 0x0e, 0xd8, 0xcc, 0x5e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0a, 0x0e, 0xd8, 0xcc, 0x60, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0b, 0x16, 0xcd, 0xc0, 0x5e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0a, 0x16, 0xcd, 0xc0, 0x60, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0b, 0x1c, 0x30, 0x18, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x80, 0x0b, 0x18, 0xcc, 0xc0, 0x73, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0xd8, 0xcc, 0x60, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x0b, 0x06, 0xcc, 0xc0, 0x73, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0xc6, 0xcc, 0x60, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x0b, 0x0e, 0xd8, 0xcc, 0x73, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0a, 0x0e, 0xd8, 0xcc, 0x60, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x0b, 0x16, 0xcd, 0xc0, 0x73, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0a, 0x16, 0xcd, 0xc0, 0x60, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x80, 0x09, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x30, 0x18, 0x6f, 0x60, 0x80, 0x0b, 0x1c, 0x30, 0x18, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x01, 0x5c, 0x3a, 0x80, 0x02, 0x06, 0x36, 0x63, 0x80, 0x02, 0x03, 0x33, 0x66, 0x80, 0x02, 0x06, 0x66, 0x33, 0x80, 0x02, 0x03, 0x63, 0x36, 0x80, 0x03, 0x2c, 0x1a, 0x30, 0x18, 0x80, 0x03, 0x2c, 0x1a, 0x0c, 0x18, 0x80, 0x04, 0x25, 0x55, 0x57, 0x57, 0x65, 0x80, 0x04, 0x25, 0x57, 0x55, 0x55, 0x65, 0x80, 0x04, 0x57, 0x51, 0x73, 0x71, 0x57, 0x80, 0x04, 0x57, 0x71, 0x53, 0x51, 0x57, 0x80, 0x04, 0x53, 0x74, 0x52, 0x54, 0x53, 0x80, 0x04, 0x55, 0x75, 0x57, 0x54, 0x54, 0x80, 0x04, 0x56, 0x71, 0x53, 0x55, 0x52, 0x80, 0x04, 0x1c, 0x04, 0x0c, 0x04, 0x04, 0x80, 0x04, 0x0c, 0x14, 0x0c, 0x04, 0x04, 0x80, 0x04, 0x57, 0x52, 0x72, 0x52, 0x52, 0x80, 0x04, 0x14, 0x14, 0x1c, 0x14, 0x14, 0x80, 0x04, 0x45, 0x45, 0x47, 0x57, 0x25, 0x80, 0x04, 0x10, 0x10, 0x10, 0x14, 0x08, 0x80, 0x0a, 0x01, 0x01, 0x01, 0x0f, 0x14, 0x0c, 0x14, 0x50, 0x70, 0x70, 0x50, 0x80, 0x0a, 0x03, 0x05, 0x03, 0x05, 0x04, 0x04, 0x1c, 0x50, 0x70, 0x70, 0x50, 0x80, 0x04, 0x39, 0x4b, 0x3d, 0x49, 0x39, 0x80, 0x03, 0x18, 0x0c, 0x0c, 0x0c, 0x80, 0x03, 0x0c, 0x0c, 0x0c, 0x18, 0x80, 0x03, 0x66, 0x33, 0x33, 0x33, 0x80, 0x03, 0x33, 0x33, 0x33, 0x66, 0x80, 0x09, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x06, 0x04, 0x0c, 0x1c, 0x3c, 0x1c, 0x0c, 0x04, 0x80, 0x08, 0x03, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x6c, 0x6c, 0x80, 0x08, 0x03, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xd6, 0xd6, 0x80, 0x02, 0x18, 0x18, 0x08, 0x80, 0x02, 0x36, 0x36, 0x12, 0x80, 0x02, 0xdb, 0xdb, 0x49, 0x80, 0x02, 0x18, 0x18, 0x10, 0x80, 0x02, 0x36, 0x36, 0x24, 0x80, 0x02, 0xdb, 0xdb, 0x92, 0x80, 0x06, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x80, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x80, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x80, 0x06, 0x7e, 0xc3, 0xdb, 0xd8, 0x78, 0x38, 0x18, 0x80, 0x01, 0x41, 0x3e, 0x80, 0x01, 0x3e, 0x41, 0x80, 0x04, 0x60, 0x30, 0x18, 0x1c, 0x36, 0x80, 0x02, 0x08, 0x1c, 0x14, 0x80, 0x02, 0x22, 0x77, 0x55, 0x80, 0x01, 0x3c, 0x3c, 0x80, 0x09, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x80, 0x09, 0x3c, 0x0c, 0x0c, 0x0c, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x80, 0x09, 0x3c, 0x30, 0x30, 0x30, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x80, 0x06, 0xde, 0xf3, 0xf3, 0xd8, 0xcc, 0xcc, 0xcc, 0x80, 0x01, 0xcc, 0xcc, 0x80, 0x06, 0x7b, 0xcf, 0xcf, 0x63, 0x33, 0x33, 0x33, 0x80, 0x05, 0x7e, 0x7e, 0x60, 0x60, 0x30, 0x30, 0x80, 0x09, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x80, 0x06, 0x7c, 0x4e, 0x4f, 0x4f, 0x4f, 0x4e, 0x7c, 0x80, 0x06, 0x1f, 0x39, 0x79, 0x79, 0x79, 0x39, 0x1f, 0x80, 0x09, 0x1e, 0x33, 0x03, 0xf3, 0x33, 0x33, 0xfe, 0x30, 0x30, 0xf0, 0x80, 0x0d, 0x20, 0x20, 0x3e, 0x73, 0x13, 0x13, 0x0b, 0x0b, 0x0b, 0x07, 0x67, 0x3e, 0x02, 0x02, 0x80, 0x09, 0x3e, 0x63, 0x03, 0x03, 0x6b, 0x1b, 0x1b, 0x1b, 0x7b, 0x3e, 0x80, 0x09, 0x1f, 0x03, 0x03, 0x03, 0x0f, 0xb3, 0x73, 0x33, 0x33, 0x33, 0x80, 0x09, 0x1c, 0x36, 0x06, 0x1f, 0x06, 0x1f, 0x06, 0x06, 0x67, 0x3f, 0x80, 0x08, 0x40, 0x37, 0x6b, 0x7b, 0x6b, 0x6b, 0x6f, 0x6b, 0x02, 0x80, 0x09, 0x66, 0x66, 0x6e, 0xff, 0x6e, 0x76, 0xff, 0x76, 0x66, 0x66, 0x80, 0x09, 0x3f, 0x66, 0x66, 0x3e, 0x46, 0x66, 0xf6, 0x66, 0x66, 0xcf, 0x80, 0x09, 0x1f, 0x33, 0x33, 0x33, 0x1f, 0x07, 0xcf, 0x6b, 0xdb, 0x73, 0x80, 0x09, 0x81, 0x81, 0x81, 0x5a, 0xff, 0x5a, 0xff, 0x24, 0x24, 0x24, 0x80, 0x07, 0x4f, 0x51, 0x55, 0x55, 0x55, 0x55, 0x45, 0x3d, 0x80, 0x09, 0x38, 0x6c, 0x06, 0x3f, 0x06, 0x1f, 0x06, 0x06, 0x6c, 0x38, 0x80, 0x09, 0x67, 0x66, 0x36, 0x1e, 0x7f, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x80, 0x09, 0x7e, 0x7e, 0x5a, 0x18, 0x78, 0x1e, 0x78, 0x1e, 0x18, 0x3c, 0x80, 0x0a, 0x08, 0x3e, 0x6d, 0x6c, 0xcc, 0xcc, 0xcc, 0xc6, 0x66, 0x6f, 0x3b, 0x80, 0x0b, 0x0e, 0x0b, 0x4b, 0x6b, 0x3e, 0x18, 0x0c, 0x76, 0x1b, 0x19, 0x18, 0x70, 0x80, 0x0b, 0x0e, 0x0b, 0x4b, 0x6b, 0x3e, 0x18, 0x0c, 0x76, 0x1b, 0x31, 0x60, 0x38, 0x80, 0x09, 0x3c, 0x46, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x46, 0x3c, 0x80, 0x09, 0x72, 0x9d, 0x1a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x98, 0x70, 0x80, 0x09, 0x3c, 0x18, 0x3e, 0x5b, 0x1b, 0x1b, 0x5b, 0x3e, 0x98, 0xfc, 0x80, 0x0b, 0x0e, 0x03, 0x43, 0x63, 0x3e, 0x18, 0x0c, 0x76, 0xdb, 0xd9, 0xd8, 0x70, 0x80, 0x0b, 0x0e, 0x03, 0x43, 0x63, 0x3e, 0x18, 0x0c, 0xde, 0xdb, 0xd9, 0xd8, 0xb0, 0x80, 0x09, 0x1e, 0x33, 0x61, 0x64, 0x7c, 0x64, 0x60, 0x61, 0x33, 0x1e, 0x80, 0x09, 0xfe, 0x9d, 0x1a, 0x58, 0x78, 0x58, 0x18, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x58, 0x66, 0x62, 0xe1, 0x31, 0x31, 0x3e, 0x19, 0x19, 0x0e, 0x80, 0x09, 0x4a, 0xad, 0xa8, 0x68, 0x34, 0x2c, 0x16, 0x95, 0x55, 0x32, 0x80, 0x0c, 0x12, 0x0d, 0x01, 0x12, 0x3e, 0x66, 0x64, 0x64, 0x65, 0x62, 0x60, 0x2c, 0x12, 0x80, 0x09, 0x47, 0x45, 0x45, 0x45, 0x7d, 0x45, 0x45, 0x45, 0x45, 0x47, 0x80, 0x09, 0x1c, 0x18, 0x18, 0x6c, 0xdc, 0xdc, 0xcc, 0x66, 0x66, 0x67, 0x80, 0x09, 0x1c, 0x78, 0x18, 0x6e, 0xdc, 0xdc, 0xcc, 0x66, 0x66, 0x67, 0x80, 0x09, 0xcc, 0x72, 0x60, 0x60, 0x30, 0x30, 0xf8, 0x36, 0x11, 0x0e, 0x80, 0x09, 0x8e, 0x71, 0x20, 0x30, 0x60, 0xc0, 0xc6, 0xc3, 0x42, 0x3c, 0x80, 0x09, 0x62, 0x92, 0x9c, 0x78, 0x18, 0x0c, 0x0e, 0x8d, 0x5d, 0x36, 0x80, 0x09, 0x70, 0x98, 0x8c, 0x4c, 0x26, 0x16, 0x0e, 0x87, 0x66, 0x1c, 0x80, 0x09, 0x1b, 0xff, 0x1b, 0x7b, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x7b, 0x80, 0x09, 0x47, 0x45, 0x4d, 0x4d, 0x55, 0x55, 0x65, 0x65, 0x45, 0x47, 0x80, 0x09, 0x33, 0xf3, 0xb7, 0xff, 0x3f, 0xfb, 0x33, 0x33, 0x33, 0x33, 0x80, 0x09, 0x3c, 0x42, 0x9d, 0xa5, 0xa5, 0x9d, 0x85, 0x85, 0x42, 0x3c, 0x80, 0x0a, 0x02, 0x71, 0xc9, 0xc5, 0xc6, 0xd2, 0x56, 0x25, 0x0d, 0x0d, 0x06, 0x80, 0x09, 0x3f, 0x45, 0x45, 0x45, 0x45, 0x3d, 0x05, 0x05, 0x05, 0x07, 0x80, 0x0a, 0x3e, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x55, 0x65, 0x7e, 0x80, 0x80, 0x09, 0x7c, 0xb2, 0xb2, 0x98, 0x78, 0x38, 0x2c, 0x2c, 0xad, 0x46, 0x80, 0x09, 0x1a, 0x65, 0xc5, 0x36, 0x1d, 0x64, 0x64, 0x64, 0xe5, 0x43, 0x80, 0x09, 0x3f, 0x45, 0x45, 0x45, 0x45, 0x3d, 0x0d, 0x15, 0x25, 0x47, 0x80, 0x0a, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0xb6, 0xe6, 0x66, 0x77, 0x10, 0x80, 0x0c, 0x0c, 0x30, 0x3f, 0x63, 0x63, 0x63, 0x3f, 0x1b, 0x3b, 0x3b, 0x67, 0x67, 0x04, 0x80, 0x03, 0x8e, 0xdb, 0xac, 0x8b, 0x80, 0x04, 0x7f, 0x4a, 0x5a, 0x4a, 0xfa, 0x80, 0x03, 0x8f, 0xda, 0xaa, 0x8a, 0x80, 0x0c, 0x06, 0x18, 0x73, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x67, 0x36, 0x1c, 0x0a, 0x02, 0x80, 0x09, 0x7f, 0x50, 0x28, 0x28, 0x14, 0x14, 0x0a, 0x0a, 0x05, 0x7f, 0x80, 0x0c, 0x7f, 0x39, 0x0c, 0x7f, 0x30, 0x18, 0x1c, 0x30, 0x60, 0x60, 0x63, 0x63, 0x3e, 0x80, 0x09, 0x18, 0x64, 0xc0, 0xc8, 0x30, 0xc8, 0xc0, 0xc0, 0x66, 0x19, 0x80, 0x06, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x38, 0x18, 0x80, 0x0b, 0x1c, 0x36, 0x1c, 0x08, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x7f, 0x63, 0x63, 0x80, 0x09, 0x78, 0xb4, 0xb4, 0x58, 0x78, 0xd8, 0x8c, 0x8c, 0x4d, 0x36, 0x80, 0x09, 0x28, 0xd6, 0x13, 0x33, 0x63, 0x63, 0x33, 0x03, 0xc6, 0x38, 0x80, 0x06, 0x3c, 0x66, 0xe7, 0xff, 0x07, 0xe6, 0x7c, 0x80, 0x06, 0x38, 0x64, 0x22, 0x1f, 0x03, 0x13, 0x0e, 0x80, 0x09, 0x32, 0x4a, 0x3c, 0x08, 0x3c, 0x06, 0x03, 0xc3, 0x33, 0x1e, 0x80, 0x09, 0xce, 0x73, 0x18, 0x5c, 0x3a, 0x18, 0x0c, 0x0c, 0x0d, 0x06, 0x80, 0x09, 0x78, 0x30, 0x30, 0x30, 0x34, 0x3c, 0x34, 0x31, 0x33, 0x7f, 0x80, 0x09, 0x48, 0x48, 0x48, 0x68, 0x6c, 0x7c, 0x5c, 0x5a, 0x4a, 0x89, 0x80, 0x06, 0x38, 0x64, 0x62, 0x63, 0x23, 0x13, 0x0e, 0x80, 0x09, 0x42, 0x63, 0xe7, 0x5e, 0x1c, 0x3a, 0x73, 0xe7, 0xc6, 0x47, 0x80, 0x09, 0x01, 0x3f, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x30, 0x7e, 0x7f, 0x80, 0x09, 0x02, 0x1e, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x78, 0x7e, 0x4f, 0x80, 0x09, 0x01, 0x7f, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x18, 0x80, 0x01, 0x1c, 0x1c, 0x80, 0x06, 0x1e, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x3e, 0x80, 0x06, 0xbe, 0xff, 0xc1, 0x61, 0x41, 0x7f, 0x3e, 0x80, 0x0c, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x61, 0x38, 0x60, 0x38, 0x80, 0x0c, 0x07, 0x0c, 0x46, 0x63, 0x3f, 0x18, 0x0c, 0x06, 0x3b, 0x61, 0x38, 0x60, 0x38, 0x80, 0x0c, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x7b, 0x19, 0x38, 0x60, 0x38, 0x80, 0x0c, 0x07, 0x0c, 0x46, 0x63, 0x3f, 0x18, 0x0c, 0x06, 0x7b, 0x19, 0x38, 0x60, 0x38, 0x80, 0x0c, 0x07, 0x0c, 0x46, 0x6c, 0x37, 0x18, 0x0c, 0x06, 0x7b, 0x19, 0x38, 0x60, 0x38, 0x80, 0x0c, 0x0c, 0x0e, 0x4d, 0x6f, 0x3c, 0x18, 0x0c, 0x06, 0x7b, 0x19, 0x38, 0x60, 0x38, 0x80, 0x0c, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x0d, 0x3c, 0x6c, 0x38, 0x80, 0x0c, 0x0f, 0x03, 0x47, 0x6c, 0x37, 0x18, 0x0c, 0x06, 0x3b, 0x0d, 0x3c, 0x6c, 0x38, 0x80, 0x0c, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x6d, 0x38, 0x6c, 0x38, 0x80, 0x0c, 0x07, 0x0c, 0x46, 0x6c, 0x37, 0x18, 0x0c, 0x06, 0x3b, 0x6d, 0x38, 0x6c, 0x38, 0x80, 0x0c, 0x0f, 0x01, 0x47, 0x6c, 0x37, 0x18, 0x0c, 0x06, 0x3b, 0x6d, 0x38, 0x6c, 0x38, 0x80, 0x0c, 0x0f, 0x0c, 0x46, 0x66, 0x36, 0x18, 0x0c, 0x06, 0x3b, 0x6d, 0x38, 0x6c, 0x38, 0x80, 0x09, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x80, 0x09, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x7f, 0x80, 0x09, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xff, 0x80, 0x09, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x73, 0x73, 0x23, 0x80, 0x09, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xce, 0xce, 0xc4, 0x80, 0x09, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa6, 0xa6, 0xa6, 0x80, 0x09, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x09, 0xdb, 0xdb, 0xdb, 0x73, 0x73, 0x73, 0xdb, 0xdb, 0xdb, 0xdb, 0x80, 0x09, 0xdb, 0xdb, 0xdb, 0xce, 0xce, 0xce, 0xdb, 0xdb, 0xdb, 0xdb, 0x80, 0x09, 0xa9, 0xa9, 0xa9, 0xa6, 0xa6, 0xa6, 0xa9, 0xa9, 0xa9, 0xa9, 0x80, 0x06, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x80, 0x06, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x80, 0x06, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x73, 0x23, 0x80, 0x06, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xce, 0xc4, 0x80, 0x06, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa6, 0xa6, 0x80, 0x01, 0xa8, 0xa8, 0x80, 0x06, 0xad, 0xad, 0xad, 0xad, 0xaa, 0xaa, 0xaa, 0x80, 0x06, 0xdb, 0xdb, 0x73, 0x73, 0x73, 0xdb, 0xdb, 0x80, 0x06, 0xdb, 0xdb, 0xce, 0xce, 0xce, 0xdb, 0xdb, 0x80, 0x06, 0xa9, 0xa9, 0xa6, 0xa6, 0xa9, 0xa9, 0xa9, 0x80, 0x09, 0x3c, 0x5a, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x5a, 0x3c, 0x80, 0x09, 0x1f, 0x33, 0x67, 0x6b, 0x6b, 0x6b, 0x6b, 0x67, 0x33, 0x1f, 0x80, 0x09, 0x3c, 0x5a, 0x99, 0xbd, 0xdb, 0xdb, 0xbd, 0x99, 0x5a, 0x3c, 0x80, 0x04, 0x0c, 0x06, 0xff, 0x06, 0x0c, 0x80, 0x09, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x04, 0x30, 0x60, 0xff, 0x60, 0x30, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x80, 0x04, 0x24, 0x66, 0xff, 0x66, 0x24, 0x80, 0x08, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x80, 0x06, 0xf0, 0xe0, 0xb0, 0x18, 0x0c, 0x06, 0x03, 0x80, 0x06, 0x03, 0x06, 0x0c, 0x18, 0xb0, 0xe0, 0xf0, 0x80, 0x06, 0xc0, 0x60, 0x30, 0x18, 0x0d, 0x07, 0x0f, 0x80, 0x04, 0x4c, 0x46, 0xff, 0x26, 0x2c, 0x80, 0x04, 0x34, 0x64, 0xff, 0x62, 0x32, 0x80, 0x02, 0x07, 0x73, 0xdd, 0x80, 0x02, 0xe0, 0xce, 0xbb, 0x80, 0x04, 0x6c, 0x36, 0xff, 0x36, 0x6c, 0x80, 0x09, 0x18, 0x3c, 0x7e, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x80, 0x04, 0x36, 0x6c, 0xff, 0x6c, 0x36, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x3c, 0x18, 0x80, 0x04, 0xcc, 0x66, 0x3f, 0x66, 0xcc, 0x80, 0x04, 0x33, 0x66, 0xfc, 0x66, 0x33, 0x80, 0x04, 0xcc, 0xc6, 0xff, 0xc6, 0xcc, 0x80, 0x09, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x80, 0x04, 0x33, 0x63, 0xff, 0x63, 0x33, 0x80, 0x09, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x80, 0x09, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x80, 0x05, 0x60, 0xcc, 0xc6, 0x7f, 0x06, 0x0c, 0x80, 0x05, 0x06, 0x33, 0x63, 0xfe, 0x60, 0x30, 0x80, 0x05, 0x60, 0xdc, 0xd6, 0x7f, 0x16, 0x0c, 0x80, 0x05, 0x06, 0x3b, 0x6b, 0xfe, 0x68, 0x30, 0x80, 0x04, 0x24, 0x5a, 0xff, 0x66, 0x24, 0x80, 0x04, 0x34, 0x76, 0xff, 0x6e, 0x2c, 0x80, 0x09, 0x0c, 0x0c, 0x06, 0xc6, 0xff, 0x63, 0x68, 0x38, 0x38, 0x78, 0x80, 0x08, 0x0c, 0x06, 0x7f, 0x66, 0x6c, 0x60, 0x60, 0x60, 0x60, 0x80, 0x08, 0x18, 0x30, 0x7f, 0x33, 0x1b, 0x03, 0x03, 0x03, 0x03, 0x80, 0x08, 0x60, 0x60, 0x60, 0x60, 0x6c, 0x66, 0x7f, 0x06, 0x0c, 0x80, 0x08, 0x03, 0x03, 0x03, 0x03, 0x1b, 0x33, 0x7f, 0x30, 0x18, 0x80, 0x05, 0x3f, 0x30, 0x30, 0xfc, 0x78, 0x30, 0x80, 0x05, 0x60, 0x6c, 0x66, 0x7f, 0x06, 0x0c, 0x80, 0x07, 0x78, 0xcc, 0xcc, 0xcc, 0x0c, 0x3f, 0x1e, 0x0c, 0x80, 0x07, 0x1e, 0x33, 0x33, 0x33, 0x30, 0xfc, 0x78, 0x30, 0x80, 0x09, 0x19, 0x0d, 0xff, 0x0d, 0x19, 0x98, 0xb0, 0xff, 0xb0, 0x98, 0x80, 0x08, 0x78, 0x38, 0x68, 0xc0, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x80, 0x08, 0x1e, 0x1c, 0x16, 0x03, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x80, 0x09, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x09, 0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x1c, 0x18, 0x80, 0x09, 0x30, 0x60, 0xff, 0x60, 0x30, 0x0c, 0x06, 0xff, 0x06, 0x0c, 0x80, 0x09, 0x24, 0x74, 0xfc, 0x24, 0x24, 0x24, 0x24, 0x3f, 0x2e, 0x24, 0x80, 0x09, 0x0c, 0x06, 0xff, 0x06, 0x0c, 0x30, 0x60, 0xff, 0x60, 0x30, 0x80, 0x09, 0x24, 0x7e, 0xff, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x80, 0x09, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xff, 0x7e, 0x24, 0x80, 0x04, 0x44, 0xfe, 0x23, 0xfe, 0x24, 0x80, 0x04, 0x34, 0x7e, 0xd3, 0x7e, 0x2c, 0x80, 0x04, 0x24, 0x7f, 0xc4, 0x7f, 0x22, 0x80, 0x04, 0x04, 0xfe, 0x03, 0xfe, 0x04, 0x80, 0x09, 0x1c, 0x3e, 0x77, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x80, 0x04, 0x20, 0x7f, 0xc0, 0x7f, 0x20, 0x80, 0x09, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x77, 0x3e, 0x1c, 0x80, 0x04, 0x24, 0x7e, 0xc3, 0x7e, 0x24, 0x80, 0x09, 0x1c, 0x3e, 0x77, 0x36, 0x36, 0x36, 0x36, 0x77, 0x3e, 0x1c, 0x80, 0x08, 0x0f, 0x07, 0x0d, 0x1b, 0x37, 0x6d, 0xd8, 0x30, 0x20, 0x80, 0x08, 0xf0, 0xe0, 0xb0, 0xd8, 0xec, 0xb6, 0x1b, 0x0c, 0x04, 0x80, 0x08, 0x04, 0x0c, 0x1b, 0xb6, 0xec, 0xd8, 0xb0, 0xe0, 0xf0, 0x80, 0x08, 0x20, 0x30, 0xd8, 0x6d, 0x37, 0x1b, 0x0d, 0x07, 0x0f, 0x80, 0x06, 0x08, 0xfc, 0x06, 0xff, 0x06, 0xfc, 0x08, 0x80, 0x06, 0x10, 0x3f, 0x60, 0xff, 0x60, 0x3f, 0x10, 0x80, 0x04, 0x0c, 0x56, 0xff, 0xa6, 0x0c, 0x80, 0x04, 0x30, 0x65, 0xff, 0x6a, 0x30, 0x80, 0x09, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x3c, 0x18, 0x3c, 0x18, 0x18, 0x80, 0x09, 0x18, 0x18, 0x3c, 0x18, 0x3c, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x80, 0x04, 0x0c, 0x06, 0xab, 0x06, 0x0c, 0x80, 0x03, 0x18, 0x3c, 0x66, 0x18, 0x80, 0x04, 0x30, 0x60, 0xd5, 0x60, 0x30, 0x80, 0x03, 0x18, 0x66, 0x3c, 0x18, 0x80, 0x04, 0x19, 0x0d, 0xff, 0x0d, 0x19, 0x80, 0x04, 0x98, 0xb0, 0xff, 0xb0, 0x98, 0x80, 0x06, 0x08, 0xfc, 0x82, 0x81, 0x82, 0xfc, 0x08, 0x80, 0x09, 0x08, 0x14, 0x22, 0x63, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3e, 0x80, 0x06, 0x10, 0x3f, 0x41, 0x81, 0x41, 0x3f, 0x10, 0x80, 0x09, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x63, 0x22, 0x14, 0x08, 0x80, 0x06, 0x08, 0x14, 0x22, 0x63, 0x22, 0x22, 0x3e, 0x80, 0x02, 0x3e, 0x22, 0x3e, 0x80, 0x09, 0x08, 0x14, 0x22, 0x63, 0x22, 0x22, 0x22, 0x63, 0x41, 0x7f, 0x80, 0x09, 0x08, 0x14, 0x3e, 0x63, 0x22, 0x22, 0x22, 0x63, 0x41, 0x7f, 0x80, 0x09, 0x08, 0x1c, 0x2a, 0x6b, 0x2a, 0x2a, 0x2a, 0x6b, 0x49, 0x7f, 0x80, 0x0a, 0x08, 0x14, 0x2a, 0x77, 0x22, 0x63, 0x22, 0x22, 0x22, 0x22, 0x3e, 0x80, 0x0a, 0x08, 0x14, 0x2a, 0x77, 0x22, 0x63, 0x22, 0x22, 0x63, 0x41, 0x7f, 0x80, 0x06, 0x17, 0x3d, 0x41, 0x81, 0x41, 0x3d, 0x17, 0x80, 0x08, 0xff, 0x01, 0x3d, 0x1d, 0x35, 0x61, 0xc1, 0x81, 0x01, 0x80, 0x08, 0x80, 0x81, 0x83, 0x86, 0xac, 0xb8, 0xbc, 0x80, 0xff, 0x80, 0x0a, 0x08, 0x14, 0x22, 0x63, 0x22, 0x22, 0x22, 0x63, 0x22, 0x14, 0x08, 0x80, 0x09, 0x63, 0x63, 0x7f, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x08, 0x80, 0x08, 0x3c, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x80, 0x09, 0x1c, 0x36, 0x60, 0x60, 0x7c, 0x66, 0x63, 0x63, 0x33, 0x1e, 0x80, 0x09, 0x7f, 0x60, 0x60, 0x60, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x7f, 0x80, 0x0b, 0x10, 0x7f, 0x68, 0x68, 0x68, 0x7e, 0x68, 0x64, 0x64, 0x64, 0x7f, 0x02, 0x80, 0x09, 0xc0, 0x7c, 0x66, 0xf3, 0xdb, 0xdb, 0xcf, 0x66, 0x3e, 0x03, 0x80, 0x09, 0x7f, 0x63, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x08, 0x80, 0x08, 0x7c, 0x06, 0x03, 0x03, 0x7f, 0x03, 0x03, 0x06, 0x7c, 0x80, 0x0a, 0x20, 0x7c, 0x26, 0x13, 0x13, 0x7f, 0x13, 0x0b, 0x0e, 0x7c, 0x04, 0x80, 0x06, 0x7c, 0x06, 0x03, 0x7f, 0x03, 0x06, 0x7c, 0x80, 0x08, 0x1f, 0x30, 0x60, 0x60, 0x7f, 0x60, 0x60, 0x30, 0x1f, 0x80, 0x0a, 0x10, 0x1f, 0x38, 0x68, 0x64, 0x7f, 0x64, 0x64, 0x32, 0x1f, 0x02, 0x80, 0x06, 0x1f, 0x30, 0x60, 0x7f, 0x60, 0x30, 0x1f, 0x80, 0x06, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x0b, 0xff, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xe7, 0x80, 0x0b, 0xe7, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xff, 0x80, 0x0b, 0xff, 0x83, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x83, 0xff, 0x80, 0x0b, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03, 0x80, 0x0b, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60, 0x80, 0x04, 0x24, 0x18, 0x7e, 0x18, 0x24, 0x80, 0x09, 0xc0, 0xc0, 0x60, 0x60, 0x60, 0x30, 0x33, 0x36, 0x1c, 0x18, 0x80, 0x09, 0xc7, 0xcc, 0x66, 0x6c, 0x67, 0x30, 0x33, 0x36, 0x1c, 0x18, 0x80, 0x09, 0xcc, 0xce, 0x6d, 0x6f, 0x6c, 0x30, 0x33, 0x36, 0x1c, 0x18, 0x80, 0x03, 0x6e, 0x1b, 0x1b, 0x76, 0x80, 0x03, 0x6e, 0xdb, 0xdb, 0x76, 0x80, 0x05, 0x03, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x80, 0x06, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x80, 0x07, 0x40, 0x68, 0x30, 0x38, 0x2c, 0x46, 0xff, 0x40, 0x80, 0x06, 0x08, 0x70, 0x1c, 0x17, 0x1c, 0x70, 0x08, 0x80, 0x09, 0x18, 0x18, 0x18, 0x58, 0x38, 0x1c, 0x1a, 0x18, 0x18, 0x18, 0x80, 0x09, 0x36, 0x36, 0x36, 0x76, 0x3e, 0x37, 0x36, 0x36, 0x36, 0x36, 0x80, 0x07, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x0d, 0x30, 0x58, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1a, 0x0c, 0x80, 0x0d, 0xcc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x33, 0x80, 0x0d, 0x54, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x15, 0x80, 0x0d, 0x30, 0x58, 0x18, 0x18, 0x3c, 0x5a, 0x99, 0x99, 0x5a, 0x3c, 0x18, 0x18, 0x1a, 0x0c, 0x80, 0x0d, 0xcc, 0x66, 0x66, 0x66, 0x7e, 0xe7, 0xe7, 0xe7, 0xe7, 0x7e, 0x66, 0x66, 0x66, 0x33, 0x80, 0x0d, 0x54, 0x2a, 0x2a, 0x2a, 0x3e, 0x6b, 0x6b, 0x6b, 0x6b, 0x3e, 0x2a, 0x2a, 0x2a, 0x15, 0x80, 0x0d, 0x18, 0x2c, 0x0c, 0x0c, 0x1c, 0xac, 0xcc, 0xec, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x06, 0x80, 0x0d, 0x30, 0x58, 0x18, 0x18, 0x3c, 0x5a, 0x5f, 0x5a, 0x5a, 0x3c, 0x18, 0x18, 0x1a, 0x0c, 0x80, 0x0d, 0x30, 0x58, 0x18, 0x18, 0x3c, 0x5a, 0xfa, 0x5a, 0x5a, 0x3c, 0x18, 0x18, 0x1a, 0x0c, 0x80, 0x03, 0x4e, 0xdb, 0xdb, 0x72, 0x80, 0x05, 0x0e, 0x1b, 0xdb, 0xdb, 0xd8, 0x70, 0x80, 0x08, 0x38, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x1c, 0x80, 0x07, 0x10, 0x10, 0x08, 0x6e, 0x3b, 0x08, 0x04, 0x04, 0x80, 0x07, 0x10, 0x10, 0x6e, 0x3b, 0x08, 0x7f, 0x04, 0x04, 0x80, 0x06, 0x6e, 0x3b, 0x10, 0x7f, 0x08, 0x7f, 0x04, 0x80, 0x09, 0x10, 0x10, 0x6e, 0x3b, 0x08, 0x7f, 0x04, 0x7f, 0x02, 0x02, 0x80, 0x08, 0x10, 0x10, 0x6e, 0x3b, 0x08, 0x6e, 0x3b, 0x04, 0x04, 0x80, 0x01, 0x63, 0x3e, 0x80, 0x01, 0x3e, 0x63, 0x80, 0x01, 0x03, 0xfb, 0x80, 0x01, 0xfb, 0x03, 0x80, 0x01, 0xc0, 0xdf, 0x80, 0x01, 0xdf, 0xc0, 0x80, 0x02, 0x7f, 0x14, 0x7f, 0x80, 0x02, 0x08, 0x14, 0x08, 0x80, 0x01, 0x1c, 0x22, 0x80, 0x02, 0x08, 0x14, 0x22, 0x80, 0x02, 0x22, 0x14, 0x08, 0x80, 0x03, 0x08, 0x08, 0x3e, 0x14, 0x80, 0x03, 0x08, 0x14, 0x22, 0x3e, 0x80, 0x03, 0x64, 0x3e, 0x2d, 0x36, 0x80, 0x02, 0x16, 0x2a, 0x2a, 0x80, 0x02, 0x0c, 0x10, 0x08, 0x80, 0x01, 0x08, 0x7f, 0x80, 0x07, 0x20, 0x10, 0x7e, 0x10, 0x08, 0x7e, 0x08, 0x04, 0x80, 0x0a, 0x20, 0x10, 0x7f, 0x10, 0x08, 0x7f, 0x08, 0x04, 0x7f, 0x04, 0x02, 0x80, 0x09, 0x70, 0x1c, 0x07, 0x1c, 0x70, 0x10, 0x7f, 0x08, 0x7f, 0x04, 0x80, 0x09, 0x07, 0x1c, 0x70, 0x1c, 0x07, 0x10, 0x7f, 0x08, 0x7f, 0x04, 0x80, 0x06, 0xd8, 0x6c, 0x36, 0x1b, 0x36, 0x6c, 0xd8, 0x80, 0x06, 0x1b, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x1b, 0x80, 0x09, 0x66, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x66, 0x80, 0x06, 0x10, 0x73, 0x3e, 0x08, 0x3e, 0x67, 0x04, 0x80, 0x08, 0x20, 0x20, 0x70, 0x1c, 0x17, 0x1c, 0x70, 0x08, 0x08, 0x80, 0x08, 0x08, 0x08, 0x07, 0x1c, 0x74, 0x1c, 0x07, 0x02, 0x02, 0x80, 0x09, 0x20, 0x20, 0x70, 0x1c, 0x17, 0x1c, 0x70, 0x08, 0x7f, 0x08, 0x80, 0x09, 0x08, 0x08, 0x07, 0x1c, 0x74, 0x1c, 0x07, 0x02, 0x7f, 0x02, 0x80, 0x0b, 0x20, 0x20, 0x70, 0x1c, 0x17, 0x1c, 0x70, 0x08, 0x6e, 0x3b, 0x04, 0x04, 0x80, 0x0a, 0x08, 0x08, 0x07, 0x1c, 0x74, 0x1c, 0x07, 0x02, 0x6e, 0x3b, 0x01, 0x80, 0x09, 0x70, 0x1c, 0x07, 0x1c, 0x70, 0x07, 0x1c, 0x70, 0x1c, 0x07, 0x80, 0x09, 0x07, 0x1c, 0x70, 0x1c, 0x07, 0x70, 0x1c, 0x07, 0x1c, 0x70, 0x80, 0x0b, 0x10, 0x70, 0x1c, 0x17, 0x1c, 0x78, 0x0f, 0x1c, 0x74, 0x1c, 0x07, 0x04, 0x80, 0x0b, 0x10, 0x17, 0x1c, 0x70, 0x1c, 0x0f, 0x78, 0x1c, 0x07, 0x1c, 0x74, 0x04, 0x80, 0x09, 0x40, 0x60, 0x38, 0x0f, 0x38, 0x60, 0x4f, 0x38, 0x60, 0x40, 0x80, 0x09, 0x01, 0x03, 0x0e, 0x78, 0x0e, 0x03, 0x79, 0x0e, 0x03, 0x01, 0x80, 0x08, 0x20, 0x60, 0x30, 0x1c, 0x17, 0x1c, 0x38, 0x68, 0x08, 0x80, 0x08, 0x08, 0x0b, 0x0e, 0x1c, 0x74, 0x1c, 0x06, 0x03, 0x02, 0x80, 0x07, 0x20, 0x7e, 0x13, 0x13, 0x0b, 0x0b, 0x7e, 0x04, 0x80, 0x07, 0x10, 0x3f, 0x68, 0x68, 0x64, 0x64, 0x3f, 0x02, 0x80, 0x09, 0x20, 0x7e, 0x13, 0x13, 0x0b, 0x0b, 0x7e, 0x04, 0x7f, 0x02, 0x80, 0x09, 0x10, 0x3f, 0x68, 0x68, 0x64, 0x64, 0x3f, 0x02, 0x7f, 0x01, 0x80, 0x08, 0x7e, 0x03, 0x03, 0x03, 0x03, 0x7e, 0x10, 0x7f, 0x08, 0x80, 0x08, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x3f, 0x08, 0x7f, 0x04, 0x80, 0x07, 0x41, 0x49, 0x45, 0x5f, 0x45, 0x49, 0x22, 0x1c, 0x80, 0x07, 0x41, 0x41, 0x49, 0x5d, 0x5d, 0x49, 0x22, 0x1c, 0x80, 0x07, 0x41, 0x41, 0x49, 0x5d, 0x49, 0x41, 0x22, 0x1c, 0x80, 0x07, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x07, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x80, 0x06, 0x1c, 0x2a, 0x49, 0x7f, 0x49, 0x2a, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x41, 0x7f, 0x41, 0x22, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x55, 0x49, 0x55, 0x22, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x51, 0x49, 0x45, 0x22, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x49, 0x5d, 0x49, 0x22, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x49, 0x55, 0x49, 0x22, 0x1c, 0x80, 0x06, 0x1c, 0x2a, 0x6b, 0x5d, 0x6b, 0x2a, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x5d, 0x41, 0x5d, 0x22, 0x1c, 0x80, 0x06, 0x1c, 0x22, 0x41, 0x5d, 0x41, 0x22, 0x1c, 0x80, 0x06, 0x7f, 0x49, 0x49, 0x7f, 0x49, 0x49, 0x7f, 0x80, 0x06, 0x7f, 0x41, 0x41, 0x7f, 0x41, 0x41, 0x7f, 0x80, 0x06, 0x7f, 0x63, 0x55, 0x49, 0x55, 0x63, 0x7f, 0x80, 0x06, 0x7f, 0x41, 0x49, 0x5d, 0x49, 0x41, 0x7f, 0x80, 0x08, 0x03, 0x03, 0x03, 0x03, 0xff, 0x03, 0x03, 0x03, 0x03, 0x80, 0x08, 0xc0, 0xc0, 0xc0, 0xc0, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x09, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x80, 0x08, 0x06, 0x06, 0x06, 0x06, 0x7e, 0x06, 0x06, 0x06, 0x06, 0x80, 0x08, 0x06, 0x06, 0x06, 0x7e, 0x06, 0x7e, 0x06, 0x06, 0x06, 0x80, 0x08, 0x03, 0x03, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03, 0x03, 0x80, 0x08, 0x1b, 0x1b, 0x1b, 0x1b, 0xfb, 0x1b, 0x1b, 0x1b, 0x1b, 0x80, 0x08, 0x15, 0x15, 0x15, 0x15, 0xf5, 0x15, 0x15, 0x15, 0x15, 0x80, 0x08, 0x1b, 0x1b, 0x1b, 0xfb, 0x1b, 0xfb, 0x1b, 0x1b, 0x1b, 0x80, 0x08, 0x03, 0x43, 0x23, 0x23, 0xff, 0x13, 0x13, 0x0b, 0x03, 0x80, 0x08, 0x03, 0x23, 0x23, 0xff, 0x13, 0xff, 0x0b, 0x0b, 0x03, 0x80, 0x08, 0x1b, 0x9b, 0x5b, 0x5b, 0xfb, 0x5b, 0x5b, 0x3b, 0x1b, 0x80, 0x08, 0x1b, 0x9b, 0x5b, 0xfb, 0x5b, 0xfb, 0x5b, 0x3b, 0x1b, 0x80, 0x06, 0x30, 0x60, 0x38, 0x0f, 0x38, 0x60, 0x30, 0x80, 0x06, 0x06, 0x03, 0x0e, 0x78, 0x0e, 0x03, 0x06, 0x80, 0x02, 0x42, 0xfd, 0x42, 0x80, 0x02, 0x42, 0xbf, 0x42, 0x80, 0x02, 0x40, 0xbe, 0x40, 0x80, 0x00, 0x63, 0x80, 0x09, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x07, 0x03, 0x03, 0x03, 0x0f, 0x13, 0x23, 0x23, 0xff, 0x80, 0x07, 0xc0, 0xe0, 0xd0, 0xc8, 0xc4, 0xc2, 0xc1, 0xff, 0x80, 0x07, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x80, 0x07, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x80, 0x04, 0x08, 0x1c, 0x36, 0x1c, 0x08, 0x80, 0x04, 0x08, 0x08, 0x3e, 0x1c, 0x14, 0x80, 0x06, 0x41, 0x63, 0x55, 0x49, 0x55, 0x63, 0x41, 0x80, 0x06, 0x41, 0x23, 0x15, 0x09, 0x15, 0x23, 0x41, 0x80, 0x06, 0x41, 0x62, 0x54, 0x48, 0x54, 0x62, 0x41, 0x80, 0x06, 0x01, 0x02, 0x04, 0x08, 0x14, 0x22, 0x41, 0x80, 0x06, 0x40, 0x20, 0x10, 0x08, 0x14, 0x22, 0x41, 0x80, 0x07, 0x08, 0x08, 0x08, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x80, 0x07, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x08, 0x08, 0x80, 0x07, 0x7c, 0x06, 0x73, 0x1b, 0x1b, 0x73, 0x06, 0x7c, 0x80, 0x07, 0x1f, 0x30, 0x67, 0x6c, 0x6c, 0x67, 0x30, 0x1f, 0x80, 0x07, 0x1c, 0x22, 0x49, 0x55, 0x55, 0x55, 0x55, 0x55, 0x80, 0x07, 0x55, 0x55, 0x55, 0x55, 0x55, 0x49, 0x22, 0x1c, 0x80, 0x09, 0x08, 0x08, 0x1c, 0x2a, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x80, 0x06, 0x18, 0x0c, 0x26, 0x73, 0x26, 0x0c, 0x18, 0x80, 0x06, 0x0c, 0x18, 0x32, 0x67, 0x32, 0x18, 0x0c, 0x80, 0x06, 0xa8, 0x54, 0x2a, 0x15, 0x2a, 0x54, 0xa8, 0x80, 0x06, 0x15, 0x2a, 0x54, 0xa8, 0x54, 0x2a, 0x15, 0x80, 0x09, 0x40, 0x60, 0x38, 0x4f, 0x60, 0x38, 0x0f, 0x38, 0x60, 0x40, 0x80, 0x09, 0x01, 0x03, 0x0e, 0x79, 0x03, 0x0e, 0x78, 0x0e, 0x03, 0x01, 0x80, 0x09, 0x50, 0x70, 0x38, 0x0f, 0x38, 0x68, 0x4f, 0x38, 0x64, 0x44, 0x80, 0x09, 0x11, 0x13, 0x0e, 0x78, 0x0e, 0x0b, 0x79, 0x0e, 0x07, 0x05, 0x80, 0x09, 0x20, 0x7f, 0x13, 0x13, 0x0b, 0x0b, 0x7f, 0x04, 0x7f, 0x02, 0x80, 0x09, 0x10, 0x7f, 0x68, 0x68, 0x64, 0x64, 0x7f, 0x02, 0x7f, 0x01, 0x80, 0x08, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x10, 0x7f, 0x08, 0x80, 0x08, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x7f, 0x08, 0x7f, 0x04, 0x80, 0x08, 0x70, 0x1c, 0x07, 0x1c, 0x70, 0x08, 0x6e, 0x3b, 0x08, 0x80, 0x08, 0x07, 0x1c, 0x70, 0x1c, 0x07, 0x08, 0x6e, 0x3b, 0x08, 0x80, 0x0a, 0x40, 0x60, 0x38, 0x0f, 0x38, 0x60, 0x40, 0x08, 0x6e, 0x3b, 0x08, 0x80, 0x0a, 0x01, 0x03, 0x0e, 0x78, 0x0e, 0x03, 0x01, 0x08, 0x6e, 0x3b, 0x08, 0x80, 0x08, 0x10, 0x70, 0x78, 0x6e, 0x6b, 0x6e, 0x78, 0x64, 0x04, 0x80, 0x08, 0x10, 0x13, 0x0f, 0x3b, 0x6b, 0x3b, 0x0f, 0x07, 0x04, 0x80, 0x0a, 0x10, 0x70, 0x78, 0x6e, 0x6b, 0x6e, 0x78, 0x64, 0x04, 0x7f, 0x02, 0x80, 0x0a, 0x10, 0x13, 0x0f, 0x3b, 0x6b, 0x3b, 0x0f, 0x07, 0x04, 0x7f, 0x02, 0x80, 0x07, 0xbc, 0x66, 0xe3, 0xd3, 0xcb, 0xc7, 0x66, 0x3d, 0x80, 0x0d, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0d, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x80, 0x0b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x80, 0x04, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x80, 0x07, 0x42, 0xa5, 0x7e, 0x24, 0x24, 0x7e, 0xa5, 0x42, 0x80, 0x08, 0x1c, 0x1c, 0x2a, 0x51, 0x6f, 0x41, 0x2a, 0x1c, 0x1c, 0x80, 0x0a, 0x7f, 0x7f, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x7f, 0x7f, 0x80, 0x0d, 0x70, 0xd8, 0xd8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, 0x1b, 0x0e, 0x80, 0x0d, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x80, 0x0d, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x80, 0x0e, 0xc0, 0x60, 0x30, 0x30, 0x18, 0x18, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x80, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x18, 0x18, 0x30, 0x30, 0x60, 0xc0, 0x80, 0x0e, 0x03, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x80, 0x0d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x03, 0x80, 0x0e, 0xfc, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x80, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xfc, 0x80, 0x0e, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x80, 0x0d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3f, 0x80, 0x0e, 0xe0, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0c, 0x07, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0xe0, 0x80, 0x0e, 0x07, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0xe0, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0c, 0x07, 0x80, 0x0f, 0xe0, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0c, 0x07, 0x80, 0x0f, 0x07, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0xe0, 0x80, 0x0d, 0xff, 0x83, 0x03, 0x06, 0x06, 0x06, 0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x18, 0x18, 0x80, 0x0d, 0x18, 0x18, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x06, 0x06, 0x06, 0x06, 0x03, 0x83, 0xff, 0x80, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, 0x1e, 0x1e, 0x1c, 0x1c, 0x18, 0x18, 0x80, 0x0f, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x09, 0xe0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa4, 0x9e, 0x43, 0x3e, 0x04, 0x80, 0x09, 0x1b, 0x1b, 0x1f, 0x1b, 0x1b, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x80, 0x09, 0x03, 0x03, 0x03, 0x03, 0x0f, 0xf0, 0x30, 0x70, 0x30, 0x30, 0x80, 0x09, 0x1b, 0x1b, 0x1f, 0x0e, 0x04, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x80, 0x09, 0x0f, 0x03, 0x07, 0x03, 0x03, 0xf0, 0x30, 0x70, 0x30, 0x30, 0x80, 0x09, 0x0e, 0x03, 0x03, 0x03, 0x0e, 0x78, 0xd8, 0x78, 0xd8, 0xd8, 0x80, 0x01, 0x41, 0x7f, 0x80, 0x09, 0x19, 0x1b, 0x1f, 0x1b, 0x1b, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x80, 0x06, 0x3e, 0x7f, 0x63, 0x63, 0x06, 0x0c, 0x0c, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x00, 0xb6, 0x80, 0x01, 0xb6, 0xb6, 0x80, 0x04, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x00, 0x55, 0x80, 0x01, 0x55, 0x55, 0x80, 0x08, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0xf8, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0x3f, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x07, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x80, 0x07, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xf8, 0x80, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xf8, 0xf8, 0x80, 0x07, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x80, 0x07, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3f, 0x80, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3f, 0x3f, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xf8, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3f, 0x3f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3f, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xff, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xff, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xff, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0xff, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0xff, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x08, 0xff, 0xff, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x07, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x1f, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xf8, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x80, 0x07, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0x80, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0x3f, 0x80, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0xf8, 0x80, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0xff, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0x3f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0xf8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xff, 0xff, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x00, 0x77, 0x80, 0x0f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x09, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x09, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x09, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x7f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x09, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x80, 0x07, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc, 0x80, 0x08, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x80, 0x07, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7f, 0x80, 0x08, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x0f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x0f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x07, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x06, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x80, 0x07, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x80, 0x08, 0xc0, 0x70, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x03, 0x0e, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x07, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0c, 0x0e, 0x03, 0x80, 0x07, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x70, 0xc0, 0x80, 0x0f, 0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x80, 0x0f, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, 0x80, 0x0f, 0x81, 0x81, 0x42, 0x42, 0x24, 0x24, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x42, 0x42, 0x81, 0x81, 0x80, 0x00, 0x1f, 0x80, 0x00, 0xf8, 0x80, 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x01, 0x3f, 0x3f, 0x80, 0x01, 0xf8, 0xf8, 0x80, 0x01, 0xff, 0xf8, 0x80, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x80, 0x01, 0xff, 0x3f, 0x80, 0x0f, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0x80, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x0f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x80, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x80, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x80, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x80, 0x0f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x80, 0x0f, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x80, 0x0f, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0x80, 0x0f, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0x80, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x08, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x08, 0x7f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7f, 0x80, 0x08, 0x3e, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x3e, 0x80, 0x08, 0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x41, 0x7f, 0x80, 0x08, 0x7f, 0x41, 0x7f, 0x41, 0x7f, 0x41, 0x7f, 0x41, 0x7f, 0x80, 0x08, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x7f, 0x80, 0x08, 0x7f, 0x55, 0x7f, 0x55, 0x7f, 0x55, 0x7f, 0x55, 0x7f, 0x80, 0x08, 0x7f, 0x51, 0x63, 0x45, 0x49, 0x51, 0x63, 0x45, 0x7f, 0x80, 0x08, 0x7f, 0x45, 0x63, 0x51, 0x49, 0x45, 0x63, 0x51, 0x7f, 0x80, 0x08, 0x7f, 0x55, 0x63, 0x55, 0x49, 0x55, 0x63, 0x55, 0x7f, 0x80, 0x04, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x80, 0x04, 0x3e, 0x22, 0x22, 0x22, 0x3e, 0x80, 0x04, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x04, 0x7f, 0x41, 0x41, 0x41, 0x7f, 0x80, 0x0b, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x0b, 0x7f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7f, 0x80, 0x05, 0x7e, 0x7e, 0x7e, 0x3f, 0x3f, 0x3f, 0x80, 0x05, 0x7e, 0x42, 0x42, 0x21, 0x21, 0x3f, 0x80, 0x06, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0x80, 0x06, 0x08, 0x14, 0x14, 0x22, 0x22, 0x41, 0x7f, 0x80, 0x03, 0x08, 0x1c, 0x1c, 0x3e, 0x80, 0x03, 0x08, 0x14, 0x14, 0x3e, 0x80, 0x0a, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x80, 0x0a, 0x01, 0x03, 0x05, 0x09, 0x11, 0x21, 0x11, 0x09, 0x05, 0x03, 0x01, 0x80, 0x04, 0x02, 0x0e, 0x1e, 0x0e, 0x02, 0x80, 0x04, 0x02, 0x0e, 0x12, 0x0e, 0x02, 0x80, 0x06, 0x01, 0x07, 0x1f, 0x7f, 0x1f, 0x07, 0x01, 0x80, 0x06, 0x01, 0x07, 0x19, 0x61, 0x19, 0x07, 0x01, 0x80, 0x06, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x80, 0x06, 0x7f, 0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x80, 0x03, 0x3e, 0x1c, 0x1c, 0x08, 0x80, 0x03, 0x3e, 0x14, 0x14, 0x08, 0x80, 0x0a, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e, 0x7c, 0x78, 0x70, 0x60, 0x40, 0x80, 0x0a, 0x40, 0x60, 0x50, 0x48, 0x44, 0x42, 0x44, 0x48, 0x50, 0x60, 0x40, 0x80, 0x04, 0x10, 0x1c, 0x1e, 0x1c, 0x10, 0x80, 0x04, 0x10, 0x1c, 0x12, 0x1c, 0x10, 0x80, 0x06, 0x40, 0x70, 0x7c, 0x7f, 0x7c, 0x70, 0x40, 0x80, 0x06, 0x40, 0x70, 0x4c, 0x43, 0x4c, 0x70, 0x40, 0x80, 0x09, 0x08, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x08, 0x80, 0x09, 0x08, 0x14, 0x22, 0x22, 0x41, 0x41, 0x22, 0x22, 0x14, 0x08, 0x80, 0x09, 0x08, 0x14, 0x22, 0x2a, 0x5d, 0x5d, 0x2a, 0x22, 0x14, 0x08, 0x80, 0x09, 0x3c, 0x42, 0x99, 0xbd, 0xbd, 0xbd, 0xbd, 0x99, 0x42, 0x3c, 0x80, 0x09, 0x08, 0x14, 0x14, 0x22, 0x41, 0x41, 0x22, 0x14, 0x14, 0x08, 0x80, 0x09, 0x3c, 0x42, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x09, 0x28, 0x02, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x40, 0x14, 0x80, 0x09, 0x3c, 0x66, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0x66, 0x3c, 0x80, 0x09, 0x3c, 0x42, 0x99, 0xa5, 0xa5, 0xa5, 0xa5, 0x99, 0x42, 0x3c, 0x80, 0x09, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x80, 0x09, 0x3c, 0x4e, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x4e, 0x3c, 0x80, 0x09, 0x3c, 0x72, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0x72, 0x3c, 0x80, 0x09, 0x3c, 0x42, 0x81, 0x81, 0x81, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x80, 0x09, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x09, 0x3c, 0x72, 0xf1, 0xf1, 0xf1, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x09, 0x3c, 0x72, 0xf1, 0xf1, 0xf1, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x80, 0x09, 0x0c, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0c, 0x80, 0x09, 0x30, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x70, 0x30, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0xbd, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x80, 0x06, 0xff, 0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0x7e, 0x80, 0x08, 0x7e, 0x7e, 0x7e, 0xbd, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x80, 0x04, 0x0c, 0x02, 0x01, 0x01, 0x01, 0x80, 0x04, 0x30, 0x40, 0x80, 0x80, 0x80, 0x80, 0x04, 0x80, 0x80, 0x80, 0x40, 0x30, 0x80, 0x04, 0x01, 0x01, 0x01, 0x02, 0x0c, 0x80, 0x04, 0x3c, 0x42, 0x81, 0x81, 0x81, 0x80, 0x04, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x0f, 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xff, 0xff, 0x80, 0x0f, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01, 0x01, 0x80, 0x0f, 0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x05, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x80, 0x09, 0xff, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0xff, 0x80, 0x09, 0xff, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xff, 0x80, 0x09, 0xff, 0xff, 0xbf, 0x9f, 0x8f, 0x8f, 0x87, 0x83, 0x81, 0xff, 0x80, 0x09, 0xff, 0x81, 0xc1, 0xe1, 0xf1, 0xf1, 0xf9, 0xfd, 0xff, 0xff, 0x80, 0x09, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff, 0x80, 0x08, 0x08, 0x08, 0x14, 0x14, 0x22, 0x22, 0x49, 0x41, 0x7f, 0x80, 0x08, 0x08, 0x08, 0x1c, 0x1c, 0x2e, 0x2e, 0x4f, 0x4f, 0x7f, 0x80, 0x08, 0x08, 0x08, 0x1c, 0x1c, 0x3a, 0x3a, 0x79, 0x79, 0x7f, 0x80, 0x0a, 0x3c, 0x42, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x08, 0x7f, 0x49, 0x49, 0x49, 0x4f, 0x41, 0x41, 0x41, 0x7f, 0x80, 0x08, 0x7f, 0x41, 0x41, 0x41, 0x4f, 0x49, 0x49, 0x49, 0x7f, 0x80, 0x08, 0x7f, 0x41, 0x41, 0x41, 0x79, 0x49, 0x49, 0x49, 0x7f, 0x80, 0x08, 0x7f, 0x49, 0x49, 0x49, 0x79, 0x41, 0x41, 0x41, 0x7f, 0x80, 0x09, 0x3c, 0x52, 0x91, 0x91, 0x91, 0x9f, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x09, 0x3c, 0x42, 0x81, 0x81, 0x9f, 0x91, 0x91, 0x91, 0x52, 0x3c, 0x80, 0x09, 0x3c, 0x42, 0x81, 0x81, 0xf9, 0x89, 0x89, 0x89, 0x4a, 0x3c, 0x80, 0x09, 0x3c, 0x4a, 0x89, 0x89, 0x89, 0xf9, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x7f, 0x1c, 0x2a, 0x08, 0x08, 0x80, 0x03, 0x0c, 0x3e, 0x7f, 0xff, 0x80, 0x08, 0x1c, 0x3e, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x28, 0x10, 0x80, 0x07, 0x08, 0x08, 0x14, 0x77, 0x22, 0x2a, 0x36, 0x22, 0x80, 0x08, 0x10, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x2c, 0x38, 0x3c, 0x80, 0x08, 0x7f, 0x63, 0x33, 0x1b, 0x0f, 0x1b, 0xb3, 0xe3, 0xf3, 0x80, 0x06, 0x1c, 0x22, 0x41, 0x49, 0x41, 0x22, 0x1c, 0x80, 0x07, 0x18, 0x24, 0x42, 0x42, 0x42, 0xa5, 0xa5, 0x42, 0x80, 0x07, 0x42, 0xa5, 0xa5, 0x42, 0x42, 0x42, 0x24, 0x18, 0x80, 0x06, 0x60, 0x30, 0x1e, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x09, 0x38, 0x6c, 0x6c, 0x38, 0x18, 0x0c, 0x0e, 0x1b, 0x1b, 0x0e, 0x80, 0x07, 0x7f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7f, 0x80, 0x07, 0x7f, 0x41, 0x61, 0x51, 0x5d, 0x49, 0x41, 0x7f, 0x80, 0x07, 0x7f, 0x41, 0x77, 0x5d, 0x5d, 0x77, 0x41, 0x7f, 0x80, 0x08, 0x41, 0x63, 0x36, 0x3e, 0x1c, 0x3e, 0x36, 0x63, 0x41, 0x80, 0x07, 0x3e, 0x41, 0x55, 0x41, 0x22, 0x3e, 0x22, 0x1c, 0x80, 0x04, 0x22, 0x63, 0x1c, 0x63, 0x22, 0x80, 0x07, 0x1c, 0x22, 0x77, 0x7f, 0x49, 0x5d, 0x3e, 0x1c, 0x80, 0x09, 0x18, 0x7e, 0x18, 0x18, 0xff, 0x18, 0x78, 0x1e, 0x18, 0x18, 0x80, 0x09, 0x18, 0x7e, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x08, 0x1c, 0x08, 0x08, 0x49, 0x7f, 0x49, 0x08, 0x08, 0x1c, 0x80, 0x09, 0x3c, 0x4e, 0x07, 0x23, 0xfb, 0x73, 0x53, 0x07, 0x4e, 0x3c, 0x80, 0x08, 0x2a, 0x14, 0x2a, 0x55, 0x55, 0x55, 0x55, 0x2a, 0x1c, 0x80, 0x09, 0x3c, 0x5a, 0x99, 0x99, 0x99, 0xbd, 0xff, 0xdb, 0x5a, 0x3c, 0x80, 0x09, 0x3c, 0x42, 0x81, 0xa1, 0x8d, 0x9f, 0xff, 0xfb, 0x7e, 0x3c, 0x80, 0x09, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0x81, 0x99, 0xa5, 0x81, 0x7e, 0x80, 0x09, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xa5, 0x99, 0x81, 0x81, 0x7e, 0x80, 0x09, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0xff, 0x7e, 0x80, 0x08, 0x08, 0x08, 0x2a, 0x14, 0x63, 0x14, 0x2a, 0x08, 0x08, 0x80, 0x09, 0x1e, 0x28, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x28, 0x1e, 0x80, 0x09, 0x78, 0x14, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x14, 0x78, 0x80, 0x0b, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x80, 0x09, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x80, 0x09, 0x18, 0x18, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0x78, 0x60, 0x70, 0x58, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x80, 0x0c, 0xc0, 0xc0, 0xde, 0xf3, 0xf3, 0xf3, 0xf0, 0xd8, 0xcc, 0xff, 0xc0, 0xc0, 0xc0, 0x80, 0x09, 0x06, 0x0f, 0x06, 0x76, 0xce, 0xc6, 0xc6, 0x66, 0x66, 0xc6, 0x80, 0x0a, 0x6b, 0x2a, 0x2a, 0x3e, 0x2a, 0x2a, 0x6b, 0x1c, 0x22, 0x22, 0x1c, 0x80, 0x0b, 0x18, 0x3c, 0xdb, 0xdb, 0xdb, 0xdb, 0x7e, 0x3c, 0x18, 0x3c, 0x18, 0x18, 0x80, 0x0a, 0x1f, 0x33, 0x33, 0x33, 0x33, 0x1f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x80, 0x0a, 0x42, 0xa5, 0xa5, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x80, 0x0a, 0xc3, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x80, 0x09, 0xc3, 0x7e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7e, 0xc3, 0x80, 0x03, 0x7e, 0xdb, 0x1b, 0x0e, 0x80, 0x03, 0x70, 0xd8, 0xdb, 0x7e, 0x80, 0x0b, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xd8, 0xde, 0xdb, 0xdb, 0xce, 0xc0, 0x80, 0x80, 0x0b, 0x29, 0x3e, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x60, 0xd0, 0x80, 0x06, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x24, 0xe7, 0x80, 0x0b, 0x29, 0x3e, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x20, 0xc0, 0x80, 0x07, 0xf8, 0xe0, 0xf1, 0xdb, 0xce, 0x0e, 0x1b, 0x11, 0x80, 0x0b, 0x09, 0x0a, 0x0e, 0x16, 0x12, 0x12, 0x72, 0x92, 0x90, 0x70, 0x08, 0x04, 0x80, 0x0a, 0xc3, 0x66, 0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0x66, 0xc3, 0x80, 0x08, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x80, 0x07, 0x36, 0x49, 0x41, 0x41, 0x41, 0x22, 0x14, 0x08, 0x80, 0x06, 0x08, 0x14, 0x22, 0x41, 0x22, 0x14, 0x08, 0x80, 0x08, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x80, 0x08, 0x18, 0x24, 0x42, 0x81, 0x81, 0x66, 0x18, 0x18, 0x3c, 0x80, 0x07, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x80, 0x06, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x80, 0x08, 0x18, 0x24, 0x3c, 0xe7, 0xa5, 0xe7, 0x18, 0x18, 0x3c, 0x80, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1c, 0x1e, 0x0e, 0x80, 0x09, 0x0c, 0x3c, 0x7c, 0x4c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0f, 0x07, 0x80, 0x0a, 0x0e, 0xfe, 0xf6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xe7, 0xe3, 0x60, 0x80, 0x0a, 0xfe, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xe7, 0xe7, 0x63, 0x80, 0x09, 0x03, 0x03, 0x03, 0x03, 0x33, 0x7b, 0x67, 0x23, 0x1b, 0x07, 0x80, 0x0b, 0x02, 0x02, 0x22, 0x3a, 0x2e, 0x22, 0x22, 0x3a, 0x2e, 0x22, 0x20, 0x20, 0x80, 0x0b, 0x20, 0x20, 0x62, 0x3a, 0x2e, 0x23, 0x62, 0x3a, 0x2e, 0x23, 0x02, 0x02, 0x80, 0x09, 0xdc, 0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0x66, 0xff, 0x80, 0x09, 0x3c, 0x76, 0x66, 0x06, 0x7f, 0x66, 0x66, 0x66, 0x66, 0xff, 0x80, 0x09, 0x7c, 0x76, 0x66, 0x66, 0x7f, 0x66, 0x66, 0x66, 0x66, 0xff, 0x80, 0x09, 0x76, 0xdb, 0xdb, 0x1b, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xff, 0x80, 0x09, 0xf6, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xff, 0x80, 0x09, 0x1c, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0xb6, 0x6f, 0x80, 0x08, 0x0e, 0xf1, 0x4c, 0x82, 0x11, 0x01, 0x11, 0x02, 0x7c, 0x80, 0x08, 0x0e, 0xf1, 0x4c, 0x82, 0x01, 0x29, 0x01, 0x02, 0x7c, 0x80, 0x08, 0x0e, 0xf1, 0x4c, 0x82, 0x29, 0x01, 0x11, 0x02, 0x7c, 0x80, 0x08, 0x0e, 0xf1, 0x4c, 0x82, 0x29, 0x01, 0x29, 0x02, 0x7c, 0x80, 0x08, 0x04, 0x1c, 0x14, 0x0e, 0x10, 0x10, 0x20, 0x62, 0x9c, 0x80, 0x07, 0x80, 0x40, 0x20, 0x10, 0x12, 0x21, 0x41, 0xbe, 0x80, 0x08, 0x25, 0x90, 0x48, 0x20, 0x10, 0x12, 0x21, 0x41, 0xbe, 0x80, 0x08, 0x45, 0x30, 0xc8, 0x30, 0x08, 0x10, 0x20, 0x20, 0x1f, 0x80, 0x08, 0x45, 0x30, 0xc8, 0x30, 0x08, 0x08, 0x10, 0x20, 0xdf, 0x80, 0x08, 0x0e, 0x01, 0x0e, 0x01, 0x08, 0x16, 0x11, 0x2e, 0xc0, 0x80, 0x04, 0x08, 0x0f, 0x08, 0x28, 0x10, 0x80, 0x04, 0x08, 0xef, 0x10, 0x10, 0x10, 0x80, 0x05, 0x08, 0x1c, 0x32, 0x4a, 0x4c, 0x3f, 0x80, 0x05, 0x08, 0x1c, 0x32, 0x4a, 0x4c, 0xbf, 0x80, 0x08, 0x0e, 0x01, 0x0e, 0x01, 0x10, 0x28, 0x06, 0x01, 0x7f, 0x80, 0x06, 0x54, 0x40, 0x4c, 0x42, 0x4c, 0x63, 0x9e, 0x80, 0x06, 0xc5, 0x30, 0x08, 0x10, 0x20, 0x20, 0x1f, 0x80, 0x06, 0xc5, 0x30, 0x08, 0x08, 0x10, 0x20, 0xdf, 0x80, 0x04, 0x08, 0x14, 0x18, 0x08, 0x04, 0x80, 0x06, 0x30, 0x48, 0xf0, 0x40, 0x3c, 0x18, 0x06, 0x80, 0x05, 0xe0, 0x11, 0xe1, 0x81, 0x7e, 0x08, 0x80, 0x08, 0x04, 0x04, 0x04, 0x04, 0x10, 0x20, 0x40, 0x42, 0x3c, 0x80, 0x08, 0x18, 0x24, 0x19, 0x06, 0x43, 0x48, 0x49, 0x39, 0x06, 0x80, 0x07, 0x40, 0x49, 0x39, 0x06, 0x70, 0x0e, 0x70, 0x0e, 0x80, 0x05, 0x18, 0x06, 0x20, 0x2a, 0x1a, 0x04, 0x80, 0x07, 0x08, 0x14, 0x08, 0x06, 0x20, 0x2a, 0x1a, 0x04, 0x80, 0x05, 0x20, 0x2a, 0x1a, 0x04, 0x30, 0x0c, 0x80, 0x05, 0x08, 0x08, 0x20, 0x2a, 0x1a, 0x04, 0x80, 0x05, 0x70, 0x0f, 0x40, 0x49, 0x39, 0x06, 0x80, 0x08, 0x18, 0x24, 0x18, 0x06, 0x40, 0x49, 0x39, 0x06, 0xff, 0x80, 0x05, 0x40, 0x48, 0x39, 0x06, 0x70, 0x0e, 0x80, 0x08, 0x08, 0x14, 0x0a, 0x14, 0x10, 0x10, 0x10, 0x10, 0xe0, 0x80, 0x08, 0x10, 0x28, 0x14, 0x28, 0x20, 0x20, 0x20, 0x20, 0x20, 0x80, 0x08, 0x20, 0x10, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x10, 0x20, 0x80, 0x08, 0x04, 0x08, 0x10, 0x54, 0x38, 0x54, 0x10, 0x08, 0x04, 0x80, 0x01, 0x54, 0x28, 0x80, 0x04, 0x84, 0x96, 0x95, 0x96, 0x68, 0x80, 0x01, 0x08, 0x10, 0x80, 0x03, 0x18, 0x24, 0x10, 0x08, 0x80, 0x06, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x80, 0x06, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x80, 0x06, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, 0x80, 0x06, 0x18, 0x10, 0x10, 0x20, 0x10, 0x10, 0x18, 0x80, 0x06, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x80, 0x06, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x80, 0x04, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x80, 0x06, 0x08, 0x14, 0x14, 0x08, 0x54, 0x24, 0x58, 0x80, 0x05, 0x08, 0x08, 0x3e, 0x1c, 0x1c, 0x22, 0x80, 0x04, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x80, 0x04, 0x10, 0x08, 0x04, 0x08, 0x10, 0x80, 0x04, 0x04, 0x08, 0x10, 0x08, 0x04, 0x80, 0x05, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x80, 0x07, 0x08, 0x1c, 0x2a, 0x0c, 0x18, 0x2a, 0x1c, 0x08, 0x80, 0x05, 0x24, 0x10, 0x10, 0x08, 0x08, 0x24, 0x80, 0x05, 0x1c, 0x22, 0x2a, 0x1a, 0x02, 0x1c, 0x80, 0x05, 0x60, 0x18, 0x06, 0x60, 0x18, 0x06, 0x80, 0x04, 0x18, 0x24, 0x28, 0x18, 0x06, 0x80, 0x04, 0x40, 0x48, 0x49, 0x39, 0x06, 0x80, 0x08, 0x80, 0x7c, 0x02, 0x10, 0x10, 0x10, 0x10, 0x10, 0xe0, 0x80, 0x08, 0x30, 0x08, 0x70, 0x08, 0x20, 0x20, 0x20, 0x20, 0xc0, 0x80, 0x0a, 0x0c, 0x02, 0x1c, 0x02, 0xe0, 0x10, 0x11, 0x61, 0x81, 0x81, 0x7e, 0x80, 0x03, 0x0c, 0x02, 0x1c, 0x02, 0x80, 0x07, 0x38, 0x04, 0x38, 0x04, 0x10, 0x20, 0x20, 0x1f, 0x80, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, 0xe0, 0x80, 0x08, 0x0e, 0xf1, 0x4c, 0x82, 0x01, 0x11, 0x01, 0x02, 0x7c, 0x80, 0x06, 0x04, 0x04, 0x04, 0x34, 0x4c, 0x45, 0xbe, 0x80, 0x06, 0x04, 0x04, 0x04, 0x34, 0x4c, 0x44, 0x3f, 0x80, 0x06, 0x04, 0x04, 0x04, 0x34, 0x4c, 0x44, 0xbf, 0x80, 0x06, 0x24, 0x04, 0x04, 0x34, 0x4c, 0x45, 0xbe, 0x80, 0x06, 0x24, 0x04, 0x04, 0x34, 0x4c, 0x44, 0x3f, 0x80, 0x06, 0x24, 0x04, 0x04, 0x34, 0x4c, 0x44, 0xbf, 0x80, 0x07, 0x60, 0x90, 0x92, 0xe1, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x06, 0x4c, 0x42, 0x4c, 0x42, 0x40, 0x61, 0x9e, 0x80, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x42, 0x41, 0x41, 0x21, 0x1e, 0x80, 0x06, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x80, 0x06, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xef, 0x80, 0x07, 0x10, 0x3c, 0xd2, 0x52, 0x22, 0x02, 0x02, 0x02, 0x80, 0x03, 0x30, 0x48, 0x4c, 0x33, 0x80, 0x03, 0x30, 0x48, 0x4c, 0xb3, 0x80, 0x06, 0x10, 0x80, 0x82, 0x81, 0x81, 0x42, 0x3c, 0x80, 0x07, 0x10, 0x28, 0x24, 0x14, 0xcf, 0x24, 0x18, 0x30, 0x80, 0x09, 0x16, 0x09, 0x40, 0x44, 0x48, 0x50, 0x20, 0x30, 0x48, 0x3c, 0x80, 0x08, 0x16, 0x09, 0x40, 0x4c, 0x48, 0x50, 0x50, 0x70, 0xbc, 0x80, 0x09, 0x06, 0x01, 0x4e, 0x45, 0x48, 0x50, 0x20, 0x30, 0x48, 0x3c, 0x80, 0x08, 0x0c, 0x02, 0x5c, 0x4a, 0x48, 0x50, 0x50, 0x70, 0xbc, 0x80, 0x09, 0x8f, 0xac, 0xaa, 0x51, 0x07, 0x60, 0xa9, 0x6b, 0xad, 0xe9, 0x80, 0x04, 0x77, 0x51, 0x77, 0x14, 0x17, 0x80, 0x0b, 0x1c, 0x3e, 0x3e, 0x63, 0x49, 0x4f, 0x67, 0x7f, 0x67, 0x3e, 0x3e, 0x1c, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcb, 0x0c, 0x00, 0x9e, 0x00, 0x00, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x75, 0x06, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd7, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xdd, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf8, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x02, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0e, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x20, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2c, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7d, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x09, 0xe6, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x33, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3d, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x61, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6d, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x79, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x85, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9d, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa9, 0x0d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x83, 0x00, 0x00, 0x00, 0x09, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x83, 0x00, 0x00, 0x00, 0x09, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb5, 0x0d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb2, 0x00, 0x00, 0x00, 0x08, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xc0, 0x0d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcb, 0x0d, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xd4, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xec, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x84, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7e, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8a, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x90, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf8, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xeb, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9c, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb4, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x96, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf9, 0x0d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x05, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa2, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1c, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x02, 0x00, 0x00, 0x05, 0xeb, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x03, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x01, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x28, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x19, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x0e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x04, 0x00, 0x00, 0x07, 0x1c, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xa8, 0x06, 0x00, 0x9f, 0x00, 0x00, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x4c, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x55, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x62, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x6f, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x78, 0x0e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x04, 0x00, 0x00, 0x07, 0x1c, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x84, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x92, 0x0e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x9e, 0x0e, 0x00, 0x00, 0x06, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa4, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xab, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb1, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x7d, 0x03, 0x00, 0x00, 0x0a, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb7, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xbf, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc7, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xc7, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd3, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb1, 0x06, 0x00, 0x00, 0x06, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xcc, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd3, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe2, 0x0e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xf1, 0x0e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdb, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x17, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x23, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0x28, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x12, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x25, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2c, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x38, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x46, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x52, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x03, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd5, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x33, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x13, 0x02, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5e, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x83, 0x00, 0x00, 0x00, 0x07, 0xb2, 0x00, 0x00, 0x00, 0x09, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x20, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x03, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x05, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6a, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x79, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x88, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x29, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x94, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x29, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa2, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbe, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x23, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcc, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xda, 0x0f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf4, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7e, 0x06, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3f, 0x05, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x03, 0x44, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb2, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x07, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4c, 0x07, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x20, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x2e, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3a, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x00, 0x05, 0x46, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x52, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x60, 0x10, 0x00, 0x00, 0x05, 0xeb, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x03, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x47, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x15, 0x03, 0x00, 0x00, 0x03, 0x50, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x02, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x02, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x65, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x73, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x81, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa5, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x28, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x02, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb1, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xbf, 0x10, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd3, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xda, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x10, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xeb, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x19, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9c, 0x03, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf4, 0x10, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x4f, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x10, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1e, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2a, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x38, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x47, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x56, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x64, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x72, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7e, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x66, 0x07, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8a, 0x11, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd5, 0x01, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xda, 0x01, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x9c, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xaa, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x69, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x69, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd2, 0x11, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe0, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xec, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf8, 0x11, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1c, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x28, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x74, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x34, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x41, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x23, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4b, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x63, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x6f, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7b, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x80, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8c, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x96, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xa5, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe4, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf0, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfc, 0x12, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x08, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x20, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5a, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x50, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x98, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa6, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2f, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3e, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4a, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x56, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x65, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x72, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7e, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x96, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa5, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb1, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbd, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbe, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xe4, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfe, 0x13, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x07, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x23, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x47, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x53, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5c, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x68, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe4, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x66, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x74, 0x14, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x75, 0x06, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8e, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9a, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa6, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc1, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd0, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdc, 0x14, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x02, 0x00, 0x00, 0x05, 0xeb, 0x14, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x14, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x21, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x8c, 0x01, 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x66, 0x07, 0x00, 0x00, 0x03, 0x5c, 0x04, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2f, 0x15, 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x15, 0x03, 0x00, 0x00, 0x03, 0x5c, 0x04, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x34, 0x15, 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x39, 0x15, 0x00, 0x00, 0x03, 0x5c, 0x04, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3d, 0x15, 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x5c, 0x04, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5f, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x42, 0x15, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4e, 0x15, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x72, 0x05, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x33, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5c, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x68, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x74, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x82, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x90, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9e, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfb, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0xad, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xfb, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbb, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x75, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xcb, 0x15, 0x00, 0x00, 0x05, 0xeb, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd0, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdc, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x07, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x03, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe8, 0x15, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf4, 0x15, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x28, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x13, 0x02, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x11, 0x16, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x33, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x1f, 0x16, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x20, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb6, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb6, 0x01, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x08, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x13, 0x08, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb6, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0x19, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x00, 0x03, 0x19, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb6, 0x01, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x00, 0x03, 0xab, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2a, 0x16, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x03, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x02, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x04, 0x00, 0x00, 0x0d, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2e, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3c, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x47, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x55, 0x16, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x63, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7b, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x89, 0x16, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x17, 0x08, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x8c, 0x01, 0x00, 0x00, 0x04, 0x68, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x23, 0x08, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x72, 0x05, 0x00, 0x00, 0x04, 0x68, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x72, 0x05, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd2, 0x01, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x9b, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa3, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xac, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb5, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbe, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xca, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd3, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdd, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xec, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf8, 0x16, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5f, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x01, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x81, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8a, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0a, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x13, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1c, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x28, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x36, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3f, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x48, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x60, 0x17, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x6f, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x24, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x78, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x81, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb7, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc0, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xcc, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd8, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe4, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf0, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x72, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf9, 0x17, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x93, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x02, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0b, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x17, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x23, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3b, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x44, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4d, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x56, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5f, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6b, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7a, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x89, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x93, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa0, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xac, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbb, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc4, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2d, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xcd, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd6, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xeb, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf4, 0x18, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x75, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0a, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x16, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2e, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x46, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4a, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x52, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x5b, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x53, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x65, 0x19, 0x00, 0x00, 0x05, 0x69, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x75, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x81, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x98, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa4, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x07, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb0, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbf, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe7, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf3, 0x19, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x02, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0e, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1a, 0x1a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5c, 0x08, 0x00, 0x00, 0x08, 0x5c, 0x08, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x26, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x2e, 0x1a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x03, 0x36, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x3d, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x43, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x49, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x50, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x58, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x5e, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x62, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x65, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3f, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x67, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6a, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x76, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x84, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8b, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x93, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x26, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x26, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0x9b, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0x9f, 0x1a, 0x00, 0x87, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd5, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xa3, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xda, 0x01, 0x00, 0x8f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xa8, 0x1a, 0x00, 0x90, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xae, 0x1a, 0x00, 0x84, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6c, 0x08, 0x00, 0x87, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3f, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe4, 0x03, 0x00, 0x8d, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x9b, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb2, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x1a, 0x00, 0xb1, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xba, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0xbf, 0x1a, 0x00, 0x83, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xc4, 0x1a, 0x00, 0x82, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x83, 0x00, 0x00, 0x00, 0x09, 0xd8, 0x00, 0x00, 0x84, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc9, 0x1a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xcd, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdb, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe9, 0x1a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x1a, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x05, 0x1b, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x21, 0x1b, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x00, 0x00, 0x05, 0x24, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x71, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x50, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2f, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x1b, 0x00, 0x00, 0x09, 0x43, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x90, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x89, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf8, 0x04, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x48, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa1, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x81, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x5a, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x24, 0x03, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x01, 0x00, 0x00, 0x05, 0x2d, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x63, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x81, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5a, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7e, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x24, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x47, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8a, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc7, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x96, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9f, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xae, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb7, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc3, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xce, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd7, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2d, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe0, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xec, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf8, 0x1b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x93, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x00, 0x05, 0x24, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x2d, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x2d, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x93, 0x05, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1c, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x28, 0x1c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x36, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x41, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4a, 0x1c, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x63, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7b, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa0, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xaf, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbc, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xca, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd5, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe1, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xed, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xfc, 0x1c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x06, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x12, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1e, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2a, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x33, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3f, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x48, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x60, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x69, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x02, 0x00, 0x00, 0x05, 0xeb, 0x02, 0x00, 0x8b, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x75, 0x1d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x83, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8e, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8a, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9a, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa6, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x1d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0xad, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, 0x03, 0x9c, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x7b, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbe, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcd, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x71, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd9, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe7, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf3, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xff, 0x1d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x19, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x90, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x89, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf8, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xec, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x25, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x31, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3f, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4b, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x65, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x71, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x89, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa1, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xad, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4a, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb8, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb9, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa7, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8a, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x36, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0x36, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x47, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc4, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xcd, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x53, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd6, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x01, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xdf, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xe8, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf5, 0x1e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc1, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x14, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xca, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1d, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd3, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x26, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x1f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x38, 0x1f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xb8, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x47, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x02, 0x00, 0x00, 0x05, 0xeb, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x50, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x59, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x07, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x47, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0x36, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x62, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6e, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb0, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7a, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x86, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x92, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9e, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa7, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb3, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbc, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc8, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd1, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xdd, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf2, 0x1f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfb, 0x1f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x05, 0x0b, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x16, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x50, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x72, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x31, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xdc, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x03, 0x3d, 0x20, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x01, 0x00, 0x00, 0x05, 0xdc, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x48, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x57, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x63, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x71, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7c, 0x20, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe5, 0x08, 0x00, 0x00, 0x05, 0xb0, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xea, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x20, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xea, 0x08, 0x00, 0x00, 0x05, 0xb0, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa4, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe5, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xbb, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc0, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc5, 0x20, 0x00, 0x80, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb9, 0x05, 0x00, 0x00, 0x06, 0xca, 0x20, 0x00, 0x00, 0x08, 0xee, 0x08, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcd, 0x20, 0x00, 0x00, 0x06, 0xd2, 0x20, 0x00, 0x00, 0x09, 0xd6, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdb, 0x20, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0xeb, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xf6, 0x20, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x03, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x19, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x25, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x33, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3e, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4a, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x53, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x62, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6e, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7c, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x96, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa2, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb0, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc7, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd0, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdc, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe8, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf4, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfd, 0x21, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x12, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x21, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2d, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x39, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x42, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x50, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5b, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x67, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x73, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7f, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8d, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x98, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa6, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb1, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbf, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xca, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd6, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xeb, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf4, 0x22, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x09, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x18, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x24, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0xa7, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x32, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x41, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4d, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5b, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x66, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x75, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x81, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8f, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9a, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa8, 0x23, 0x00, 0x80, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x33, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x80, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5f, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xb3, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x5f, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xbe, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xa7, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xc9, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x8a, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x23, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x75, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x9c, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x36, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x9c, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x36, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x66, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x50, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x72, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x72, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xeb, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xd3, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x7b, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x7b, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x03, 0x7b, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xda, 0x01, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xf6, 0x23, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xc1, 0x08, 0x00, 0x81, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x01, 0x24, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xca, 0x08, 0x00, 0x85, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0c, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x18, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x24, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x30, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3c, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x45, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x53, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5e, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x6a, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x73, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7f, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x88, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x94, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9d, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa9, 0x24, 0x00, 0x9f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb2, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xeb, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x24, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x11, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1d, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x29, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x35, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x41, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4e, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5a, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x66, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x72, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7f, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xeb, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x25, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1c, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x28, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4c, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x58, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x64, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x70, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7c, 0x26, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x88, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8e, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x62, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x94, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x99, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x9e, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xa3, 0x26, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa8, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb1, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbd, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc9, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd5, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe1, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xed, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfb, 0x26, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x07, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x13, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1f, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2e, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3a, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x64, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x70, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7c, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x88, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa0, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xac, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb8, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc4, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xcd, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd9, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe5, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf1, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfa, 0x27, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x03, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x12, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1b, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x27, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x33, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3c, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4b, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x57, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x60, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x28, 0x00, 0x80, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7b, 0x28, 0x00, 0x85, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x80, 0x28, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0xbd, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x86, 0x28, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x92, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x97, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9c, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa1, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xa6, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xab, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb5, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xba, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbf, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc5, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xcb, 0x28, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x0b, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x10, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xd1, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xd6, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xdb, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe1, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xec, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xf2, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x28, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd5, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x01, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xfc, 0x28, 0x00, 0x00, 0x0e, 0xff, 0x28, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x02, 0x29, 0x00, 0x00, 0x0e, 0x05, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x08, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x01, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xbd, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xbd, 0x05, 0x00, 0x00, 0x0e, 0x01, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0x0d, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc0, 0x05, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x12, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0d, 0x26, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x17, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x15, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x55, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3f, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x83, 0x00, 0x00, 0x8a, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x1b, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x25, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2f, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x39, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x43, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4d, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x57, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x61, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x6b, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x75, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x7c, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x89, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x93, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x9f, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xa9, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb3, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xc0, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xca, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xd4, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xde, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xeb, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf5, 0x29, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x02, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x0c, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x19, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x23, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2d, 0x2a, 0x00, 0x84, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x37, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x41, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4b, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xda, 0x01, 0x00, 0x96, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x52, 0x2a, 0x00, 0x8d, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x58, 0x2a, 0x00, 0x00, 0x08, 0x83, 0x00, 0x00, 0x82, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5d, 0x2a, 0x00, 0x00, 0x09, 0x7d, 0x00, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xc4, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1f, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2a, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x35, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcb, 0x05, 0x00, 0x00, 0x0a, 0xd3, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x65, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcb, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x63, 0x02, 0x00, 0x00, 0x04, 0x43, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x42, 0x09, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x49, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x66, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x86, 0x04, 0x00, 0x00, 0x04, 0x66, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x71, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x71, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2b, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5d, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4a, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x56, 0x03, 0x00, 0x00, 0x04, 0x4a, 0x03, 0x00, 0x84, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x89, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd9, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x66, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x72, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x0e, 0xe5, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7a, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x9d, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa3, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xa3, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x88, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x72, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x93, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x93, 0x09, 0x00, 0x89, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x77, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa4, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7c, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x92, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xba, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc5, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd0, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9d, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xa9, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb1, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xdb, 0x09, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x59, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x00, 0x04, 0xe5, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xec, 0x09, 0x00, 0x00, 0x04, 0xe5, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xed, 0x05, 0x00, 0x00, 0x0a, 0xec, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb8, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbe, 0x2a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf1, 0x09, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf1, 0x09, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xc9, 0x2a, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x0d, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x0d, 0x87, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd3, 0x2a, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x66, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x05, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x10, 0x0a, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0x66, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf5, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x1b, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xe2, 0x2a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x79, 0x02, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xec, 0x2a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf5, 0x2a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x0c, 0x79, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfd, 0x2a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb8, 0x00, 0x00, 0x00, 0x05, 0x05, 0x2b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x26, 0x0a, 0x00, 0x00, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x03, 0xd1, 0x00, 0x00, 0x00, 0x05, 0x26, 0x0a, 0x00, 0x00, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x0d, 0x2b, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0x16, 0x2b, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x86, 0x04, 0x00, 0x00, 0x02, 0x2e, 0x0a, 0x00, 0x00, 0x04, 0x4a, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x0a, 0x0b, 0x06, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x0a, 0xd1, 0x00, 0x00, 0x00, 0x0c, 0xb8, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x89, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x89, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x31, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x1f, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x28, 0x2b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0x94, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x04, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x32, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x44, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3d, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x48, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x55, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x62, 0x2b, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd9, 0x05, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x00, 0x0e, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0x6f, 0x2b, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7a, 0x2b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x00, 0x04, 0xf5, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa7, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x2b, 0x00, 0x00, 0x07, 0xa7, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x07, 0xa7, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x89, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5a, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x79, 0x02, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x63, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x06, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x14, 0x06, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x92, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x9c, 0x2b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x18, 0x06, 0x00, 0x00, 0x0d, 0x7d, 0x00, 0x00, 0x00, 0x0f, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x18, 0x06, 0x00, 0x00, 0x0d, 0x87, 0x00, 0x00, 0x00, 0x0f, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x71, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa7, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x43, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb2, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbb, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xca, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd1, 0x2b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x78, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd9, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfc, 0x2b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x78, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x02, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x06, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x85, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x85, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0b, 0x8b, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8b, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x21, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0b, 0x7e, 0x0a, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x24, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa4, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2a, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x35, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xba, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc5, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd0, 0x09, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x4b, 0x2c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x53, 0x2c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x56, 0x03, 0x00, 0x00, 0x04, 0x5c, 0x2c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xc4, 0x05, 0x00, 0x00, 0x0a, 0x68, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x6e, 0x2c, 0x00, 0xc9, 0xd3, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7a, 0x2c, 0x00, 0x82, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x86, 0x2c, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8f, 0x2c, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9b, 0x2c, 0x00, 0x87, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa4, 0x2c, 0x00, 0xcd, 0x18, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x02, 0x00, 0x00, 0x0d, 0xd5, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x0d, 0xd5, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0xb0, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xbb, 0x2c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x02, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x05, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x02, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x05, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0xc8, 0x2c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x2f, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0xd6, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe1, 0x2c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x84, 0x03, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x02, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x84, 0x03, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x02, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xef, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x2c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1c, 0x2d, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x27, 0x06, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x27, 0x06, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2b, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x02, 0x00, 0x00, 0x0d, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x0d, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x46, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0x17, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x54, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x5f, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x9f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x44, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x6a, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x02, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x03, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x44, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0x78, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x92, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x02, 0x00, 0x00, 0x0d, 0xc4, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x03, 0x00, 0x00, 0x0d, 0xc4, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x0d, 0x99, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x0d, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa1, 0x2d, 0x00, 0x00, 0x04, 0xa6, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x2d, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0xad, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb6, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x03, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x03, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x02, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x02, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x50, 0x07, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x5b, 0x07, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x02, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x02, 0x00, 0x00, 0x0d, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc3, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd2, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x92, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x03, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x92, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x03, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x02, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x03, 0x03, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x28, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x02, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x02, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x71, 0x01, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe1, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf0, 0x2d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfc, 0x2d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9d, 0x0a, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x02, 0x23, 0x08, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x2e, 0x00, 0x00, 0x04, 0x68, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x2e, 0x00, 0x00, 0x04, 0x68, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0xa3, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0x01, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0xa3, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x01, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x19, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9c, 0x03, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x00, 0x03, 0x19, 0x03, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x00, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9c, 0x03, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7a, 0x01, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x4f, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x03, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x2e, 0x00, 0x00, 0x04, 0x19, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x23, 0x2e, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x29, 0x2e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x37, 0x2e, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x4f, 0x05, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x83, 0x01, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x45, 0x2e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x50, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x02, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x04, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x49, 0x02, 0x00, 0x00, 0x0d, 0xb2, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x04, 0x00, 0x00, 0x0d, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5d, 0x2e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6c, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb4, 0x03, 0x00, 0x00, 0x0d, 0x95, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x0d, 0x95, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb4, 0x03, 0x00, 0x00, 0x0d, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x0d, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7b, 0x2e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8a, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x96, 0x2e, 0x00, 0x00, 0x05, 0x9c, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9d, 0x0a, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x02, 0x8a, 0x00, 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x05, 0x00, 0x00, 0x03, 0xef, 0x01, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0xa5, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0x19, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x05, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x19, 0x04, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x03, 0xab, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x03, 0xab, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x91, 0x00, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xab, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0xab, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x96, 0x06, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0xae, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xae, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x03, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x03, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0a, 0x02, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x03, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x03, 0xbe, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd5, 0x01, 0x00, 0x00, 0x05, 0xc9, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd5, 0x01, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x67, 0x08, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x03, 0xc9, 0x2e, 0x00, 0x83, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x02, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6a, 0x03, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf0, 0x2e, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf6, 0x2e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x04, 0x2f, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x04, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x18, 0x2f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x26, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdb, 0x06, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x34, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x42, 0x2f, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x48, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x56, 0x2f, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5c, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x6a, 0x2f, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x70, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x2f, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x03, 0x3a, 0x01, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x02, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x84, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6a, 0x03, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x03, 0x45, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x92, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb9, 0x0a, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa0, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbf, 0x0a, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x04, 0x00, 0x00, 0x05, 0x27, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x04, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xae, 0x2f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbc, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xbb, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xca, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6a, 0x03, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0xdd, 0x00, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x90, 0x03, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd8, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6a, 0x03, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb9, 0x0a, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbf, 0x0a, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x04, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x12, 0x07, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05, 0xa6, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2c, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x46, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6e, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x89, 0x30, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x98, 0x07, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa6, 0x07, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb4, 0x03, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x96, 0x30, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6c, 0x08, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa4, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbe, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd8, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe6, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf3, 0x30, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x01, 0x31, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbe, 0x07, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x07, 0x00, 0x00, 0x0d, 0x8d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcc, 0x03, 0x00, 0x00, 0x0d, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0e, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1a, 0x31, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6a, 0x03, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x28, 0x31, 0x00, 0x00, 0x03, 0x17, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x05, 0xf5, 0x00, 0x00, 0x85, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe4, 0x03, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x2c, 0x31, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x31, 0x31, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x36, 0x31, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3b, 0x31, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x40, 0x31, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x46, 0x31, 0x00, 0x00, 0x05, 0x8f, 0x01, 0x00, 0xc0, 0xf7, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x4c, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x53, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x5a, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x61, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x68, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x6f, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x76, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x7d, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x84, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x8b, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x92, 0x31, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x30, 0x06, 0x00, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x30, 0x06, 0x00, 0x00, 0x08, 0x99, 0x31, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x30, 0x06, 0x00, 0x00, 0x08, 0xa0, 0x31, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0xa7, 0x31, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0xb4, 0x31, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x8a, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc1, 0x31, 0x00, 0x00, 0x07, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x66, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc8, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe6, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0xe6, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xce, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd4, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc5, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0xc5, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xda, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe0, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcb, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x21, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xec, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0xe6, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x37, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x83, 0x00, 0x00, 0x87, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xf5, 0x31, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x00, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0b, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x10, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1a, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1f, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x24, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0b, 0xa2, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x29, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x32, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xd7, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x32, 0x00, 0x00, 0x0a, 0xe6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x44, 0x32, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x4d, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x51, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x55, 0x32, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x5c, 0x32, 0x00, 0x00, 0x08, 0x61, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x66, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6a, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x76, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x82, 0x32, 0x00, 0x80, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8e, 0x32, 0x00, 0x00, 0x0a, 0x97, 0x32, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9b, 0x32, 0x00, 0x00, 0x0a, 0x3b, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa4, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xac, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb8, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xc1, 0x32, 0x00, 0xa1, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe0, 0x0a, 0x00, 0x82, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe8, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xf0, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xf8, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x08, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x10, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x18, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xef, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xef, 0x01, 0x00, 0x00, 0x04, 0xef, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x1f, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x27, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2f, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xe0, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd3, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb7, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xbf, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xe8, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xf0, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xf8, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x08, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x10, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x18, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x09, 0xef, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xef, 0x01, 0x00, 0x00, 0x0a, 0xef, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x1f, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x27, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x2f, 0x0b, 0x00, 0x8f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xca, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd6, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x32, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x0a, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x21, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2d, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x39, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x45, 0x33, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x07, 0x00, 0x00, 0x0d, 0x8a, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4f, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5b, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x67, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x73, 0x33, 0x00, 0xc0, 0x4f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x80, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8e, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9c, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb4, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc0, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xce, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8c, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdc, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe8, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf4, 0x33, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0c, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1b, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x27, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x33, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3f, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4b, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x63, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7b, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x93, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x9f, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xac, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc5, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd1, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdd, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf6, 0x34, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x05, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x0b, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x12, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x18, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x27, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x33, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa1, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd8, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x42, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4e, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x57, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x65, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x71, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7d, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x86, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8f, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9b, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa7, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb3, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbf, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc8, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe0, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xec, 0x35, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf8, 0x35, 0x00, 0x00, 0x05, 0xfc, 0x35, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x05, 0x36, 0x00, 0x97, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x0e, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x1d, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x2c, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3b, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x4a, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x59, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x68, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x77, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x86, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x95, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xa4, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb3, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xc2, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xce, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xda, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe6, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x04, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x36, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0a, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x16, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2e, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xec, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x84, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0x3b, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x95, 0x00, 0x00, 0x00, 0x05, 0x3a, 0x37, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x37, 0x06, 0x00, 0x00, 0x05, 0x43, 0x37, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3f, 0x03, 0x00, 0x00, 0x05, 0x4c, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x19, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x02, 0x00, 0x00, 0x05, 0x55, 0x37, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x0b, 0x00, 0x00, 0x05, 0x5e, 0x37, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x67, 0x37, 0x00, 0x00, 0x05, 0x6b, 0x37, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3f, 0x03, 0x00, 0x00, 0x05, 0x74, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x02, 0x00, 0x00, 0x05, 0x7d, 0x37, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x0b, 0x00, 0x00, 0x05, 0x86, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc0, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x03, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8f, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9b, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa7, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x74, 0x07, 0x00, 0x8b, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb3, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xba, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc6, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcd, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd9, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe0, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x3a, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xeb, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf4, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xfd, 0x37, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x06, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0d, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x14, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x19, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1e, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x25, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x31, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x38, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x44, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4b, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x52, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x59, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x65, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6c, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x78, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x84, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x8c, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x94, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x9c, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa4, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xab, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xbe, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xc9, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xd4, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xdf, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xea, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf2, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xfa, 0x38, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x04, 0x39, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb5, 0x00, 0x00, 0x00, 0x04, 0x3a, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0e, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x1a, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x25, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x43, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x48, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x30, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3c, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4d, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x52, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x48, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x60, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6c, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x78, 0x39, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x0b, 0x00, 0x00, 0x08, 0x57, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x84, 0x39, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5e, 0x0b, 0x00, 0x00, 0x08, 0x5e, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x90, 0x39, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x43, 0x0b, 0x00, 0x00, 0x08, 0x52, 0x0b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4d, 0x0b, 0x00, 0x00, 0x08, 0x48, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9c, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa3, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xaa, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb1, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc4, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcb, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd7, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xde, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xea, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xf5, 0x39, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x00, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x0b, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x16, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x1f, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x28, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x42, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4e, 0x3a, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x3a, 0x00, 0x00, 0x07, 0x01, 0x01, 0x00, 0x00, 0x09, 0x01, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5b, 0x3a, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00, 0x00, 0x08, 0x62, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x68, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x6f, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x76, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7f, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x8b, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x3a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa0, 0x3a, 0x00, 0x00, 0x0a, 0xa9, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xae, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xba, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc6, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd2, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xdf, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xec, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x3a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0b, 0x3b, 0x00, 0x8b, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x18, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x24, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2f, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3b, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x47, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x08, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x61, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x6d, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x78, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x85, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8e, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xa6, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xaf, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc6, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd4, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb2, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb2, 0x00, 0x00, 0x00, 0x06, 0x7d, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x83, 0x00, 0x00, 0x00, 0x06, 0x7d, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xe2, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xf0, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfe, 0x3b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x65, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x21, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x05, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x11, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1d, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x29, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x35, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3d, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x46, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x50, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe4, 0x07, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x59, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x66, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x65, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x44, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xbc, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x71, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7b, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8b, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9b, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xab, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbb, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xcb, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdb, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xeb, 0x3c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfb, 0x3c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x00, 0x00, 0x00, 0x0a, 0xe6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x00, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x00, 0x00, 0x00, 0x0a, 0xe6, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x83, 0x00, 0x00, 0x00, 0x07, 0xb2, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x22, 0x02, 0x00, 0x00, 0x07, 0xef, 0x01, 0x00, 0x00, 0x09, 0x22, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x07, 0xb2, 0x00, 0x00, 0x00, 0x09, 0xe6, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x83, 0x00, 0x00, 0x00, 0x06, 0x99, 0x00, 0x00, 0x00, 0x09, 0x8d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x4e, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0b, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x11, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x19, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x24, 0x3d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x80, 0x00, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x99, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x2e, 0x3d, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x99, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x38, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x41, 0x3d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x99, 0x00, 0x00, 0x00, 0x08, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x4d, 0x3d, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x99, 0x00, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x99, 0x00, 0x00, 0x00, 0x06, 0x99, 0x00, 0x00, 0x00, 0x09, 0x99, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4e, 0x06, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x58, 0x3d, 0x00, 0x00, 0x08, 0x5c, 0x3d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb9, 0x05, 0x00, 0x00, 0x08, 0xee, 0x08, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb9, 0x05, 0x00, 0x00, 0x08, 0xb2, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0xb2, 0x00, 0x00, 0x00, 0x08, 0xb2, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x05, 0xb2, 0x00, 0x00, 0x00, 0x08, 0xb2, 0x00, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x05, 0x00, 0x00, 0x05, 0xb2, 0x00, 0x00, 0x00, 0x08, 0xb2, 0x00, 0x00, 0x00, 0x0a, 0x55, 0x02, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x02, 0x00, 0x00, 0x05, 0xb2, 0x00, 0x00, 0x00, 0x08, 0xb2, 0x00, 0x00, 0x00, 0x0a, 0xc0, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x60, 0x3d, 0x00, 0x00, 0x08, 0x64, 0x3d, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x68, 0x3d, 0x00, 0x00, 0x08, 0x6c, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x70, 0x3d, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x75, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7a, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7e, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x88, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x8e, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x94, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9a, 0x3d, 0x00, 0x00, 0x06, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x9f, 0x3d, 0x00, 0x00, 0x05, 0xa4, 0x3d, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xa8, 0x3d, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb2, 0x3d, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x05, 0x80, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x0b, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x7d, 0x02, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x84, 0x02, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7d, 0x02, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x0b, 0x80, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x84, 0x02, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x0b, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xbf, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcb, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xd7, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xe0, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf5, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfe, 0x3d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x09, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x14, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x20, 0x3e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x7d, 0x02, 0x00, 0x00, 0x0a, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x84, 0x02, 0x00, 0x00, 0x0a, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2c, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3a, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x47, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x53, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x5f, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6d, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x6b, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x74, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7b, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x87, 0x3e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6b, 0x0b, 0x00, 0x00, 0x0a, 0x99, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x74, 0x0b, 0x00, 0x00, 0x0a, 0x99, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x93, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9e, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x7d, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x85, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xa9, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb3, 0x3e, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7d, 0x0b, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x85, 0x0b, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbd, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc9, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xd5, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xe0, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xeb, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf5, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xff, 0x3e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x8d, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x95, 0x0b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8d, 0x0b, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x95, 0x0b, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x09, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x13, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x1d, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x26, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2f, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x38, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x41, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4a, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x53, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x5c, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x65, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x6e, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x77, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x80, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x89, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x92, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x9d, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa8, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb4, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xc0, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcb, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xd6, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xe1, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xec, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xf7, 0x3f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x02, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x0d, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x18, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x23, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x2e, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x37, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x9d, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xa6, 0x0b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9d, 0x0b, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa6, 0x0b, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x40, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x45, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x4a, 0x40, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xaf, 0x0b, 0x00, 0x00, 0x07, 0x4f, 0x40, 0x00, 0x00, 0x09, 0xaf, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x52, 0x40, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbc, 0x04, 0x00, 0x00, 0x0b, 0x80, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x04, 0x44, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x04, 0xbc, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x5e, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x68, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x44, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xbc, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x72, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7c, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x86, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8d, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xd7, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x94, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x9d, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xa6, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xaf, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xb8, 0x40, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x4e, 0x06, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xc1, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcb, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xd5, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xdf, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xe9, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xf3, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xfd, 0x40, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcb, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x09, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x12, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x1b, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x24, 0x41, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x02, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x09, 0x84, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x84, 0x02, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x09, 0x7d, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x06, 0x7d, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x06, 0x84, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2d, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x39, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x45, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x51, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5d, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x69, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x75, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x80, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x8b, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x96, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa1, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xae, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc6, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd1, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xde, 0x41, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00, 0x00, 0x06, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x83, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x37, 0x06, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x22, 0x02, 0x00, 0x00, 0x06, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x3f, 0x03, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3f, 0x03, 0x00, 0x00, 0x06, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x22, 0x02, 0x00, 0x8d, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xeb, 0x41, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xa8, 0x06, 0x00, 0x84, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x41, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x05, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x15, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x23, 0x42, 0x00, 0x83, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x31, 0x42, 0x00, 0x86, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x38, 0x42, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x42, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x4d, 0x42, 0x00, 0x83, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5a, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x6a, 0x42, 0x00, 0x86, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x78, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x88, 0x42, 0x00, 0xc0, 0x6f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x98, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb3, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa9, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb9, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc5, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xca, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xda, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb3, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xeb, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xfb, 0x42, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc5, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x1c, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2d, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3f, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x52, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x4f, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x60, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x72, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x52, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x82, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x94, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa6, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb6, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd7, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0xdb, 0x0b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xdb, 0x0b, 0x00, 0x00, 0x08, 0xd7, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc6, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdf, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd6, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x09, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0b, 0xb5, 0x00, 0x00, 0x8f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe8, 0x43, 0x00, 0xb9, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf4, 0x43, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0c, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x18, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x24, 0x44, 0x00, 0x94, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x30, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x44, 0x00, 0x80, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x44, 0x00, 0x00, 0x0a, 0x8d, 0x00, 0x00, 0xc0, 0xd8, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x64, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x52, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x49, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x5b, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x5e, 0x44, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x22, 0x04, 0x00, 0x00, 0x05, 0x1c, 0x05, 0x00, 0x00, 0x0b, 0x22, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf1, 0x0b, 0x00, 0x00, 0x05, 0x62, 0x44, 0x00, 0x00, 0x0b, 0xf1, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x69, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x6c, 0x44, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, 0x00, 0x04, 0x26, 0x02, 0x00, 0x00, 0x08, 0x26, 0x02, 0x00, 0x00, 0x0c, 0x26, 0x02, 0x00, 0x00, 0x04, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc6, 0x04, 0x00, 0x00, 0x04, 0xc6, 0x04, 0x00, 0x00, 0x08, 0xc6, 0x04, 0x00, 0x00, 0x0c, 0xc6, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x70, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x7b, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x86, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x91, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x9c, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa7, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb2, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xbd, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc8, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd2, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdd, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe7, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf2, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfc, 0x44, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x07, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x11, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2e, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x52, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x64, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x76, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x88, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9a, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xac, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbe, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd0, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf4, 0x45, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x06, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x18, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2a, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x3c, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x47, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x52, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x5d, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x68, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x73, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x7e, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x89, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x94, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9e, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa9, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb4, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xbf, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc9, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdf, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xea, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfc, 0x46, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x20, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x32, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x44, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x56, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x68, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7a, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8c, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9e, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc2, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd4, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe6, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf8, 0x47, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x0a, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x36, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x06, 0x00, 0x00, 0x08, 0x3b, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x0b, 0x00, 0x00, 0x08, 0xf7, 0x0b, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xb5, 0x00, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0d, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x1f, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x2b, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x36, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x42, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x4e, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x59, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x65, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x70, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7a, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x85, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x90, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9a, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa5, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb7, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc9, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdb, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xed, 0x48, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xff, 0x48, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xb5, 0x00, 0x00, 0x00, 0x08, 0x11, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x1b, 0x49, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xb5, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x26, 0x49, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2f, 0x49, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x0c, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x39, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4b, 0x49, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x0c, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x5d, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x68, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x73, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x99, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xab, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xbd, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x15, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xc0, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xc3, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xce, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd2, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x13, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd6, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xda, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xec, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf0, 0x49, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x02, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0e, 0x64, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0x0b, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x11, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x19, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x23, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2f, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3d, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4d, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x71, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x83, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x95, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa7, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdf, 0x0b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb9, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xcb, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xdd, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xef, 0x4a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x64, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x13, 0x4b, 0x00, 0x89, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x25, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x30, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x3b, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x46, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x51, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x5c, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x67, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x72, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7d, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x88, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x93, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x9a, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa1, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa8, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbd, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xcb, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xd3, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xdb, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe4, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xed, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xf3, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xf9, 0x4b, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x06, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x13, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x1a, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x21, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2a, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x33, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x45, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x4b, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x51, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x5e, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x6b, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x72, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x79, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x82, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8b, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x97, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa3, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbb, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xeb, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x4c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x03, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0f, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1b, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x27, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x33, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3f, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4b, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x63, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x75, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x90, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9b, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa2, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa9, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xb0, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb7, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xbe, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xc5, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd7, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe9, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfb, 0x4d, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x0d, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x15, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x21, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2d, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x39, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x45, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x51, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x5c, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x67, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x72, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7f, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x8a, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x95, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xa0, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xab, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb7, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc3, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcf, 0x4e, 0x00, 0x87, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xdb, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xe6, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xec, 0x4e, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xdb, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xf7, 0x4e, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x01, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0c, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x17, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x20, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2a, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x3d, 0x4f, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x49, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x53, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x5d, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x67, 0x4f, 0x00, 0x8b, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x72, 0x4f, 0x00, 0x00, 0x0a, 0x7c, 0x4f, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x83, 0x4f, 0x00, 0x82, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8d, 0x4f, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x99, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xa5, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb0, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xbc, 0x4f, 0x00, 0x81, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc7, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd3, 0x4f, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x01, 0x00, 0x00, 0x06, 0x57, 0x01, 0x00, 0x00, 0x0a, 0x57, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x01, 0x00, 0x00, 0x06, 0x57, 0x01, 0x00, 0x00, 0x0a, 0x57, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x01, 0x00, 0x00, 0x06, 0x36, 0x01, 0x00, 0x00, 0x0a, 0x57, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x01, 0x00, 0x00, 0x06, 0x36, 0x01, 0x00, 0x00, 0x0a, 0x57, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x01, 0x00, 0x00, 0x06, 0x57, 0x01, 0x00, 0x00, 0x0a, 0x36, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x01, 0x00, 0x00, 0x06, 0x57, 0x01, 0x00, 0x00, 0x0a, 0x36, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x57, 0x01, 0x00, 0x00, 0x06, 0x36, 0x01, 0x00, 0x00, 0x0a, 0x36, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x36, 0x01, 0x00, 0x00, 0x06, 0x36, 0x01, 0x00, 0x00, 0x0a, 0x36, 0x01, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdf, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xeb, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf7, 0x4f, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x03, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0e, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x1a, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x26, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x40, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x4c, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x58, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x67, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x73, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x80, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8e, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9b, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xa8, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb5, 0x50, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc1, 0x50, 0x00, 0x00, 0x08, 0xc7, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xcd, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdb, 0x50, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x50, 0x00, 0x00, 0x0a, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf2, 0x50, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x00, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0a, 0x51, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x1e, 0x0c, 0x00, 0x00, 0x08, 0x1e, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x18, 0x51, 0x00, 0x8b, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x25, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x30, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x3a, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x43, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x4e, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x59, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x63, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x6c, 0x51, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x77, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x83, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8f, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x9c, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa9, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb5, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc3, 0x51, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xd7, 0x8f, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd1, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xdd, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xe9, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xf5, 0x51, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x01, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x0d, 0x52, 0x00, 0xc0, 0x49, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x00, 0x04, 0xed, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x05, 0x00, 0x00, 0x04, 0x23, 0x0c, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x68, 0x06, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0xcb, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0xd2, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x68, 0x06, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0xcb, 0x04, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x04, 0xd2, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x10, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x19, 0x52, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x0a, 0xb8, 0x00, 0x00, 0x00, 0x0c, 0xb8, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x05, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x24, 0x52, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x0b, 0xd1, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xf5, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2f, 0x52, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x0a, 0xd1, 0x00, 0x00, 0x00, 0x0c, 0xb8, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x1b, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x52, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x0a, 0xd1, 0x00, 0x00, 0x00, 0x0c, 0xd1, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x0a, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x87, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x6f, 0x03, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x63, 0x02, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x63, 0x02, 0x00, 0x00, 0x04, 0x6f, 0x03, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x63, 0x02, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x63, 0x02, 0x00, 0x00, 0x04, 0x6f, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x45, 0x52, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x87, 0x00, 0x00, 0x00, 0x07, 0xd9, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x07, 0xd9, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x31, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x50, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2b, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3d, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x48, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x53, 0x0c, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x0a, 0xaf, 0x00, 0x00, 0x00, 0x0c, 0xaf, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3d, 0x0c, 0x00, 0x00, 0x0a, 0xaf, 0x00, 0x00, 0x00, 0x0c, 0xaf, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x48, 0x0c, 0x00, 0x00, 0x0a, 0xaf, 0x00, 0x00, 0x00, 0x0c, 0xaf, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x53, 0x0c, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x44, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x5a, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x65, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x70, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x5e, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x07, 0x5e, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7b, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x43, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xa7, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x86, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x8d, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x66, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x66, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x94, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x9c, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x71, 0x0a, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x6f, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa4, 0x52, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6f, 0x06, 0x00, 0x00, 0x08, 0x6f, 0x0c, 0x00, 0xa0, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x3b, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x02, 0xaf, 0x52, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x56, 0x03, 0x00, 0x00, 0x02, 0xb8, 0x52, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x56, 0x03, 0x00, 0x00, 0x02, 0xc1, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x63, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xca, 0x52, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x79, 0x02, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x79, 0x02, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x06, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x06, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf7, 0x09, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x87, 0x00, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x5a, 0x0a, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x79, 0x02, 0x00, 0x00, 0x06, 0xd1, 0x52, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x14, 0x06, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x14, 0x06, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x0d, 0xaf, 0x00, 0x00, 0x00, 0x0f, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xda, 0x52, 0x00, 0x00, 0x0f, 0xaf, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0a, 0x7d, 0x00, 0x00, 0x00, 0x0c, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x91, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x18, 0x06, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x76, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0xc0, 0x5a, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xe2, 0x52, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x59, 0x03, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x59, 0x03, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xed, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf8, 0x52, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x02, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x53, 0x00, 0xab, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x59, 0x03, 0x00, 0x00, 0x08, 0x76, 0x03, 0x00, 0xc0, 0x60, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x24, 0x53, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2c, 0x53, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x37, 0x53, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0xc0, 0x46, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x3f, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x4a, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x55, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x60, 0x53, 0x00, 0xc0, 0xb1, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6b, 0x53, 0x00, 0x00, 0x04, 0x6f, 0x53, 0x00, 0xc0, 0x5c, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x09, 0x75, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x09, 0x76, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x09, 0xaf, 0x00, 0x00, 0x80, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x7d, 0x00, 0x00, 0x00, 0x09, 0x75, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xaf, 0x00, 0x00, 0x00, 0x09, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x7a, 0x53, 0x00, 0x00, 0x0a, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x59, 0x03, 0x00, 0x00, 0x0a, 0xaf, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x80, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x89, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x92, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x9b, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xa4, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xad, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xb6, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xbd, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xc6, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xce, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xd2, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xd5, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xdc, 0x53, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd2, 0x01, 0x00, 0x00, 0x09, 0xd2, 0x01, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe3, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xeb, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xf5, 0x53, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xfd, 0x53, 0x00, 0x83, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x05, 0x54, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x7a, 0x09, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0a, 0x9d, 0x04, 0x00, 0x80, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xa3, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x79, 0x0c, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0d, 0x54, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x0c, 0xa3, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x0b, 0x79, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x88, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x14, 0x54, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x65, 0x0b, 0x00, 0x00, 0x08, 0xb5, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xc4, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1f, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x1b, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x2a, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x26, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x35, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6f, 0x06, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xed, 0x05, 0x00, 0x00, 0x0a, 0x7e, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x23, 0x0c, 0x00, 0x00, 0x0a, 0x7e, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x31, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x3e, 0x54, 0x00, 0x00, 0x08, 0x76, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x44, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x6f, 0x06, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xcb, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x4e, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0b, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x63, 0x02, 0x00, 0x00, 0x04, 0x43, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x2e, 0x0a, 0x00, 0x00, 0x03, 0x84, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x42, 0x09, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xea, 0x00, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0xba, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x49, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x56, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x0b, 0xaf, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x66, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x8c, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x86, 0x04, 0x00, 0x00, 0x04, 0x66, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x86, 0x04, 0x00, 0x00, 0x05, 0x8c, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xaf, 0x00, 0x00, 0x00, 0x05, 0x34, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x00, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x6f, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x00, 0x04, 0x6f, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0xd9, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x7d, 0x00, 0x00, 0x00, 0x07, 0xd9, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x71, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x71, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x97, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x07, 0x9c, 0x0c, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x05, 0x71, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x87, 0x00, 0x00, 0x00, 0x06, 0x71, 0x02, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x03, 0xd1, 0x00, 0x00, 0x00, 0x06, 0x97, 0x0c, 0x00, 0x00, 0x03, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x03, 0x87, 0x00, 0x00, 0x00, 0x07, 0x9c, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x2b, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x2b, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe0, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x2b, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xb8, 0x00, 0x00, 0x00, 0x05, 0x2b, 0x02, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x05, 0xe0, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x05, 0xe0, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x54, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x61, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x6a, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x73, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x5d, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7c, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x85, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x8e, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x4a, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xa0, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xac, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xb2, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x56, 0x03, 0x00, 0x00, 0x04, 0x4a, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x7d, 0x00, 0x00, 0x00, 0x04, 0xa0, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x00, 0x05, 0xac, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xb2, 0x0c, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x98, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x00, 0x00, 0x00, 0x04, 0x68, 0x06, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0xcb, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x04, 0xd2, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x04, 0x89, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xd1, 0x00, 0x00, 0x00, 0x05, 0x97, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x04, 0xcb, 0x04, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0x04, 0xd2, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x94, 0x04, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xa1, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x2b, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x34, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0xd9, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xaa, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb7, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x66, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xc9, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd3, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xd9, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xde, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xdf, 0x54, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0xaf, 0x00, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0x43, 0x03, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x84, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x03, 0x72, 0x09, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x04, 0xe8, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x27, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0x40, 0x02, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x76, 0x03, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0xe6, 0x01, 0x00, 0x00, 0x0e, 0xe5, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x76, 0x03, 0x00, 0x00, 0x0e, 0xe5, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x0b, 0x87, 0x00, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xf2, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0xfe, 0x54, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x09, 0x55, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x15, 0x55, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x0c, 0x00, 0x00, 0x0b, 0xd3, 0x05, 0x00, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc2, 0x0c, 0x00, 0x00, 0x0b, 0xd3, 0x05, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xb8, 0x0c, 0x00, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x02, 0xc2, 0x0c, 0x00, 0x81, 0x00, 0x02, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x20, 0x55, 0x00, 0x00, 0x0b, 0x2c, 0x55, 0x00, 0xc0, 0xfc, 0x00, 0x01, 0x08, 0x10, 0x08, 0x00, 0x00, 0x01, 0x33, 0x55, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x32, 0x4e, 0x46, 0x53 }; static const unsigned int u_vga16_sfn_len = 59195; tboot-1.10.5/tboot/include/vga/ssfn.h0000644000000000000000000020000214210363175015520 0ustar 00000000000000/* * ssfn.h * * Copyright (C) 2020 bzt (bztsrc@gitlab) * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * @brief Scalable Screen Font renderers * */ #ifndef _SSFN_H_ #define _SSFN_H_ #define SSFN_VERSION 0x0200 #ifdef __cplusplus extern "C" { # ifndef __THROW # define __THROW throw() # endif #else # ifndef __THROW # define __THROW # endif #endif /* if stdint.h was not included before us */ #ifndef _STDINT_H typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef short int int16_t; typedef unsigned int uint32_t; #ifndef _UINT64_T //typedef unsigned long int uint64_t; #endif #endif /***** file format *****/ /* magic bytes */ #define SSFN_MAGIC "SFN2" #define SSFN_COLLECTION "SFNC" #define SSFN_ENDMAGIC "2NFS" /* ligatures area */ #define SSFN_LIG_FIRST 0xF000 #define SSFN_LIG_LAST 0xF8FF /* font family group in font type byte */ #define SSFN_TYPE_FAMILY(x) ((x)&15) #define SSFN_FAMILY_SERIF 0 #define SSFN_FAMILY_SANS 1 #define SSFN_FAMILY_DECOR 2 #define SSFN_FAMILY_MONOSPACE 3 #define SSFN_FAMILY_HAND 4 /* font style flags in font type byte */ #define SSFN_TYPE_STYLE(x) (((x)>>4)&15) #define SSFN_STYLE_REGULAR 0 #define SSFN_STYLE_BOLD 1 #define SSFN_STYLE_ITALIC 2 #define SSFN_STYLE_USRDEF1 4 /* user defined variant 1 */ #define SSFN_STYLE_USRDEF2 8 /* user defined variant 2 */ /* contour commands */ #define SSFN_CONTOUR_MOVE 0 #define SSFN_CONTOUR_LINE 1 #define SSFN_CONTOUR_QUAD 2 #define SSFN_CONTOUR_CUBIC 3 /* glyph fragments, kerning groups and hinting grid info */ #define SSFN_FRAG_CONTOUR 0 #define SSFN_FRAG_BITMAP 1 #define SSFN_FRAG_PIXMAP 2 #define SSFN_FRAG_KERNING 3 #define SSFN_FRAG_HINTING 4 /* main SSFN header, 32 bytes */ typedef struct { uint8_t magic[4]; /* SSFN magic bytes */ uint32_t size; /* total size in bytes */ uint8_t type; /* font family and style */ uint8_t features; /* format features and revision */ uint8_t width; /* overall width of the font */ uint8_t height; /* overall height of the font */ uint8_t baseline; /* horizontal baseline in grid pixels */ uint8_t underline; /* position of under line in grid pixels */ uint16_t fragments_offs; /* offset of fragments table relative to magic */ uint32_t characters_offs; /* characters table offset relative to magic */ uint32_t ligature_offs; /* ligatures table offset relative to magic */ uint32_t kerning_offs; /* kerning table offset relative to magic */ uint32_t cmap_offs; /* color map offset relative to magic */ } __attribute__((packed)) ssfn_font_t; /***** renderer API *****/ #define SSFN_FAMILY_ANY 0xff /* select the first loaded font */ #define SSFN_FAMILY_BYNAME 0xfe /* select font by its unique name */ /* additional styles not stored in fonts */ #define SSFN_STYLE_UNDERLINE 16 /* under line glyph */ #define SSFN_STYLE_STHROUGH 32 /* strike through glyph */ #define SSFN_STYLE_NOAA 64 /* no anti-aliasing */ #define SSFN_STYLE_NOKERN 128 /* no kerning */ #define SSFN_STYLE_NODEFGLYPH 256 /* don't draw default glyph */ #define SSFN_STYLE_NOCACHE 512 /* don't cache rasterized glyph */ #define SSFN_STYLE_NOHINTING 1024 /* no auto hinting grid (not used as of now) */ #define SSFN_STYLE_RTL 2048 /* render right-to-left */ #define SSFN_STYLE_ABS_SIZE 4096 /* scale absoulte height */ /* error codes */ #define SSFN_OK 0 /* success */ #define SSFN_ERR_ALLOC -1 /* allocation error */ #define SSFN_ERR_BADFILE -2 /* bad SSFN file format */ #define SSFN_ERR_NOFACE -3 /* no font face selected */ #define SSFN_ERR_INVINP -4 /* invalid input */ #define SSFN_ERR_BADSTYLE -5 /* bad style */ #define SSFN_ERR_BADSIZE -6 /* bad size */ #define SSFN_ERR_NOGLYPH -7 /* glyph (or kerning info) not found */ #define SSFN_SIZE_MAX 192 /* biggest size we can render */ #define SSFN_ITALIC_DIV 4 /* italic angle divisor, glyph top side pushed width / this pixels */ #define SSFN_PREC 4 /* precision in bits */ /* destination frame buffer context */ typedef struct { uint8_t *ptr; /* pointer to the buffer */ int16_t w; /* width (positive: ARGB, negative: ABGR pixels) */ int16_t h; /* height */ uint16_t p; /* pitch, bytes per line */ int16_t x; /* cursor x */ int16_t y; /* cursor y */ uint32_t fg; /* foreground color */ uint32_t bg; /* background color */ } ssfn_buf_t; /* cached bitmap struct */ #define SSFN_DATA_MAX ((SSFN_SIZE_MAX + 4 + (SSFN_SIZE_MAX + 4) / SSFN_ITALIC_DIV) << 8) typedef struct { uint16_t p; /* data buffer pitch, bytes per line */ uint8_t h; /* data buffer height */ uint8_t o; /* overlap of glyph, scaled to size */ uint8_t x; /* advance x, scaled to size */ uint8_t y; /* advance y, scaled to size */ uint8_t a; /* ascender, scaled to size */ uint8_t d; /* descender, scaled to size */ uint8_t data[SSFN_DATA_MAX]; /* data buffer */ } ssfn_glyph_t; /* character metrics */ typedef struct { uint8_t t; /* type and overlap */ uint8_t n; /* number of fragments */ uint8_t w; /* width */ uint8_t h; /* height */ uint8_t x; /* advance x */ uint8_t y; /* advance y */ } ssfn_chr_t; #ifdef SSFN_PROFILING #include #include #endif /* renderer context */ typedef struct { #ifdef SSFN_MAXLINES const ssfn_font_t *fnt[5][16]; /* static font registry */ #else const ssfn_font_t **fnt[5]; /* dynamic font registry */ #endif const ssfn_font_t *s; /* explicitly selected font */ const ssfn_font_t *f; /* font selected by best match */ ssfn_glyph_t ga; /* glyph sketch area */ ssfn_glyph_t *g; /* current glyph pointer */ #ifdef SSFN_MAXLINES uint16_t p[SSFN_MAXLINES*2]; #else ssfn_glyph_t ***c[17]; /* glyph cache */ uint16_t *p; char **bufs; /* allocated extra buffers */ #endif ssfn_chr_t *rc; /* pointer to current character */ int numbuf, lenbuf, np, ap; int mx, my, lx, ly; /* move to coordinates, last coordinates */ int len[5]; /* number of fonts in registry */ int family; /* required family */ int style; /* required style */ int size; /* required size */ int line; /* calculate line height */ #ifdef SSFN_PROFILING uint64_t lookup, raster, blit, kern;/* profiling accumulators */ #endif } ssfn_t; /***** API function protoypes *****/ uint32_t ssfn_utf8(char **str); /* decode UTF-8 sequence */ /* normal renderer */ int ssfn_load(ssfn_t *ctx, const void *data); /* add an SSFN to context */ int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size); /* select font to use */ int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str); /* render a glyph to a pixel buffer */ int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top); /* get bounding box of a rendered string */ ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg); /* renders text to a newly allocated buffer */ int ssfn_mem(ssfn_t *ctx); /* return how much memory is used */ void ssfn_free(ssfn_t *ctx); /* free context */ #define ssfn_error(err) (err<0&&err>=-7?ssfn_errstr[-err]:"Unknown error") /* return string for error code */ extern const char *ssfn_errstr[]; /* simple renderer */ extern ssfn_font_t *ssfn_src; /* font buffer */ extern ssfn_buf_t ssfn_dst; /* destination frame buffer */ int ssfn_putc(uint32_t unicode); /* render console bitmap font */ /***** renderer implementations *****/ /*** these go for both renderers ***/ #if (defined(SSFN_IMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \ defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)) && !defined(SSFN_COMMON) #define SSFN_COMMON /** * Error code strings */ const char *ssfn_errstr[] = { "", "Memory allocation error", "Bad file format", "No font face found", "Invalid input value", "Invalid style", "Invalid size", "Glyph not found" }; /** * Decode an UTF-8 multibyte, advance string pointer and return UNICODE. Watch out, no input checks * * @param **s pointer to an UTF-8 string pointer * @return unicode, and *s moved to next multibyte sequence */ uint32_t ssfn_utf8(char **s) { uint32_t c = **s; if((**s & 128) != 0) { if(!(**s & 32)) { c = ((**s & 0x1F)<<6)|(*(*s+1) & 0x3F); *s += 1; } else if(!(**s & 16)) { c = ((**s & 0xF)<<12)|((*(*s+1) & 0x3F)<<6)|(*(*s+2) & 0x3F); *s += 2; } else if(!(**s & 8)) { c = ((**s & 0x7)<<18)|((*(*s+1) & 0x3F)<<12)|((*(*s+2) & 0x3F)<<6)|(*(*s+3) & 0x3F); *s += 3; } else c = 0; } *s += 1; /* *s++ is not what you think */ return c; } #endif #ifdef SSFN_IMPLEMENTATION /*** normal renderer (ca. 28k, fully featured with error checking) ***/ # ifndef NULL # define NULL (void*)0 # endif # ifndef size_t typedef __SIZE_TYPE__ size_t; # endif # ifndef inline # define inline __inline__ # endif #ifndef _STRING_H_ extern int memcmp (const void *__s1, const void *__s2, size_t __n) __THROW; extern void *memset (void *__s, int __c, size_t __n) __THROW; #endif /* Clang does not have built-in versions but gcc has */ # ifndef SSFN_memcmp # ifdef __builtin_memcmp # define SSFN_memcmp __builtin_memcmp # else # ifndef SSFN_MAXLINES # define SSFN_memcmp memcmp # else static int SSFN_memcmp(const void *__s1, const void *__s2, size_t __n) { unsigned char *a = (unsigned char *)__s1, *b = (unsigned char *)__s2; if(__n > 0) { while(__n-- > 0) { if(*a != *b) { return *a - *b; } a++; b++; } } return 0; } # endif # endif # endif # ifndef SSFN_memset # ifdef __builtin_memset # define SSFN_memset __builtin_memset # else # ifndef SSFN_MAXLINES # define SSFN_memset memset # else static void *SSFN_memset(void *__s, int __c, size_t __n) { unsigned char *a = __s; if(__n > 0) { while(__n-- > 0) *a++ = __c; } return __s; } # endif # endif # endif # ifndef SSFN_MAXLINES # ifndef SSFN_realloc # ifdef __builtin_realloc # define SSFN_realloc __builtin_realloc # else # define SSFN_realloc realloc extern void *realloc (void *__ptr, size_t __size) __THROW; # endif # endif # ifndef SSFN_free # ifdef __builtin_free # define SSFN_free __builtin_free # else # define SSFN_free free extern void free (void *p) __THROW; # endif # endif # endif /* if !SSFN_MAXLINES */ /*** Private functions ***/ /* parse character table */ static uint8_t *_ssfn_c(const ssfn_font_t *font, const char *str, int *len, uint32_t *unicode) { uint32_t i, j, u = -1U; uint16_t *l; uint8_t *ptr, *s; *len = 0; *unicode = 0; if(!font || !font->characters_offs || !str || !*str) return NULL; if(font->ligature_offs) { for(l = (uint16_t*)((uint8_t*)font + font->ligature_offs), i = 0; l[i] && u == -1U; i++) { for(ptr = (uint8_t*)font + l[i], s = (uint8_t*)str; *ptr && *ptr == *s; ptr++, s++); if(!*ptr) { u = SSFN_LIG_FIRST + i; *len = (int)(s - (uint8_t*)str); break; } } } if(u == -1U) { s = (uint8_t*)str; u = ssfn_utf8((char**)&s); *len = (int)(s - (uint8_t*)str); } *unicode = u; for(ptr = (uint8_t*)font + font->characters_offs, i = 0; i < 0x110000; i++) { if(ptr[0] == 0xFF) { i += 65535; ptr++; } else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; } else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; } else { if(i == u) return ptr; ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); } } return NULL; } /* add a line to contour */ static void _ssfn_l(ssfn_t *ctx, int p, int h, int x, int y) { if(x < 0 || y < 0 || x >= p || y >= h || ( ((ctx->lx + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((x + (1 << (SSFN_PREC-1))) >> SSFN_PREC) && ((ctx->ly + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((y + (1 << (SSFN_PREC-1))) >> SSFN_PREC))) return; #ifdef SSFN_MAXLINES if(ctx->np >= SSFN_MAXLINES*2-2) return; #else if(ctx->ap <= ctx->np) { ctx->ap = ctx->np + 512; ctx->p = (uint16_t*)SSFN_realloc(ctx->p, ctx->ap * sizeof(uint16_t)); if(!ctx->p) { ctx->ap = ctx->np = 0; return; } } #endif if(!ctx->np) { ctx->p[0] = ctx->mx; ctx->p[1] = ctx->my; ctx->np += 2; } ctx->p[ctx->np+0] = x; ctx->p[ctx->np+1] = y; ctx->np += 2; ctx->lx = x; ctx->ly = y; } /* add a Bezier curve to contour */ static void _ssfn_b(ssfn_t *ctx, int p,int h, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l) { int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y; if(l<4 && (x0!=x3 || y0!=y3)) { m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0; m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1; m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2; m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y; m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y; m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y; _ssfn_b(ctx, p,h, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1); _ssfn_b(ctx, p,h, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1); } if(l) _ssfn_l(ctx, p,h, x3, y3); } #ifndef SSFN_MAXLINES /* free internal cache */ static void _ssfn_fc(ssfn_t *ctx) { int i, j, k; if(!ctx) return; for(k = 0; k <= 16; k++) if(ctx->c[k]) { for(j = 0; j < 256; j++) if(ctx->c[k][j]) { for(i = 0; i < 256; i++) if(ctx->c[k][j][i]) SSFN_free(ctx->c[k][j][i]); SSFN_free(ctx->c[k][j]); } SSFN_free(ctx->c[k]); ctx->c[k] = NULL; } } /* * gzip deflate uncompressor from stb_image.h with minor modifications to reduce dependency * stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h */ #define SSFN__ZFAST_BITS 9 #define SSFN__ZFAST_MASK ((1 << SSFN__ZFAST_BITS) - 1) typedef struct { uint16_t fast[1 << SSFN__ZFAST_BITS]; uint16_t firstcode[16]; int maxcode[17]; uint16_t firstsymbol[16]; unsigned char size[288]; uint16_t value[288]; } _ssfn__zhuffman; inline static int _ssfn__bitreverse16(int n) { n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); return n; } inline static int _ssfn__bit_reverse(int v, int bits) { return _ssfn__bitreverse16(v) >> (16-bits); } static int _ssfn__zbuild_huffman(_ssfn__zhuffman *z, unsigned char *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; SSFN_memset(sizes, 0, sizeof(sizes)); SSFN_memset(z->fast, 0, sizeof(z->fast)); for (i=0; i < num; ++i) ++sizes[sizelist[i]]; sizes[0] = 0; for (i=1; i < 16; ++i) if (sizes[i] > (1 << i)) return 0; code = 0; for (i=1; i < 16; ++i) { next_code[i] = code; z->firstcode[i] = (uint16_t) code; z->firstsymbol[i] = (uint16_t) k; code = (code + sizes[i]); if (sizes[i]) if (code-1 >= (1 << i)) return 0; z->maxcode[i] = code << (16-i); code <<= 1; k += sizes[i]; } z->maxcode[16] = 0x10000; for (i=0; i < num; ++i) { int s = sizelist[i]; if (s) { int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; uint16_t fastv = (uint16_t) ((s << 9) | i); z->size [c] = (unsigned char) s; z->value[c] = (uint16_t) i; if (s <= SSFN__ZFAST_BITS) { int j = _ssfn__bit_reverse(next_code[s],s); while (j < (1 << SSFN__ZFAST_BITS)) { z->fast[j] = fastv; j += (1 << s); } } ++next_code[s]; } } return 1; } typedef struct { unsigned char *zbuffer; int num_bits; uint32_t code_buffer; char *zout; char *zout_start; char *zout_end; _ssfn__zhuffman z_length, z_distance; } _ssfn__zbuf; inline static unsigned char _ssfn__zget8(_ssfn__zbuf *z) { return *z->zbuffer++; } static void _ssfn__fill_bits(_ssfn__zbuf *z) { do { z->code_buffer |= (unsigned int) _ssfn__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); } inline static unsigned int _ssfn__zreceive(_ssfn__zbuf *z, int n) { unsigned int k; if (z->num_bits < n) _ssfn__fill_bits(z); k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; return k; } static int _ssfn__zhuffman_decode_slowpath(_ssfn__zbuf *a, _ssfn__zhuffman *z) { int b,s,k; k = _ssfn__bit_reverse(a->code_buffer, 16); for (s=SSFN__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; if (s == 16) return -1; b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; } inline static int _ssfn__zhuffman_decode(_ssfn__zbuf *a, _ssfn__zhuffman *z) { int b,s; if (a->num_bits < 16) _ssfn__fill_bits(a); b = z->fast[a->code_buffer & SSFN__ZFAST_MASK]; if (b) { s = b >> 9; a->code_buffer >>= s; a->num_bits -= s; return b & 511; } return _ssfn__zhuffman_decode_slowpath(a, z); } static int _ssfn__zexpand(_ssfn__zbuf *z, char *zout) { char *q; int cur, limit; z->zout = zout; cur = (int) (z->zout - z->zout_start); limit = (int) (z->zout_end - z->zout_start); if(limit == 8) { if(z->zout_start[0] != 'S' || z->zout_start[1] != 'F' || z->zout_start[2] != 'N') return 0; limit = *((uint32_t*)&z->zout_start[4]); } else return 0; q = (char *) SSFN_realloc(z->zout_start, limit); if (q == NULL) return 0; z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit; return 1; } static int _ssfn__zlength_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; static int _ssfn__zlength_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; static int _ssfn__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; static int _ssfn__zdist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static int _ssfn__parse_huffman_block(_ssfn__zbuf *a) { char *zout = a->zout; for(;;) { int z = _ssfn__zhuffman_decode(a, &a->z_length); if (z < 256) { if (z < 0) return 0; if (zout >= a->zout_end) { if (!_ssfn__zexpand(a, zout)) return 0; zout = a->zout; } *zout++ = (char) z; } else { unsigned char *p; int len,dist; if (z == 256) { a->zout = zout; return 1; } z -= 257; len = _ssfn__zlength_base[z]; if (_ssfn__zlength_extra[z]) len += _ssfn__zreceive(a, _ssfn__zlength_extra[z]); z = _ssfn__zhuffman_decode(a, &a->z_distance); if (z < 0) return 0; dist = _ssfn__zdist_base[z]; if (_ssfn__zdist_extra[z]) dist += _ssfn__zreceive(a, _ssfn__zdist_extra[z]); if (zout - a->zout_start < dist) return 0; if (zout + len > a->zout_end) { if (!_ssfn__zexpand(a, zout)) return 0; zout = a->zout; } p = (unsigned char *) (zout - dist); if (dist == 1) { unsigned char v = *p; if (len) { do *zout++ = v; while (--len); } } else { if (len) { do *zout++ = *p++; while (--len); } } } } } static int _ssfn__compute_huffman_codes(_ssfn__zbuf *a) { static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; _ssfn__zhuffman z_codelength; unsigned char lencodes[286+32+137]; unsigned char codelength_sizes[19]; int i,n; int hlit = _ssfn__zreceive(a,5) + 257; int hdist = _ssfn__zreceive(a,5) + 1; int hclen = _ssfn__zreceive(a,4) + 4; int ntot = hlit + hdist; SSFN_memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { int s = _ssfn__zreceive(a,3); codelength_sizes[length_dezigzag[i]] = (unsigned char) s; } if (!_ssfn__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; while (n < ntot) { int c = _ssfn__zhuffman_decode(a, &z_codelength); if (c < 0 || c >= 19) return 0; if (c < 16) lencodes[n++] = (unsigned char) c; else { unsigned char fill = 0; if (c == 16) { c = _ssfn__zreceive(a,2)+3; if (n == 0) return 0; fill = lencodes[n-1]; } else if (c == 17) c = _ssfn__zreceive(a,3)+3; else { c = _ssfn__zreceive(a,7)+11; } if (ntot - n < c) return 0; SSFN_memset(lencodes+n, fill, c); n += c; } } if (n != ntot) return 0; if (!_ssfn__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; if (!_ssfn__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; } inline static int _ssfn__parse_uncompressed_block(_ssfn__zbuf *a) { unsigned char header[4]; int len,nlen,k; if (a->num_bits & 7) _ssfn__zreceive(a, a->num_bits & 7); k = 0; while (a->num_bits > 0) { header[k++] = (unsigned char) (a->code_buffer & 255); a->code_buffer >>= 8; a->num_bits -= 8; } while (k < 4) header[k++] = _ssfn__zget8(a); len = header[1] * 256 + header[0]; nlen = header[3] * 256 + header[2]; if (nlen != (len ^ 0xffff)) return 0; if (a->zout + len > a->zout_end) if (!_ssfn__zexpand(a, a->zout)) return 0; for(k = 0; k < len; k++) a->zout[k] = a->zbuffer[k]; a->zbuffer += len; a->zout += len; return 1; } static unsigned char _ssfn__zdefault_length[288], _ssfn__zdefault_distance[32]; static void _ssfn__init_zdefaults(void) { int i; for (i=0; i <= 143; ++i) _ssfn__zdefault_length[i] = 8; for ( ; i <= 255; ++i) _ssfn__zdefault_length[i] = 9; for ( ; i <= 279; ++i) _ssfn__zdefault_length[i] = 7; for ( ; i <= 287; ++i) _ssfn__zdefault_length[i] = 8; for (i=0; i <= 31; ++i) _ssfn__zdefault_distance[i] = 5; } static int _ssfn__parse_zlib(_ssfn__zbuf *a) { int fin, type; a->num_bits = 0; a->code_buffer = 0; do { fin = _ssfn__zreceive(a,1); type = _ssfn__zreceive(a,2); if (type == 0) { if (!_ssfn__parse_uncompressed_block(a)) return 0; } else if (type == 3) { return 0; } else { if (type == 1) { if (!_ssfn__zbuild_huffman(&a->z_length , _ssfn__zdefault_length , 288)) return 0; if (!_ssfn__zbuild_huffman(&a->z_distance, _ssfn__zdefault_distance, 32)) return 0; } else { if (!_ssfn__compute_huffman_codes(a)) return 0; } if (!_ssfn__parse_huffman_block(a)) return 0; } } while (!fin); return 1; } char *_ssfn_zlib_decode(const char *buffer) { _ssfn__zbuf a; char *p = (char *) SSFN_realloc(NULL, 8); if (p == NULL) return NULL; a.zbuffer = (unsigned char *) buffer; a.zout_start = p; a.zout = p; a.zout_end = p + 8; _ssfn__init_zdefaults(); if (_ssfn__parse_zlib(&a)) { return a.zout_start; } else { SSFN_free(a.zout_start); return NULL; } } #endif /* if !SSFN_MAXLINES */ /*** Public API implementation ***/ /** * Load a font or font collection into renderer context * * @param ctx rendering context * @param font SSFN font or font collection in memory * @return error code */ int ssfn_load(ssfn_t *ctx, const void *data) { const ssfn_font_t *font = (const ssfn_font_t *)data; ssfn_font_t *fnt, *end; int family; #ifndef SSFN_MAXLINES uint8_t c, r, *ptr = (uint8_t *)font; #endif if(!ctx || !font) return SSFN_ERR_INVINP; if(((uint8_t *)font)[0] == 0x1f && ((uint8_t *)font)[1] == 0x8b) { #ifdef SSFN_MAXLINES return SSFN_ERR_BADFILE; #else ptr += 2; if(*ptr++ != 8) return SSFN_ERR_BADFILE; c = *ptr++; ptr += 6; if(c & 4) { r = *ptr++; r += (*ptr++ << 8); ptr += r; } if(c & 8) { while(*ptr++ != 0); } if(c & 16) { while(*ptr++ != 0); } font = (ssfn_font_t*)_ssfn_zlib_decode((const char*)ptr); if(!font) return SSFN_ERR_BADFILE; ctx->bufs = (char**)SSFN_realloc(ctx->bufs, (ctx->numbuf + 1) * sizeof(char*)); if(!ctx->bufs) { ctx->numbuf = 0; return SSFN_ERR_ALLOC; } ctx->bufs[ctx->numbuf++] = (char*)font; ctx->lenbuf += font->size; #endif } if(!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) { end = (ssfn_font_t*)((uint8_t*)font + font->size); for(fnt = (ssfn_font_t*)((uint8_t*)font + 8); fnt < end && !ssfn_load(ctx, (const void *)fnt); fnt = (ssfn_font_t*)((uint8_t*)fnt + fnt->size)); } else { family = SSFN_TYPE_FAMILY(font->type); if(SSFN_memcmp(font->magic, SSFN_MAGIC, 4) || SSFN_memcmp((uint8_t*)font + font->size - 4, SSFN_ENDMAGIC, 4) || family > SSFN_FAMILY_HAND || font->fragments_offs >= font->size || font->characters_offs >= font->size || font->ligature_offs >= font->size || font->kerning_offs >= font->size || font->cmap_offs >= font->size || font->fragments_offs >= font->characters_offs) { return SSFN_ERR_BADFILE; } else { ctx->len[family]++; #ifdef SSFN_MAXLINES if(ctx->len[family] > 15) return SSFN_ERR_ALLOC; #else ctx->fnt[family] = (const ssfn_font_t**)SSFN_realloc(ctx->fnt[family], ctx->len[family]*sizeof(void*)); if(!ctx->fnt[family]) { ctx->len[family] = 0; return SSFN_ERR_ALLOC; } else #endif ctx->fnt[family][ctx->len[family]-1] = font; } #ifndef SSFN_MAXLINES _ssfn_fc(ctx); #endif } return SSFN_OK; } /** * Free renderer context * * @param ctx rendering context */ void ssfn_free(ssfn_t *ctx) { #ifndef SSFN_MAXLINES int i; #endif if(!ctx) return; #ifndef SSFN_MAXLINES _ssfn_fc(ctx); if(ctx->bufs) { for(i = 0; i < ctx->numbuf; i++) if(ctx->bufs[i]) SSFN_free(ctx->bufs[i]); SSFN_free(ctx->bufs); } for(i = 0; i < 5; i++) if(ctx->fnt[i]) SSFN_free(ctx->fnt[i]); if(ctx->p) SSFN_free(ctx->p); #endif SSFN_memset(ctx, 0, sizeof(ssfn_t)); } /** * Returns how much memory a context consumes * * @param ctx rendering context * @return total memory used by that context in bytes */ int ssfn_mem(ssfn_t *ctx) { #ifdef SSFN_MAXLINES return ctx ? sizeof(ssfn_t) : 0; #else int i, j, k, ret = sizeof(ssfn_t); if(!ctx) return 0; for(i = 0; i < 5; i++) ret += ctx->len[i] * sizeof(ssfn_font_t*); ret += ctx->lenbuf; for(k = 0; k <= 16; k++) { if(ctx->c[k]) { for(j = 0; j < 256; j++) if(ctx->c[k][j]) { for(i = 0; i < 256; i++) if(ctx->c[k][j][i]) ret += 8 + ctx->c[k][j][i]->p * ctx->c[k][j][i]->h; ret += 256 * sizeof(void*); } ret += 256 * sizeof(void*); } } if(ctx->p) ret += ctx->ap * sizeof(uint16_t); return ret; #endif } /** * Set up rendering parameters * * @param ctx rendering context * @param family one of SSFN_FAMILY_* * @param name NULL or UTF-8 string if family is SSFN_FAMILY_BYNAME * @param style OR'd values of SSFN_STYLE_* * @param size how big glyph it should render, 8 - 192 * @return error code */ int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size) { int i, j, l; if(!ctx) return SSFN_ERR_INVINP; #ifndef SSFN_MAXLINES _ssfn_fc(ctx); #endif if((style & ~0x1FFF)) return SSFN_ERR_BADSTYLE; if(size < 8 || size > SSFN_SIZE_MAX) return SSFN_ERR_BADSIZE; if(family == SSFN_FAMILY_BYNAME) { if(!name || !name[0]) return SSFN_ERR_INVINP; for(l=0; name[l]; l++); for(i=0; i < 5; i++) { for(j=0; j < ctx->len[i]; j++) { if(!SSFN_memcmp(name, (uint8_t*)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t), l)) { ctx->s = ctx->fnt[i][j]; goto familyfound; } } } return SSFN_ERR_NOFACE; } else { if(family != SSFN_FAMILY_ANY && (family > SSFN_FAMILY_HAND || !ctx->len[family])) return SSFN_ERR_NOFACE; ctx->s = NULL; } familyfound: ctx->f = NULL; ctx->family = family; ctx->style = style; ctx->size = size; ctx->line = 0; return SSFN_OK; } /** * Render a glyph to a pixel buffer * * @param ctx rendering context * @param dst destination buffer * @param str pointer to an UTF-8 string * @return number of bytes parsed in str (zero means end of string) or error code */ int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str) { ssfn_font_t **fl; uint8_t *ptr = NULL, *frg, *end, *tmp, color, ci = 0, cb = 0, cs, dec[65536]; uint16_t r[640]; uint32_t unicode, P, O, *Op, *Ol; unsigned long int sR, sG, sB, sA; int ret = 0, i, j, k, l, p, m, n, o, s, x, y, w, h, a, A, b, B, nr, uix, uax; int ox, oy, y0, y1, Y0, Y1, x0, x1, X0, X1, X2, xs, ys, yp, pc, af, fB, fG, fR, fA, bB, bG, bR; #ifdef SSFN_PROFILING struct timeval tv0, tv1, tvd; gettimeofday(&tv0, NULL); #endif if(!ctx || !str) return SSFN_ERR_INVINP; if(!*str) return 0; /* determine the unicode from str and get a font with a fragment descriptor list for the glyph */ if(ctx->s) { ctx->f = ctx->s; ptr = _ssfn_c(ctx->f, str, &ret, &unicode); } else { /* find best match */ p = ctx->family; ctx->f = NULL; again: if(p >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = p; for(; n <= m; n++) { fl = (ssfn_font_t **)ctx->fnt[n]; if(ctx->style & 3) { /* check if we have a specific ctx->f for the requested style and size */ for(i=0;ilen[n];i++) if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && fl[i]->height == ctx->size && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } /* if not, check if we have the requested size (for bitmap fonts) */ if(!ptr) for(i=0;ilen[n];i++) if(fl[i]->height == ctx->size && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } /* if neither size+style nor size matched, look for style match */ if(!ptr) for(i=0;ilen[n];i++) if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } /* if bold italic was requested, check if we have at least bold or italic */ if(!ptr && (ctx->style & 3) == 3) for(i=0;ilen[n];i++) if(((fl[i]->type>>4) & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } } /* last resort, get the first ctx->f which has a glyph for this multibyte, no matter style */ if(!ptr) { for(i=0;ilen[n];i++) if((ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; } } } /* if glyph still not found, try any family group */ if(!ptr && p != SSFN_FAMILY_ANY) { p = SSFN_FAMILY_ANY; goto again; } } if(!ptr) { if(ctx->style & SSFN_STYLE_NODEFGLYPH) return SSFN_ERR_NOGLYPH; else { /* get the first font in family which has a default glyph */ unicode = 0; if(ctx->family >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = ctx->family; for(; n <= m && !ptr; n++) if(ctx->len[n] && ctx->fnt[n][0] && !(*((uint8_t*)ctx->fnt[n][0] + ctx->fnt[n][0]->characters_offs) & 0x80)) { ctx->f = ctx->fnt[n][0]; ptr = (uint8_t*)ctx->f + ctx->f->characters_offs; } } if(!ptr) return SSFN_ERR_NOGLYPH; } if(!ctx->f || !ctx->f->height || !ctx->size) return SSFN_ERR_NOFACE; if((unicode >> 16) > 0x10) return SSFN_ERR_INVINP; ctx->rc = (ssfn_chr_t*)ptr; ptr += sizeof(ssfn_chr_t); #ifdef SSFN_PROFILING gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } ctx->lookup += tvd.tv_sec * 1000000L + tvd.tv_usec; memcpy(&tv0, &tv1, sizeof(struct timeval)); #endif /* render glyph into cache */ #ifndef SSFN_MAXLINES if(!(ctx->style & SSFN_STYLE_NOCACHE) && ctx->c[unicode >> 16] && ctx->c[unicode >> 16][(unicode >> 8) & 0xFF] && ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]) { ctx->g = ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]; } else #endif { h = ctx->style & SSFN_STYLE_NOAA ? ctx->size : (ctx->size > ctx->f->height ? (ctx->size + 4) & ~3 : ctx->f->height); ci = (ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC); cb = (ctx->style & SSFN_STYLE_BOLD) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_BOLD) ? (ctx->f->height+64)>>6 : 0; w = ctx->rc->w * h / ctx->f->height; p = w + (ci ? h / SSFN_ITALIC_DIV : 0) + cb; /* failsafe, should never happen */ if(p * h >= SSFN_DATA_MAX) return SSFN_ERR_BADSIZE; #ifndef SSFN_MAXLINES if(!(ctx->style & SSFN_STYLE_NOCACHE)) { if(!ctx->c[unicode >> 16]) { ctx->c[unicode >> 16] = (ssfn_glyph_t***)SSFN_realloc(NULL, 256 * sizeof(void*)); if(!ctx->c[unicode >> 16]) return SSFN_ERR_ALLOC; SSFN_memset(ctx->c[unicode >> 16], 0, 256 * sizeof(void*)); } if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF]) { ctx->c[unicode >> 16][(unicode >> 8) & 0xFF] = (ssfn_glyph_t**)SSFN_realloc(NULL, 256 * sizeof(void*)); if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF]) return SSFN_ERR_ALLOC; SSFN_memset(ctx->c[unicode >> 16][(unicode >> 8) & 0xFF], 0, 256 * sizeof(void*)); } ctx->g = ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF] = (ssfn_glyph_t*)SSFN_realloc(NULL, p * h + 8); if(!ctx->c[unicode >> 16][(unicode >> 8) & 0xFF][unicode & 0xFF]) return SSFN_ERR_ALLOC; } else #endif ctx->g = &ctx->ga; x = (ctx->rc->x > 0 && ci ? (ctx->f->height - ctx->f->baseline) * h / SSFN_ITALIC_DIV / ctx->f->height : 0); ctx->g->p = p; ctx->g->h = h; ctx->g->x = ctx->rc->x + x; ctx->g->y = ctx->rc->y; ctx->g->o = (ctx->rc->t & 0x3F) + x; SSFN_memset(&ctx->g->data, 0xFF, p * h); color = 0xFE; ctx->g->a = ctx->g->d = 0; for(n = 0; n < ctx->rc->n; n++) { if(ptr[0] == 255 && ptr[1] == 255) { color = ptr[2]; ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; } x = ((ptr[0] + cb) << SSFN_PREC) * h / ctx->f->height; y = (ptr[1] << SSFN_PREC) * h / ctx->f->height; if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; } else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; } frg = (uint8_t*)ctx->f + m; if(!(frg[0] & 0x80)) { /* contour */ j = (frg[0] & 0x3F); if(frg[0] & 0x40) { j <<= 8; j |= frg[1]; frg++; } j++; frg++; tmp = frg; frg += (j+3)/4; ctx->np = 0; for(i = 0; i < j; i++) { k = (frg[0] << SSFN_PREC) * h / ctx->f->height + x; m = (frg[1] << SSFN_PREC) * h / ctx->f->height + y; switch((tmp[i >> 2] >> ((i & 3) << 1)) & 3) { case SSFN_CONTOUR_MOVE: ctx->mx = ctx->lx = k; ctx->my = ctx->ly = m; frg += 2; break; case SSFN_CONTOUR_LINE: _ssfn_l(ctx, p << SSFN_PREC, h << SSFN_PREC, k, m); frg += 2; break; case SSFN_CONTOUR_QUAD: a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y; _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, ((a-ctx->lx)/2)+ctx->lx, ((A-ctx->ly)/2)+ctx->ly, ((k-a)/2)+a,((A-m)/2)+m, k,m, 0); frg += 4; break; case SSFN_CONTOUR_CUBIC: a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y; b = (frg[4] << SSFN_PREC) * h / ctx->f->height + x; B = (frg[5] << SSFN_PREC) * h / ctx->f->height + y; _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, a,A, b,B, k,m, 0); frg += 6; break; } } /* close path */ if(ctx->mx != ctx->lx || ctx->my != ctx->ly) { ctx->p[ctx->np+0] = ctx->mx; ctx->p[ctx->np+1] = ctx->my; ctx->np += 2; } /* add rasterized vector layers to cached glyph */ if(ctx->np > 4) { for(b = A = B = o = 0; b < h; b++, B += p) { a = b << SSFN_PREC; for(nr = 0, i = 0; i < ctx->np - 3; i += 2) { if( (ctx->p[i+1] < a && ctx->p[i+3] >= a) || (ctx->p[i+3] < a && ctx->p[i+1] >= a)) { if((ctx->p[i+1] >> SSFN_PREC) == (ctx->p[i+3] >> SSFN_PREC)) x = (((int)ctx->p[i]+(int)ctx->p[i+2])>>1); else x = ((int)ctx->p[i]) + ((a - (int)ctx->p[i+1])* ((int)ctx->p[i+2] - (int)ctx->p[i])/ ((int)ctx->p[i+3] - (int)ctx->p[i+1])); x >>= SSFN_PREC; if(ci) x += (h - b) / SSFN_ITALIC_DIV; if(cb && !o) { if(ctx->g->data[B + x] != color) { o = -cb; A = cb; } else { o = cb; A = -cb; } } for(k = 0; k < nr && x > r[k]; k++); for(l = nr; l > k; l--) r[l] = r[l-1]; r[k] = x; nr++; } } if(nr > 1 && nr & 1) { r[nr - 2] = r[nr - 1]; nr--; } if(nr) { if(ctx->g->d < y + b) ctx->g->d = y + b; for(i = 0; i < nr - 1; i += 2) { l = r[i] + o; m = r[i + 1] + A; if(l < 0) l = 0; if(m > p) m = p; if(i > 0 && l < r[i - 1] + A) l = r[i - 1] + A; for(; l < m; l++) ctx->g->data[B + l] = ctx->g->data[B + l] == color ? 0xFF : color; } } } } } else if((frg[0] & 0x60) == 0x00) { /* bitmap */ B = ((frg[0] & 0x1F) + 1) << 3; A = frg[1] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC; b = B * h / ctx->f->height; a = A * h / ctx->f->height; if(ctx->g->d < y + a) ctx->g->d = y + a; frg += 2; for(j = 0; j < a; j++) { k = j * A / a; l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0); for(i = 0; i < b; i++) { m = i * B / b; if(frg[(k * B + m) >> 3] & (1 << (m & 7))) { for(o = 0; o <= cb; o++) ctx->g->data[l + i + o] = color; } } } if(!(ctx->style & SSFN_STYLE_NOAA)) { m = color == 0xFD ? 0xFC : 0xFD; o = y * p + p + x; for(k = h; k > ctx->f->height + 4; k -= 2*ctx->f->height) { for(j = 1, l = o; j < a - 1; j++, l += p) for(i = 1; i < b - 1; i++) { if(ctx->g->data[l + i] == 0xFF && (ctx->g->data[l + i - p] == color || ctx->g->data[l + i + p] == color) && (ctx->g->data[l + i - 1] == color || ctx->g->data[l + i + 1] == color)) ctx->g->data[l + i] = m; } for(j = 1, l = o; j < a - 1; j++, l += p) for(i = 1; i < b - 1; i++) { if(ctx->g->data[l + i] == m) ctx->g->data[l + i] = color; } } } } else if((frg[0] & 0x60) == 0x20) { /* pixmap */ k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; B = frg[2] + 1; A = frg[3] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC; b = B * h / ctx->f->height; a = A * h / ctx->f->height; if(ctx->g->d < y + a) ctx->g->d = y + a; frg += 4; end = frg + k; i = 0; while(frg < end) { l = ((*frg++) & 0x7F) + 1; if(frg[-1] & 0x80) { while(l--) dec[i++] = *frg; frg++; } else while(l--) dec[i++] = *frg++; } for(j = 0; j < a; j++) { k = j * A / a * B; l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0); for(i = 0; i < b; i++) { m = dec[k + i * B / b]; if(m != 0xFF) ctx->g->data[l + i] = m; } } } color = 0xFE; } ctx->g->a = ctx->f->baseline; if(ctx->g->d > ctx->g->a + 1) ctx->g->d -= ctx->g->a + 1; else ctx->g->d = 0; #ifdef SSFN_DEBUGGLYPH printf("\nU+%06X size %d p %d h %d base %d under %d overlap %d ascender %d descender %d advance x %d advance y %d cb %d\n", unicode, ctx->size,p,h,ctx->f->baseline,ctx->f->underline,ctx->g->o,ctx->g->a,ctx->g->d,ctx->g->x,ctx->g->y,cb); for(j = 0; j < h; j++) { printf("%3d: ", j); for(i = 0; i < p; i++) { if(ctx->g->data[j*p+i] == 0xFF) printf(j == ctx->g->a ? "_" : "."); else printf("%x", ctx->g->data[j*p+i] & 0xF); } printf("\n"); } #endif #ifdef SSFN_PROFILING gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } ctx->raster += tvd.tv_sec * 1000000L + tvd.tv_usec; memcpy(&tv0, &tv1, sizeof(struct timeval)); #endif } if(dst) { /* blit glyph from cache into buffer */ h = (ctx->style & SSFN_STYLE_ABS_SIZE) || SSFN_TYPE_FAMILY(ctx->f->type) == SSFN_FAMILY_MONOSPACE || !ctx->f->baseline ? ctx->size : ctx->size * ctx->f->height / ctx->f->baseline; if(h > ctx->line) ctx->line = h; w = ctx->g->p * h / ctx->g->h; s = ctx->g->x * h / ctx->f->height - ctx->g->o * h / ctx->f->height; n = ctx->size > 16 ? 2 : 1; if(w < n) w = n; if(s < n) s = n; if(dst->ptr) { if(ctx->g->x) { ox = (ctx->g->o * h / ctx->f->height) + (ctx->style & SSFN_STYLE_RTL ? w : 0); oy = ctx->g->a * h / ctx->f->height; } else { ox = w / 2; oy = 0; } j = dst->w < 0 ? -dst->w : dst->w; cs = dst->w < 0 ? 16 : 0; cb = (h + 64) >> 6; uix = w > s ? w : s; uax = 0; n = ctx->f->underline * h / ctx->f->height; #ifdef SSFN_DEBUGGLYPH printf("Scaling to w %d h %d (glyph %d %d, cache %d %d, font %d)\n", w,h,ctx->rc->w,ctx->rc->h,ctx->g->p,ctx->g->h,ctx->f->height); #endif fR = (dst->fg >> 16) & 0xFF; fG = (dst->fg >> 8) & 0xFF; fB = (dst->fg >> 0) & 0xFF; fA = (dst->fg >> 24) & 0xFF; bR = (dst->bg >> 16) & 0xFF; bG = (dst->bg >> 8) & 0xFF; bB = (dst->bg >> 0) & 0xFF; Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy) + ((dst->x - ox) << 2)); for (y = 0; y < h && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) { if(dst->y + y - oy < 0) continue; y0 = (y << 8) * ctx->g->h / h; Y0 = y0 >> 8; y1 = ((y + 1) << 8) * ctx->g->h / h; Y1 = y1 >> 8; Ol = Op; for (x = 0; x < w && dst->x + x - ox < j; x++, Ol++) { if(dst->x + x - ox < 0) continue; m = 0; sR = sG = sB = sA = 0; if(!dst->bg) { /* real linear frame buffers should be accessed only as uint32_t on 32 bit boundary */ O = *Ol; bR = (O >> (16 - cs)) & 0xFF; bG = (O >> 8) & 0xFF; bB = (O >> cs) & 0xFF; } x0 = (x << 8) * ctx->g->p / w; X0 = x0 >> 8; x1 = ((x + 1) << 8) * ctx->g->p / w; X1 = x1 >> 8; for(ys = y0; ys < y1; ys += 256) { if(ys >> 8 == Y0) { yp = 256 - (ys & 0xFF); ys &= ~0xFF; if(yp > y1 - y0) yp = y1 - y0; } else if(ys >> 8 == Y1) yp = y1 & 0xFF; else yp = 256; X2 = (ys >> 8) * ctx->g->p; for(xs = x0; xs < x1; xs += 256) { if (xs >> 8 == X0) { k = 256 - (xs & 0xFF); xs &= ~0xFF; if(k > x1 - x0) k = x1 - x0; pc = k == 256 ? yp : (k * yp) >> 8; } else if (xs >> 8 == X1) { k = x1 & 0xFF; pc = k == 256 ? yp : (k * yp) >> 8; } else pc = yp; m += pc; k = ctx->g->data[X2 + (xs >> 8)]; if(k == 0xFF) { sB += bB * pc; sG += bG * pc; sR += bR * pc; } else if(k == 0xFE || !ctx->f->cmap_offs) { af = (256 - fA) * pc; sB += fB * af; sG += fG * af; sR += fR * af; sA += fA * pc; } else { P = *((uint32_t*)((uint8_t*)ctx->f + ctx->f->cmap_offs + (k << 2))); af = (256 - (P >> 24)) * pc; sR += (((P >> 16) & 0xFF) * af); sG += (((P >> 8) & 0xFF) * af); sB += (((P >> 0) & 0xFF) * af); sA += (((P >> 24) & 0xFF) * pc); } } } if(m) { sR /= m; sG /= m; sB /= m; sA /= m; } else { sR >>= 8; sG >>= 8; sB >>= 8; sA >>= 8; } if(sA > 15) { *Ol = ((sA > 255 ? 255 : sA) << 24) | ((sR > 255 ? 255 : sR) << (16 - cs)) | ((sG > 255 ? 255 : sG) << 8) | ((sB > 255 ? 255 : sB) << cs); if(y == n) { if(uix > x) uix = x; if(uax < x) uax = x; } } } } if(ctx->style & SSFN_STYLE_UNDERLINE) { uix -= cb + 1; uax += cb + 2; if(uax < uix) uax = uix + 1; k = (w > s ? w : s); Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2)); for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) { if(dst->y + y - oy < 0) continue; for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) { if(dst->x + x - ox < 0 || (x > uix && x < uax)) continue; O = *Ol; bR = (O >> (16 - cs)) & 0xFF; bG = (O >> 8) & 0xFF; bB = (O >> cs) & 0xFF; bB += ((fB - bB) * fA) >> 8; bG += ((fG - bG) * fA) >> 8; bR += ((fR - bR) * fA) >> 8; *Ol = (fA << 24) | (bR << (16 - cs)) | (bG << 8) | (bB << cs); } } } if(ctx->style & SSFN_STYLE_STHROUGH) { n = (h >> 1); k = (w > s ? w : s) + 1; Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2)); for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) { if(dst->y + y - oy < 0) continue; for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) { if(dst->x + x - ox < 0) continue; O = *Ol; bR = (O >> (16 - cs)) & 0xFF; bG = (O >> 8) & 0xFF; bB = (O >> cs) & 0xFF; bB += ((fB - bB) * fA) >> 8; bG += ((fG - bG) * fA) >> 8; bR += ((fR - bR) * fA) >> 8; *Ol = (fA << 24) | (bR << (16 - cs)) | (bG << 8) | (bB << cs); } } } #ifdef SSFN_PROFILING gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } ctx->blit += tvd.tv_sec * 1000000L + tvd.tv_usec; memcpy(&tv0, &tv1, sizeof(struct timeval)); #endif } /* add advance and kerning */ dst->x += (ctx->style & SSFN_STYLE_RTL ? -s : s); dst->y += ctx->g->y * h / ctx->f->height; ptr = (uint8_t*)str + ret; if(!(ctx->style & SSFN_STYLE_NOKERN) && ctx->f->kerning_offs && _ssfn_c(ctx->f, (const char*)ptr, &i, &P) && P > 32) { ptr = (uint8_t*)ctx->rc + sizeof(ssfn_chr_t); /* check all kerning fragments, because we might have both vertical and horizontal kerning offsets */ for(n = 0; n < ctx->rc->n; n++) { if(ptr[0] == 255 && ptr[1] == 255) { ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; } x = ptr[0]; if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; } else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; } frg = (uint8_t*)ctx->f + m; if((frg[0] & 0xE0) == 0xC0) { k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; frg += 2; /* check if there's a kerning group for the next code point */ while(k--) { m = ((frg[2] & 0xF) << 16) | (frg[1] << 8) | frg[0]; if(P >= (uint32_t)m && P <= (uint32_t)(((frg[5] & 0xF) << 16) | (frg[4] << 8) | frg[3])) { P -= m; m = ctx->f->kerning_offs + ((((frg[2] >> 4) & 0xF) << 24) | (((frg[5] >> 4) & 0xF) << 16) | (frg[7] << 8) | frg[6]); /* decode RLE compressed offsets */ tmp = (uint8_t*)ctx->f + m; while(tmp < (uint8_t*)ctx->f + ctx->f->size - 4) { if((tmp[0] & 0x7F) < P) { P -= (tmp[0] & 0x7F) + 1; tmp += 2 + (tmp[0] & 0x80 ? 0 : tmp[0] & 0x7F); } else { y = (int)((signed char)tmp[1 + ((tmp[0] & 0x80) ? 0 : P)]) * h / ctx->f->height; if(x) dst->x += y; else dst->y += y; break; } } break; } frg += 8; } } /* if kerning fragment */ } #ifdef SSFN_PROFILING gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } ctx->kern += tvd.tv_sec * 1000000L + tvd.tv_usec; #endif } } return ret; } /** * Get the bounding box for a string * @param ctx rendering context * @param str string to measure * @param w returned width * @param h returned height * @param left returned left margin * @param top returned ascender * @return error code */ int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top) { ssfn_buf_t buf; int ret, f = 1, s; if(!ctx || !str || !w || !h || !top || !left) return SSFN_ERR_INVINP; *w = *h = *top = *left = 0; if(!*str) return SSFN_OK; SSFN_memset(&buf, 0, sizeof(ssfn_buf_t)); while((ret = ssfn_render(ctx, &buf, str))) { if(ret < 0 || !ctx->g) return ret; if(f) { f = 0; buf.w = buf.x = ctx->style & SSFN_STYLE_RTL ? ctx->g->p : ctx->g->o; } if(ctx->g->x) { if(ctx->g->a > buf.y) buf.y = ctx->g->a; if(ctx->g->h > buf.h) buf.h = ctx->g->h; buf.w += ctx->g->x; } else { if(buf.w < ctx->g->p) buf.w = ctx->g->p; buf.h += ctx->g->y ? ctx->g->y : ctx->g->h; } str += ret; } if(ctx->g->x) buf.w += ctx->style & SSFN_STYLE_RTL ? ctx->g->o : ctx->g->p; else { buf.x = buf.w / 2; buf.y = 0; } s = (ctx->style & SSFN_STYLE_ABS_SIZE) || SSFN_TYPE_FAMILY(ctx->f->type) == SSFN_FAMILY_MONOSPACE || !ctx->f->baseline ? ctx->size : ctx->size * ctx->f->height / ctx->f->baseline; *w = buf.w * s / ctx->f->height; *h = buf.h * s / ctx->f->height; *left = ctx->style & SSFN_STYLE_RTL ? *w : buf.x * s / ctx->f->height; *top = buf.y * s / ctx->f->height; return SSFN_OK; } /** * Render text to a newly allocated pixel buffer * * @param ctx rendering context * @param str string to measure * @return a newly allocated pixel buffer or NULL */ ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg) { #ifndef SSFN_MAXLINES ssfn_buf_t *buf; int ret; if(!ctx || !str) return NULL; buf = (ssfn_buf_t*)SSFN_realloc(NULL, sizeof(ssfn_buf_t)); if(!buf) return NULL; SSFN_memset(buf, 0, sizeof(ssfn_buf_t)); buf->fg = fg; if(!*str || ssfn_bbox(ctx, str, (int*)&buf->w, (int*)&buf->h, (int*)&buf->x, (int*)&buf->y) != SSFN_OK) return buf; buf->ptr = (uint8_t*)SSFN_realloc(NULL, buf->w * buf->h * sizeof(uint32_t)); SSFN_memset(buf->ptr, 0, buf->w * buf->h * sizeof(uint32_t)); while((ret = ssfn_render(ctx, buf, str)) > 0) str += ret; if(ret != SSFN_OK) { SSFN_free(buf->ptr); SSFN_free(buf); return NULL; } return buf; #else (void)ctx; (void)str; (void)fg; return NULL; #endif } #endif /* SSFN_IMPLEMENTATION */ #if defined(SSFN_CONSOLEBITMAP_PALETTE) || defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR) /*** special console bitmap font renderer (ca. 1.5k, no dependencies, no memory allocation and no error checking) ***/ /** * public variables to configure */ ssfn_font_t *ssfn_src; /* font buffer with an inflated bitmap font */ ssfn_buf_t ssfn_dst; /* destination frame buffer */ /** * Minimal OS kernel console renderer * * @param unicode character * @return error code */ int ssfn_putc(uint32_t unicode) { # ifdef SSFN_CONSOLEBITMAP_PALETTE # define SSFN_PIXEL uint8_t # else # ifdef SSFN_CONSOLEBITMAP_HICOLOR # define SSFN_PIXEL uint16_t # else # define SSFN_PIXEL uint32_t # endif # endif register SSFN_PIXEL *o, *p; register uint8_t *ptr, *chr = NULL, *frg; register int i, j, k, l, m, y = 0, w, s = ssfn_dst.p / sizeof(SSFN_PIXEL); if(!ssfn_src || ssfn_src->magic[0] != 'S' || ssfn_src->magic[1] != 'F' || ssfn_src->magic[2] != 'N' || ssfn_src->magic[3] != '2' || !ssfn_dst.ptr || !ssfn_dst.p) return SSFN_ERR_INVINP; w = ssfn_dst.w < 0 ? -ssfn_dst.w : ssfn_dst.w; for(ptr = (uint8_t*)ssfn_src + ssfn_src->characters_offs, i = 0; i < 0x110000; i++) { if(ptr[0] == 0xFF) { i += 65535; ptr++; } else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; } else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; } else { if((uint32_t)i == unicode) { chr = ptr; break; } ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); } } if(!chr) return SSFN_ERR_NOGLYPH; ptr = chr + 6; o = (SSFN_PIXEL*)((uint8_t*)ssfn_dst.ptr + ssfn_dst.y * ssfn_dst.p + ssfn_dst.x * sizeof(SSFN_PIXEL)); for(i = 0; i < chr[1]; i++, ptr += chr[0] & 0x40 ? 6 : 5) { if(ptr[0] == 255 && ptr[1] == 255) continue; frg = (uint8_t*)ssfn_src + (chr[0] & 0x40 ? ((ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]) : ((ptr[4] << 16) | (ptr[3] << 8) | ptr[2])); if((frg[0] & 0xE0) != 0x80) continue; if(ssfn_dst.bg) { for(; y < ptr[1] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) { for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++) *p = ssfn_dst.bg; } } else { o += (int)(ptr[1] - y) * s; y = ptr[1]; } k = ((frg[0] & 0x1F) + 1) << 3; j = frg[1] + 1; frg += 2; for(m = 1; j && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); j--, y++, o += s) for(p = o, l = 0; l < k; l++, p++, m <<= 1) { if(m > 0x80) { frg++; m = 1; } if(ssfn_dst.x + l >= 0 && (!w || ssfn_dst.x + l < w)) { if(*frg & m) { *p = ssfn_dst.fg; } else if(ssfn_dst.bg) { *p = ssfn_dst.bg; } } } } if(ssfn_dst.bg) for(; y < chr[3] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) { for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++) *p = ssfn_dst.bg; } ssfn_dst.x += chr[4]; ssfn_dst.y += chr[5]; return SSFN_OK; } #endif /* SSFN_CONSOLEBITMAP */ #ifdef __cplusplus } /*** SSFN C++ Wrapper Class ***/ #include namespace SSFN { #ifndef SSFN_IMPLEMENTATION class Font { public: Font(); ~Font(); public: int Load(const std::string &data); int Load(const unsigned char *data, int len); int Select(int family, const std::string &name, int style, int size); int Select(int family, const char *name, int style, int size); int Render(ssfn_buf_t *dst, const std::string &str); int Render(ssfn_buf_t *dst, const char *str); int BBox(const std::string &str, int *w, int *h, int *left, int *top); int BBox(const char *str, int *w, int *h, int *left, int *top); ssfn_buf_t *Text(const std::string &str, unsigned int fg); ssfn_buf_t *Text(const char *str, unsigned int fg); int LineHeight(); int Mem(); const std::string ErrorStr(int err); }; #else class Font { private: ssfn_t ctx; public: Font() { SSFN_memset(&this->ctx, 0, sizeof(ssfn_t)); } ~Font() { ssfn_free(&this->ctx); } public: int Load(const std::string &data) { return ssfn_load(&this->ctx,(const void*)data.data()); } int Load(const unsigned char *data) { return ssfn_load(&this->ctx, (const void*)data); } int Select(int family, const std::string &name, int style, int size) { return ssfn_select(&this->ctx, family, (char*)name.data(), style, size); } int Select(int family, char *name, int style, int size) { return ssfn_select(&this->ctx,family,name,style,size); } int Render(ssfn_buf_t *dst, const std::string &str) { return ssfn_render(&this->ctx,dst,(const char*)str.data()); } int Render(ssfn_buf_t *dst, const char *str) { return ssfn_render(&this->ctx, dst, str); } int BBox(const std::string &str, int *w, int *h, int *left, int *top) { return ssfn_bbox(&this->ctx, (const char *)str.data(), w, h, left, top); } int BBox(const char *str, int *w, int *h, int *left, int *top) { return ssfn_bbox(&this->ctx,str,w,h,left,top); } ssfn_buf_t *Text(const std::string &str, unsigned int fg) { return ssfn_text(&this->ctx,(const char*)str.data(), fg); } ssfn_buf_t *Text(const char *str, unsigned int fg) { return ssfn_text(&this->ctx, str, fg); } int LineHeight() { return this->ctx->line; } int Mem() { return ssfn_mem(&this->ctx); } const std::string ErrorStr(int err) { return std::string(ssfn_error(err)); } }; #endif } #endif #endif /* _SSFN_H_ */ tboot-1.10.5/tboot/include/vga/u_vga16.bdf0000644000000000000000000136270714210363175016351 0ustar 00000000000000STARTFONT 2.1 FONT -Bolkhov-VGA-Medium-R-Normal--16-160-75-75-C-80-iso10646-1 SIZE 16 75 75 FONTBOUNDINGBOX 8 16 0 -4 STARTPROPERTIES 24 FOUNDRY "Bolkhov" FAMILY_NAME "VGA" WEIGHT_NAME "Medium" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "" PIXEL_SIZE 16 POINT_SIZE 160 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 80 CHARSET_REGISTRY "iso10646" CHARSET_ENCODING "1" CAP_HEIGHT 10 X_HEIGHT 7 FONT_ASCENT 12 FONT_DESCENT 4 FACE_NAME "Vga Unicode" COPYRIGHT "Copyright (c) 2000 Dmitry Bolkhovityanov, bolkhov@inp.nsk.su" HOMEPAGE "http://www.inp.nsk.su/~bolkhov/files/fonts/univga/" NOTICE "VGA is a trademark of IBM Corporation." DEFAULT_CHAR 0 _XMBDFED_INFO "Edited with xmbdfed 4.4." ENDPROPERTIES CHARS 2899 STARTCHAR char0 ENCODING 0 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DA 02 80 82 02 80 82 02 80 B6 00 00 00 00 ENDCHAR STARTCHAR space ENCODING 32 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR exclam ENCODING 33 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 3C 3C 18 18 18 00 18 18 00 00 00 00 ENDCHAR STARTCHAR quotedbl ENCODING 34 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 66 66 66 24 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR numbersign ENCODING 35 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 6C 6C FE 6C 6C 6C FE 6C 6C 00 00 00 00 ENDCHAR STARTCHAR dollar ENCODING 36 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 7C C6 C2 C0 7C 06 06 86 C6 7C 18 18 00 00 ENDCHAR STARTCHAR percent ENCODING 37 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C2 C6 0C 18 30 60 C6 86 00 00 00 00 ENDCHAR STARTCHAR ampersand ENCODING 38 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 6C 38 76 DC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR quotesingle ENCODING 39 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 30 30 20 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR parenleft ENCODING 40 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 30 30 30 30 30 30 18 0C 00 00 00 00 ENDCHAR STARTCHAR parenright ENCODING 41 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 18 0C 0C 0C 0C 0C 0C 18 30 00 00 00 00 ENDCHAR STARTCHAR asterisk ENCODING 42 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 3C FF 3C 66 00 00 00 00 00 00 ENDCHAR STARTCHAR plus ENCODING 43 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 18 7E 18 18 00 00 00 00 00 00 ENDCHAR STARTCHAR comma ENCODING 44 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 18 18 18 30 00 00 00 ENDCHAR STARTCHAR hyphen ENCODING 45 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FE 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR period ENCODING 46 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR slash ENCODING 47 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 02 06 0C 18 30 60 C0 80 00 00 00 00 ENDCHAR STARTCHAR zero ENCODING 48 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C C6 C6 D6 D6 C6 C6 6C 38 00 00 00 00 ENDCHAR STARTCHAR one ENCODING 49 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 38 78 18 18 18 18 18 18 7E 00 00 00 00 ENDCHAR STARTCHAR two ENCODING 50 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 06 0C 18 30 60 C0 C6 FE 00 00 00 00 ENDCHAR STARTCHAR three ENCODING 51 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 06 06 3C 06 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR four ENCODING 52 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 1C 3C 6C CC FE 0C 0C 0C 1E 00 00 00 00 ENDCHAR STARTCHAR five ENCODING 53 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C0 C0 C0 FC 06 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR six ENCODING 54 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 60 C0 C0 FC C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR seven ENCODING 55 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 06 06 0C 18 30 30 30 30 00 00 00 00 ENDCHAR STARTCHAR eight ENCODING 56 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 7C C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR nine ENCODING 57 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 7E 06 06 06 0C 78 00 00 00 00 ENDCHAR STARTCHAR colon ENCODING 58 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 00 00 00 18 18 00 00 00 00 00 ENDCHAR STARTCHAR semicolon ENCODING 59 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 00 00 00 18 18 30 00 00 00 00 ENDCHAR STARTCHAR less ENCODING 60 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 06 0C 18 30 60 30 18 0C 06 00 00 00 00 ENDCHAR STARTCHAR equal ENCODING 61 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E 00 00 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR greater ENCODING 62 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 60 30 18 0C 06 0C 18 30 60 00 00 00 00 ENDCHAR STARTCHAR question ENCODING 63 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 0C 18 18 18 00 18 18 00 00 00 00 ENDCHAR STARTCHAR at ENCODING 64 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C C6 C6 DE DE DE DC C0 7C 00 00 00 00 ENDCHAR STARTCHAR A ENCODING 65 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 6C C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR B ENCODING 66 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR C ENCODING 67 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR D ENCODING 68 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 66 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR E ENCODING 69 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR F ENCODING 70 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR G ENCODING 71 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR H ENCODING 72 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR I ENCODING 73 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR J ENCODING 74 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 0C 0C 0C 0C 0C CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR K ENCODING 75 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR L ENCODING 76 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 60 60 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR M ENCODING 77 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 EE FE FE D6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR N ENCODING 78 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR O ENCODING 79 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR P ENCODING 80 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR Q ENCODING 81 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 C6 D6 DE 7C 0C 0E 00 00 ENDCHAR STARTCHAR R ENCODING 82 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 6C 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR S ENCODING 83 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 60 38 0C 06 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR T ENCODING 84 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR U ENCODING 85 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR V ENCODING 86 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 6C 38 10 00 00 00 00 ENDCHAR STARTCHAR W ENCODING 87 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 D6 D6 D6 FE EE 6C 00 00 00 00 ENDCHAR STARTCHAR X ENCODING 88 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 6C 7C 38 38 7C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR Y ENCODING 89 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Z ENCODING 90 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 86 0C 18 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR bracketleft ENCODING 91 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 30 30 30 30 30 30 30 30 3C 00 00 00 00 ENDCHAR STARTCHAR backslash ENCODING 92 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 80 C0 E0 70 38 1C 0E 06 02 00 00 00 00 ENDCHAR STARTCHAR bracketright ENCODING 93 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 0C 0C 0C 0C 0C 0C 0C 0C 3C 00 00 00 00 ENDCHAR STARTCHAR asciicircum ENCODING 94 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 6C C6 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR underscore ENCODING 95 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 ENDCHAR STARTCHAR grave ENCODING 96 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 18 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR a ENCODING 97 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR b ENCODING 98 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 78 6C 66 66 66 66 7C 00 00 00 00 ENDCHAR STARTCHAR c ENCODING 99 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR d ENCODING 100 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR e ENCODING 101 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR f ENCODING 102 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 64 60 F0 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR g ENCODING 103 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR h ENCODING 104 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR i ENCODING 105 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR j ENCODING 106 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 06 00 0E 06 06 06 06 06 06 66 66 3C 00 ENDCHAR STARTCHAR k ENCODING 107 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 66 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR l ENCODING 108 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR m ENCODING 109 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 EC FE D6 D6 D6 D6 C6 00 00 00 00 ENDCHAR STARTCHAR n ENCODING 110 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR o ENCODING 111 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR p ENCODING 112 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 7C 60 60 F0 00 ENDCHAR STARTCHAR q ENCODING 113 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 CC CC CC CC CC 7C 0C 0C 1E 00 ENDCHAR STARTCHAR r ENCODING 114 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR s ENCODING 115 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR t ENCODING 116 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR u ENCODING 117 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR v ENCODING 118 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 66 66 3C 18 00 00 00 00 ENDCHAR STARTCHAR w ENCODING 119 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR x ENCODING 120 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 6C 38 38 38 6C C6 00 00 00 00 ENDCHAR STARTCHAR y ENCODING 121 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR z ENCODING 122 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 30 60 C6 FE 00 00 00 00 ENDCHAR STARTCHAR braceleft ENCODING 123 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 18 18 18 70 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR bar ENCODING 124 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 00 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR braceright ENCODING 125 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 18 18 18 0E 18 18 18 18 70 00 00 00 00 ENDCHAR STARTCHAR asciitilde ENCODING 126 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR char127 ENCODING 127 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 38 6C C6 C6 C6 FE 00 00 00 00 00 ENDCHAR STARTCHAR space ENCODING 160 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR exclamdown ENCODING 161 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 18 18 18 3C 3C 3C 18 00 00 00 00 ENDCHAR STARTCHAR cent ENCODING 162 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 3C 66 60 60 60 66 3C 18 18 00 00 00 00 ENDCHAR STARTCHAR sterling ENCODING 163 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 64 60 F0 60 60 60 60 E6 FC 00 00 00 00 ENDCHAR STARTCHAR currency ENCODING 164 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 66 3C 66 66 66 3C 66 00 00 00 00 00 ENDCHAR STARTCHAR yen ENCODING 165 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 3C 18 7E 18 7E 18 18 18 00 00 00 00 ENDCHAR STARTCHAR brokenbar ENCODING 166 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 00 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR section ENCODING 167 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C C6 60 38 6C C6 C6 6C 38 0C C6 7C 00 00 00 ENDCHAR STARTCHAR dieresis ENCODING 168 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR copyright ENCODING 169 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 99 A5 A1 A1 A5 99 42 3C 00 00 00 00 ENDCHAR STARTCHAR ordfeminine ENCODING 170 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 3C 6C 6C 3E 00 7E 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR guillemotleft ENCODING 171 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 36 6C D8 6C 36 00 00 00 00 00 00 ENDCHAR STARTCHAR logicalnot ENCODING 172 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FE 06 06 06 06 00 00 00 00 00 ENDCHAR STARTCHAR hyphen ENCODING 173 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 3C 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR registered ENCODING 174 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 44 BA B2 AA 44 38 00 00 00 00 00 00 00 ENDCHAR STARTCHAR macron ENCODING 175 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR degree ENCODING 176 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 6C 38 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR plusminus ENCODING 177 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 7E 18 18 00 7E 00 00 00 00 00 ENDCHAR STARTCHAR twosuperior ENCODING 178 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D8 30 60 C8 F8 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR threesuperior ENCODING 179 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D8 30 18 D8 70 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR acute ENCODING 180 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR mu ENCODING 181 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC F6 C0 C0 C0 00 ENDCHAR STARTCHAR paragraph ENCODING 182 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7F DB DB DB 7B 1B 1B 1B 1B 1B 00 00 00 00 ENDCHAR STARTCHAR periodcentered ENCODING 183 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR cedilla ENCODING 184 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 0C 38 00 ENDCHAR STARTCHAR onesuperior ENCODING 185 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 70 30 30 30 78 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR ordmasculine ENCODING 186 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 6C 38 00 7C 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR guillemotright ENCODING 187 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D8 6C 36 6C D8 00 00 00 00 00 00 ENDCHAR STARTCHAR onequarter ENCODING 188 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 66 CE 9E 3E 06 06 00 00 ENDCHAR STARTCHAR onehalf ENCODING 189 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 60 DC 86 0C 18 3E 00 00 ENDCHAR STARTCHAR threequarters ENCODING 190 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 30 62 36 EC 18 30 66 CE 9E 3E 06 06 00 00 ENDCHAR STARTCHAR questiondown ENCODING 191 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 30 30 60 C0 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Agrave ENCODING 192 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Aacute ENCODING 193 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Acircumflex ENCODING 194 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 6C 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Atilde ENCODING 195 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Adieresis ENCODING 196 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Aring ENCODING 197 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 38 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR AE ENCODING 198 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 6C CC CC FE CC CC CC CC CE 00 00 00 00 ENDCHAR STARTCHAR Ccedilla ENCODING 199 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 C2 66 3C 18 0C 38 00 ENDCHAR STARTCHAR Egrave ENCODING 200 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 18 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR Eacute ENCODING 201 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR Ecircumflex ENCODING 202 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR Edieresis ENCODING 203 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR Igrave ENCODING 204 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 18 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Iacute ENCODING 205 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Icircumflex ENCODING 206 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 3C 42 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Idieresis ENCODING 207 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 66 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Eth ENCODING 208 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 F6 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR Ntilde ENCODING 209 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 C6 E6 F6 FE DE CE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Ograve ENCODING 210 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Oacute ENCODING 211 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ocircumflex ENCODING 212 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Otilde ENCODING 213 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Odieresis ENCODING 214 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR multiply ENCODING 215 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 3C 18 3C 66 00 00 00 00 00 00 ENDCHAR STARTCHAR Oslash ENCODING 216 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7A C4 CE CE D6 D6 E6 E6 46 BC 00 00 00 00 ENDCHAR STARTCHAR Ugrave ENCODING 217 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Uacute ENCODING 218 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ucircumflex ENCODING 219 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Udieresis ENCODING 220 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Yacute ENCODING 221 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Thorn ENCODING 222 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 7C 66 66 66 66 7C 60 F0 00 00 00 00 ENDCHAR STARTCHAR germandbls ENCODING 223 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 6C 66 66 66 66 EC 00 00 00 00 ENDCHAR STARTCHAR agrave ENCODING 224 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR aacute ENCODING 225 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 30 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR acircumflex ENCODING 226 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR atilde ENCODING 227 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR adieresis ENCODING 228 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR aring ENCODING 229 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR ae ENCODING 230 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC 76 36 7E D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR ccedilla ENCODING 231 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C6 7C 18 0C 38 00 ENDCHAR STARTCHAR egrave ENCODING 232 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR eacute ENCODING 233 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR ecircumflex ENCODING 234 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR edieresis ENCODING 235 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR igrave ENCODING 236 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 18 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR iacute ENCODING 237 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR icircumflex ENCODING 238 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR idieresis ENCODING 239 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR eth ENCODING 240 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 1C 3C 06 7E C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR ntilde ENCODING 241 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR ograve ENCODING 242 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR oacute ENCODING 243 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR ocircumflex ENCODING 244 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR otilde ENCODING 245 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR odieresis ENCODING 246 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR divide ENCODING 247 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 00 7E 00 18 18 00 00 00 00 00 ENDCHAR STARTCHAR oslash ENCODING 248 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7A C4 CE D6 E6 46 BC 00 00 00 00 ENDCHAR STARTCHAR ugrave ENCODING 249 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uacute ENCODING 250 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 30 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR ucircumflex ENCODING 251 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR udieresis ENCODING 252 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR yacute ENCODING 253 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR thorn ENCODING 254 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 7C 66 66 66 66 66 7C 60 60 F0 00 ENDCHAR STARTCHAR ydieresis ENCODING 255 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR Amacron ENCODING 256 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR amacron ENCODING 257 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Abreve ENCODING 258 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR abreve ENCODING 259 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Aogonek ENCODING 260 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 6C C6 C6 FE C6 C6 C6 C6 0C 18 0E 00 ENDCHAR STARTCHAR aogonek ENCODING 261 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 0C 7C CC CC CC 76 0C 18 0E 00 ENDCHAR STARTCHAR Cacute ENCODING 262 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 3C 66 C2 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR cacute ENCODING 263 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ccircumflex ENCODING 264 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 3C 66 C2 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR ccircumflex ENCODING 265 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Cdotaccent ENCODING 266 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 3C 66 C2 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR cdotaccent ENCODING 267 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ccaron ENCODING 268 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 3C 66 C2 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR ccaron ENCODING 269 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Dcaron ENCODING 270 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 F8 6C 66 66 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR dcaron ENCODING 271 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 0C 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Dcroat ENCODING 272 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 F6 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR dcroat ENCODING 273 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 3E 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Emacron ENCODING 274 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR emacron ENCODING 275 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ebreve ENCODING 276 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR ebreve ENCODING 277 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Edotaccent ENCODING 278 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR edotaccent ENCODING 279 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Eogonek ENCODING 280 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 66 62 68 78 68 62 66 FE 18 30 1C 00 ENDCHAR STARTCHAR eogonek ENCODING 281 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 30 60 38 00 ENDCHAR STARTCHAR Ecaron ENCODING 282 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR ecaron ENCODING 283 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Gcircumflex ENCODING 284 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 3C 66 C2 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR gcircumflex ENCODING 285 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR Gbreve ENCODING 286 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 3C 66 C2 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR gbreve ENCODING 287 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR Gdotaccent ENCODING 288 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 3C 66 C2 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR gdotaccent ENCODING 289 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR Gcommaaccent ENCODING 290 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 DE C6 C6 66 3A 00 18 18 30 ENDCHAR STARTCHAR gcommaaccent ENCODING 291 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 30 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR Hcircumflex ENCODING 292 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 00 C6 C6 C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR hcircumflex ENCODING 293 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 E0 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR Hbar ENCODING 294 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 FF 66 66 7E 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR hbar ENCODING 295 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 F8 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR Itilde ENCODING 296 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR itilde ENCODING 297 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Imacron ENCODING 298 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7E 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR imacron ENCODING 299 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7E 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Ibreve ENCODING 300 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 3C 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR ibreve ENCODING 301 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 3C 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Iogonek ENCODING 302 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 3C 18 18 18 18 18 18 18 3C 18 30 1C 00 ENDCHAR STARTCHAR iogonek ENCODING 303 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 38 18 18 18 18 18 3C 18 30 1C 00 ENDCHAR STARTCHAR Idotaccent ENCODING 304 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR dotlessi ENCODING 305 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR IJ ENCODING 306 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F7 63 63 63 63 63 63 7B 7B EE 00 00 00 00 ENDCHAR STARTCHAR ij ENCODING 307 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 00 EE 66 66 66 66 66 F6 06 66 3C 00 ENDCHAR STARTCHAR Jcircumflex ENCODING 308 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 1C 22 1E 0C 0C 0C 0C CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR jcircumflex ENCODING 309 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 04 0E 1B 00 0E 06 06 06 06 06 06 66 66 3C 00 ENDCHAR STARTCHAR Kcommaaccent ENCODING 310 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 18 18 30 ENDCHAR STARTCHAR kcommaaccent ENCODING 311 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 66 6C 78 78 6C 66 E6 00 18 18 30 ENDCHAR STARTCHAR kgreenlandic ENCODING 312 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 E6 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR Lacute ENCODING 313 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 30 00 F0 60 60 60 60 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR lacute ENCODING 314 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 38 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Lcommaaccent ENCODING 315 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 60 60 60 62 66 FE 00 18 18 30 ENDCHAR STARTCHAR lcommaaccent ENCODING 316 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 3C 00 18 18 30 ENDCHAR STARTCHAR Lcaron ENCODING 317 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 F0 60 60 60 60 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR lcaron ENCODING 318 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 38 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Ldot ENCODING 319 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 66 66 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR ldot ENCODING 320 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 30 30 30 36 36 30 30 30 78 00 00 00 00 ENDCHAR STARTCHAR Lslash ENCODING 321 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 78 E0 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR lslash ENCODING 322 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 1E 78 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Nacute ENCODING 323 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 C6 E6 F6 FE DE CE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR nacute ENCODING 324 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR Ncommaaccent ENCODING 325 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 00 18 18 30 ENDCHAR STARTCHAR ncommaaccent ENCODING 326 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 00 18 18 30 ENDCHAR STARTCHAR Ncaron ENCODING 327 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 C6 E6 F6 FE DE CE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR ncaron ENCODING 328 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR napostrophe ENCODING 329 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 60 C0 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR Eng ENCODING 330 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 06 06 1C 00 ENDCHAR STARTCHAR eng ENCODING 331 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 06 06 1C 00 ENDCHAR STARTCHAR Omacron ENCODING 332 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR omacron ENCODING 333 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Obreve ENCODING 334 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR obreve ENCODING 335 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ohungarumlaut ENCODING 336 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 CC 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR ohungarumlaut ENCODING 337 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 CC 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR OE ENCODING 338 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6E D8 D8 D8 DE D8 D8 D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR oe ENCODING 339 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C D6 D6 DE D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR Racute ENCODING 340 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 FC 66 66 66 7C 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR racute ENCODING 341 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 DC 76 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR Rcommaaccent ENCODING 342 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 6C 66 66 66 E6 00 18 18 30 ENDCHAR STARTCHAR rcommaaccent ENCODING 343 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 66 60 60 60 F0 00 18 18 30 ENDCHAR STARTCHAR Rcaron ENCODING 344 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 FC 66 66 66 7C 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR rcaron ENCODING 345 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 DC 76 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR Sacute ENCODING 346 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 7C C6 C6 60 38 0C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR sacute ENCODING 347 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR Scircumflex ENCODING 348 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 7C C6 C6 60 38 0C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR scircumflex ENCODING 349 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR Scedilla ENCODING 350 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C C6 C6 60 38 0C C6 C6 7C 18 0C 38 00 ENDCHAR STARTCHAR scedilla ENCODING 351 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 60 38 0C C6 7C 18 0C 38 00 ENDCHAR STARTCHAR Scaron ENCODING 352 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 7C C6 C6 60 38 0C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR scaron ENCODING 353 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR Tcommaaccent ENCODING 354 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 18 0C 38 00 ENDCHAR STARTCHAR tcommaaccent ENCODING 355 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 18 0C 38 00 ENDCHAR STARTCHAR Tcaron ENCODING 356 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 7E 7E 5A 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR tcaron ENCODING 357 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 10 30 FC 30 30 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR Tbar ENCODING 358 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 3C 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR tbar ENCODING 359 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 FC 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR Utilde ENCODING 360 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR utilde ENCODING 361 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Umacron ENCODING 362 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR umacron ENCODING 363 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 78 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Ubreve ENCODING 364 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR ubreve ENCODING 365 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 78 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Uring ENCODING 366 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 38 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uring ENCODING 367 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 38 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Uhungarumlaut ENCODING 368 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 CC 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uhungarumlaut ENCODING 369 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Uogonek ENCODING 370 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uogonek ENCODING 371 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC 76 30 60 38 00 ENDCHAR STARTCHAR Wcircumflex ENCODING 372 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 C6 C6 C6 D6 D6 D6 FE EE 6C 00 00 00 00 ENDCHAR STARTCHAR wcircumflex ENCODING 373 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR Ycircumflex ENCODING 374 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR ycircumflex ENCODING 375 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR Ydieresis ENCODING 376 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 66 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Zacute ENCODING 377 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 FE C6 8C 18 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR zacute ENCODING 378 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 FE CC 18 30 60 C6 FE 00 00 00 00 ENDCHAR STARTCHAR Zdotaccent ENCODING 379 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 FE C6 8C 18 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR zdotaccent ENCODING 380 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 FE CC 18 30 60 C6 FE 00 00 00 00 ENDCHAR STARTCHAR Zcaron ENCODING 381 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 FE C6 8C 18 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR zcaron ENCODING 382 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 FE CC 18 30 60 C6 FE 00 00 00 00 ENDCHAR STARTCHAR longs ENCODING 383 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 64 60 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni0180 ENCODING 384 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 F8 60 78 6C 66 66 66 66 7C 00 00 00 00 ENDCHAR STARTCHAR uni0181 ENCODING 385 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E B3 B3 33 3E 33 33 33 33 7E 00 00 00 00 ENDCHAR STARTCHAR uni0182 ENCODING 386 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 64 60 60 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni0183 ENCODING 387 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 62 60 78 6C 66 66 66 66 7C 00 00 00 00 ENDCHAR STARTCHAR uni0184 ENCODING 388 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C E6 E6 66 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni0185 ENCODING 389 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 E0 E0 78 6C 66 66 66 66 7C 00 00 00 00 ENDCHAR STARTCHAR uni0186 ENCODING 390 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC 86 06 06 06 06 86 CC 78 00 00 00 00 ENDCHAR STARTCHAR uni0187 ENCODING 391 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 03 3E 66 C2 C0 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0188 ENCODING 392 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 03 7E C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0189 ENCODING 393 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 F6 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR uni018A ENCODING 394 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C B6 B3 33 33 33 33 33 36 7C 00 00 00 00 ENDCHAR STARTCHAR uni018B ENCODING 395 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 4C 0C 0C 7C CC CC CC CC 7E 00 00 00 00 ENDCHAR STARTCHAR uni018C ENCODING 396 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C 4C 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni018D ENCODING 397 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 7C 30 18 CC 78 00 ENDCHAR STARTCHAR uni018E ENCODING 398 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE CC 8C 2C 3C 2C 0C 8C CC FE 00 00 00 00 ENDCHAR STARTCHAR uni018F ENCODING 399 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 06 06 06 FE C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0190 ENCODING 400 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C2 C0 78 C0 C0 C2 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0191 ENCODING 401 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 60 60 60 60 60 C0 00 ENDCHAR STARTCHAR florin ENCODING 402 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 36 32 30 78 30 30 30 30 30 30 30 E0 00 ENDCHAR STARTCHAR uni0193 ENCODING 403 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 03 3E 66 C2 C0 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR uni0194 ENCODING 404 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 6C 6C 6C 38 38 10 38 6C 38 00 00 ENDCHAR STARTCHAR uni0195 ENCODING 405 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 F3 DB DB DB DB DB CE 00 00 00 00 ENDCHAR STARTCHAR uni0196 ENCODING 406 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 30 30 30 30 30 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR uni0197 ENCODING 407 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni0198 ENCODING 408 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 6D 6C 78 70 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni0199 ENCODING 409 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 60 66 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni019A ENCODING 410 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni019B ENCODING 411 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C8 38 70 D0 38 38 6C 64 C6 C2 00 00 00 00 ENDCHAR STARTCHAR uni019C ENCODING 412 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D6 D6 D6 D6 D6 D6 D6 D6 FE EC 00 00 00 00 ENDCHAR STARTCHAR uni019D ENCODING 413 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 76 7E 7E 6E 66 66 66 66 60 60 C0 00 ENDCHAR STARTCHAR uni019E ENCODING 414 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 06 06 06 00 ENDCHAR STARTCHAR uni019F ENCODING 415 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 FE C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Ohorn ENCODING 416 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 03 7A CC CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR ohorn ENCODING 417 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 06 78 CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni01A2 ENCODING 418 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 73 DF DB DB DB DB DB DB DB 73 03 03 03 00 ENDCHAR STARTCHAR uni01A3 ENCODING 419 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 73 DF DB DB DB DB 73 03 03 03 00 ENDCHAR STARTCHAR uni01A4 ENCODING 420 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E B3 B3 33 3E 30 30 30 30 78 00 00 00 00 ENDCHAR STARTCHAR uni01A5 ENCODING 421 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 60 7C 66 66 66 66 66 7C 60 60 F0 00 ENDCHAR STARTCHAR uni01A6 ENCODING 422 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 7C 66 66 7C 78 6C 6C E6 06 00 00 00 ENDCHAR STARTCHAR uni01A7 ENCODING 423 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 0C 38 60 C0 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01A8 ENCODING 424 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 0C 38 60 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01A9 ENCODING 425 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 62 30 18 18 30 62 C6 FE 00 00 00 00 ENDCHAR STARTCHAR uni01AA ENCODING 426 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D8 78 18 18 18 18 18 18 18 18 1B 0E 00 ENDCHAR STARTCHAR uni01AB ENCODING 427 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 0C 6C 38 00 ENDCHAR STARTCHAR uni01AC ENCODING 428 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E FE 9A 58 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni01AD ENCODING 429 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 36 30 FC 30 30 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR uni01AE ENCODING 430 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 18 18 18 0E 00 ENDCHAR STARTCHAR Uhorn ENCODING 431 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 03 CE CC CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uhorn ENCODING 432 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 06 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01B1 ENCODING 433 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 EE 6C 6C 6C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01B2 ENCODING 434 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC C6 C6 C6 C6 C6 C6 C6 CC 78 00 00 00 00 ENDCHAR STARTCHAR uni01B3 ENCODING 435 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 63 B3 B3 33 1E 0C 0C 0C 0C 1E 00 00 00 00 ENDCHAR STARTCHAR uni01B4 ENCODING 436 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 06 0D CC CC CC CC CC CC 7C 0C 18 F0 00 ENDCHAR STARTCHAR uni01B5 ENCODING 437 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 86 0C 7E 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR uni01B6 ENCODING 438 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 FC 60 C6 FE 00 00 00 00 ENDCHAR STARTCHAR uni01B7 ENCODING 439 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 06 0C 18 30 7C 06 06 06 06 C6 7C 00 00 ENDCHAR STARTCHAR uni01B8 ENCODING 440 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C0 60 30 18 7C C0 C0 C0 C0 C6 7C 00 00 ENDCHAR STARTCHAR uni01B9 ENCODING 441 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE C0 60 30 78 C0 C0 C0 C6 7C 00 ENDCHAR STARTCHAR uni01BA ENCODING 442 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 06 0C 18 3C 06 7C C0 C6 7C 00 ENDCHAR STARTCHAR uni01BB ENCODING 443 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 06 0C 7E 30 60 C0 C6 FE 00 00 00 00 ENDCHAR STARTCHAR uni01BC ENCODING 444 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 60 60 78 0C 06 06 06 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni01BD ENCODING 445 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 60 78 0C 06 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni01BE ENCODING 446 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 18 4C 6C 38 00 00 00 00 ENDCHAR STARTCHAR uni01BF ENCODING 447 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 6C 78 70 60 60 F0 00 ENDCHAR STARTCHAR uni01C0 ENCODING 448 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni01C1 ENCODING 449 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 6C 6C 6C 6C 6C 6C 6C 6C 00 00 00 00 ENDCHAR STARTCHAR uni01C2 ENCODING 450 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 7E 18 7E 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni01C3 ENCODING 451 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 3C 3C 18 18 18 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni01C4 ENCODING 452 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1B 0E 04 F7 D9 D9 DA DA DA DC DC F7 00 00 00 00 ENDCHAR STARTCHAR uni01C5 ENCODING 453 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F5 DA D8 DF D9 DA DA DA DC F7 00 00 00 00 ENDCHAR STARTCHAR uni01C6 ENCODING 454 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3D 1A 18 7F D9 DA DA DA DC 6F 00 00 00 00 ENDCHAR STARTCHAR uni01C7 ENCODING 455 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C7 C3 C3 C3 C3 C3 C3 C3 CB F6 00 00 00 00 ENDCHAR STARTCHAR uni01C8 ENCODING 456 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F3 63 60 67 63 63 63 67 6F FF 03 1B 0E 00 ENDCHAR STARTCHAR uni01C9 ENCODING 457 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E3 63 60 67 63 63 63 63 63 F3 03 33 1E 00 ENDCHAR STARTCHAR uni01CA ENCODING 458 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB FB FB FB DB DB DB DB DE 00 00 00 00 ENDCHAR STARTCHAR uni01CB ENCODING 459 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB F8 FF FB FB DB DB DB DB 03 33 1E 00 ENDCHAR STARTCHAR uni01CC ENCODING 460 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 00 B7 DB DB DB DB DB DB 03 33 1E 00 ENDCHAR STARTCHAR uni01CD ENCODING 461 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni01CE ENCODING 462 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01CF ENCODING 463 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni01D0 ENCODING 464 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni01D1 ENCODING 465 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01D2 ENCODING 466 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01D3 ENCODING 467 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01D4 ENCODING 468 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01D5 ENCODING 469 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 00 6C 00 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01D6 ENCODING 470 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 78 00 CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01D7 ENCODING 471 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 10 6C 00 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01D8 ENCODING 472 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 30 00 CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01D9 ENCODING 473 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 28 10 6C 00 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01DA ENCODING 474 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 78 30 00 CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01DB ENCODING 475 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 10 6C 00 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01DC ENCODING 476 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01DD ENCODING 477 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 06 FE C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni01DE ENCODING 478 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 00 6C 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni01DF ENCODING 479 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01E0 ENCODING 480 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 30 30 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni01E1 ENCODING 481 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 30 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni01E2 ENCODING 482 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 3E 6C CC CC FE CC CC CC CE 00 00 00 00 ENDCHAR STARTCHAR uni01E3 ENCODING 483 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 CC 76 36 7E D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR uni01E4 ENCODING 484 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 DE C6 DF 66 3A 00 00 00 00 ENDCHAR STARTCHAR uni01E5 ENCODING 485 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 CC CC CC CC 7C 0C 3E CC 78 00 ENDCHAR STARTCHAR Gcaron ENCODING 486 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 3C 66 C2 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR gcaron ENCODING 487 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR uni01E8 ENCODING 488 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 E6 66 66 6C 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni01E9 ENCODING 489 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 E0 60 66 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni01EA ENCODING 490 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 C6 C6 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uni01EB ENCODING 491 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uni01EC ENCODING 492 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 7C C6 C6 C6 C6 C6 C6 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uni01ED ENCODING 493 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 7C C6 C6 C6 C6 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uni01EE ENCODING 494 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 FE 0C 18 30 7C 06 06 06 06 C6 7C 00 00 ENDCHAR STARTCHAR uni01EF ENCODING 495 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 FE 06 0C 18 3C 06 06 06 C6 7C 00 ENDCHAR STARTCHAR uni01F0 ENCODING 496 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1B 0E 04 00 0E 06 06 06 06 06 06 66 66 3C 00 ENDCHAR STARTCHAR uni01F1 ENCODING 497 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F7 D9 D9 DA DA DA DA DC DC F7 00 00 00 00 ENDCHAR STARTCHAR uni01F2 ENCODING 498 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 D8 D8 DF D9 DA DA DA DC F7 00 00 00 00 ENDCHAR STARTCHAR uni01F3 ENCODING 499 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 7F D9 DA DA DA DC 6F 00 00 00 00 ENDCHAR STARTCHAR uni01F4 ENCODING 500 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 3C 66 C2 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR uni01F5 ENCODING 501 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 30 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR uni01F6 ENCODING 502 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D8 D8 D8 DB FB DB DB DB DB CE 00 00 00 00 ENDCHAR STARTCHAR uni01F7 ENCODING 503 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 66 6C 78 70 60 60 60 60 E0 00 ENDCHAR STARTCHAR uni01F8 ENCODING 504 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 C6 E6 F6 FE DE CE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni01F9 ENCODING 505 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 18 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR Aringacute ENCODING 506 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 38 6C 38 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR aringacute ENCODING 507 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 38 6C 38 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR AEacute ENCODING 508 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 3E 6C CC CC FE CC CC CC CE 00 00 00 00 ENDCHAR STARTCHAR aeacute ENCODING 509 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 CC 76 36 7E D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR Oslashacute ENCODING 510 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 7A C4 CE CE D6 E6 E6 46 BC 00 00 00 00 ENDCHAR STARTCHAR oslashacute ENCODING 511 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7A C4 CE D6 E6 46 BC 00 00 00 00 ENDCHAR STARTCHAR uni0200 ENCODING 512 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni0201 ENCODING 513 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0202 ENCODING 514 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni0203 ENCODING 515 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0204 ENCODING 516 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni0205 ENCODING 517 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0206 ENCODING 518 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni0207 ENCODING 519 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0208 ENCODING 520 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni0209 ENCODING 521 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni020A ENCODING 522 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 3C 66 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni020B ENCODING 523 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni020C ENCODING 524 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni020D ENCODING 525 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni020E ENCODING 526 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni020F ENCODING 527 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0210 ENCODING 528 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 FC 66 66 66 7C 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni0211 ENCODING 529 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 DC 76 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni0212 ENCODING 530 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 00 FC 66 66 66 7C 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni0213 ENCODING 531 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 00 DC 76 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni0214 ENCODING 532 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0215 ENCODING 533 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0216 ENCODING 534 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 00 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0217 ENCODING 535 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR Scommaaccent ENCODING 536 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 60 38 0C 06 C6 C6 7C 00 18 18 30 ENDCHAR STARTCHAR scommaaccent ENCODING 537 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 60 38 0C C6 7C 00 18 18 30 ENDCHAR STARTCHAR Tcommaaccent ENCODING 538 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 00 18 18 30 ENDCHAR STARTCHAR tcommaaccent ENCODING 539 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 00 18 18 30 ENDCHAR STARTCHAR uni021C ENCODING 540 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 86 06 1C 74 06 06 06 06 1C F0 00 00 ENDCHAR STARTCHAR uni021D ENCODING 541 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 0E 3C 06 06 1C F0 00 00 ENDCHAR STARTCHAR uni021E ENCODING 542 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 C6 C6 C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni021F ENCODING 543 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 E0 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni0222 ENCODING 546 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C C6 C6 C6 7C C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0223 ENCODING 547 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 66 66 66 3C 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0224 ENCODING 548 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 86 0C 18 30 60 C0 C0 FC 06 0C 00 00 ENDCHAR STARTCHAR uni0225 ENCODING 549 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 30 60 C0 FC 06 0C 00 00 ENDCHAR STARTCHAR uni0226 ENCODING 550 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni0227 ENCODING 551 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0228 ENCODING 552 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 18 0C 38 00 ENDCHAR STARTCHAR uni0229 ENCODING 553 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 18 0C 38 00 ENDCHAR STARTCHAR uni022A ENCODING 554 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 00 6C 00 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni022B ENCODING 555 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 6C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni022C ENCODING 556 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 00 72 9C 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni022D ENCODING 557 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 00 76 DC 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni022E ENCODING 558 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni022F ENCODING 559 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0230 ENCODING 560 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 00 30 00 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0231 ENCODING 561 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 30 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0232 ENCODING 562 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 3C 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni0233 ENCODING 563 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni0250 ENCODING 592 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 7C 60 3C 00 00 00 00 ENDCHAR STARTCHAR uni0251 ENCODING 593 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 74 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0252 ENCODING 594 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 5C 00 00 00 00 ENDCHAR STARTCHAR uni0253 ENCODING 595 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 60 78 6C 66 66 66 66 7C 00 00 00 00 ENDCHAR STARTCHAR uni0254 ENCODING 596 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0255 ENCODING 597 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 DC E6 7C 80 00 00 00 ENDCHAR STARTCHAR uni0256 ENCODING 598 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 7C 0C 0D 06 00 ENDCHAR STARTCHAR uni0257 ENCODING 599 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 0D 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0258 ENCODING 600 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0259 ENCODING 601 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 06 FE C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni025A ENCODING 602 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3B 6C 8E 16 26 6C 38 00 00 00 00 ENDCHAR STARTCHAR uni025B ENCODING 603 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 78 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni025C ENCODING 604 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 3C 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni025D ENCODING 605 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7A CD 0D 38 0C CC 78 00 00 00 00 ENDCHAR STARTCHAR uni025E ENCODING 606 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 DC C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni025F ENCODING 607 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0E 06 06 1F 06 06 06 66 66 3C 00 ENDCHAR STARTCHAR uni0260 ENCODING 608 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 06 0D 7C CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR uni0261 ENCODING 609 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR uni0262 ENCODING 610 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 CE C6 C6 7A 00 00 00 00 ENDCHAR STARTCHAR uni0263 ENCODING 611 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 46 6C 2C 2C 38 18 18 18 18 00 ENDCHAR STARTCHAR uni0264 ENCODING 612 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C2 64 28 38 38 6C 38 00 00 00 00 ENDCHAR STARTCHAR uni0265 ENCODING 613 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CE CC CC CC CC DC 6C 0C 0C 0E 00 ENDCHAR STARTCHAR uni0266 ENCODING 614 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni0267 ENCODING 615 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 60 6C 76 66 66 66 66 E6 06 06 1C 00 ENDCHAR STARTCHAR uni0268 ENCODING 616 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 38 18 18 3C 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni0269 ENCODING 617 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 18 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR uni026A ENCODING 618 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni026B ENCODING 619 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 7B DE 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni026C ENCODING 620 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 78 58 3E 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni026D ENCODING 621 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 18 18 1B 0E 00 ENDCHAR STARTCHAR uni026E ENCODING 622 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 7F 63 66 6C 7E 63 F3 03 33 1E 00 ENDCHAR STARTCHAR uni026F ENCODING 623 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 D6 D6 D6 D6 FE 6E 00 00 00 00 ENDCHAR STARTCHAR uni0270 ENCODING 624 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 D6 D6 D6 D6 FE 6E 06 06 06 00 ENDCHAR STARTCHAR uni0271 ENCODING 625 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 EC FE D6 D6 D6 D6 C6 06 06 1C 00 ENDCHAR STARTCHAR uni0272 ENCODING 626 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 60 60 C0 00 ENDCHAR STARTCHAR uni0273 ENCODING 627 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 06 06 03 00 ENDCHAR STARTCHAR uni0274 ENCODING 628 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 E6 F6 FE DE CE C6 00 00 00 00 ENDCHAR STARTCHAR uni0275 ENCODING 629 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 FE C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0276 ENCODING 630 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6E D8 D8 DE D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR uni0277 ENCODING 631 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C C6 D6 D6 D6 D6 6C 00 00 00 00 ENDCHAR STARTCHAR uni0278 ENCODING 632 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 10 7C D6 D6 D6 D6 D6 7C 10 10 10 00 ENDCHAR STARTCHAR uni0279 ENCODING 633 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 1E 0C 0C 0C CC DC 76 00 00 00 00 ENDCHAR STARTCHAR uni027A ENCODING 634 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 0C 0C 0C 0C 0C 0C CC DC 76 00 00 00 00 ENDCHAR STARTCHAR uni027B ENCODING 635 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 1E 0C 0C 0C CC DC 6C 0C 0D 06 00 ENDCHAR STARTCHAR uni027C ENCODING 636 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 66 60 60 60 60 60 60 F0 00 ENDCHAR STARTCHAR uni027D ENCODING 637 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 66 60 60 60 60 60 6C 38 00 ENDCHAR STARTCHAR uni027E ENCODING 638 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni027F ENCODING 639 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 CC CC 0C 0C 0C 1E 00 00 00 00 ENDCHAR STARTCHAR uni0280 ENCODING 640 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FC 66 66 7C 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni0281 ENCODING 641 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 E6 66 6C 7C 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni0282 ENCODING 642 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 60 38 0C C6 FC C0 D8 70 00 ENDCHAR STARTCHAR uni0283 ENCODING 643 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 1B 19 18 18 18 18 18 18 18 98 D8 70 00 ENDCHAR STARTCHAR uni0284 ENCODING 644 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 1B 19 18 18 18 18 18 18 3C 98 D8 70 00 ENDCHAR STARTCHAR uni0285 ENCODING 645 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 D8 18 18 18 18 1B 0E 00 00 00 00 ENDCHAR STARTCHAR uni0286 ENCODING 646 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0E 1B 18 18 18 18 18 18 7E D8 70 00 ENDCHAR STARTCHAR uni0287 ENCODING 647 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D8 18 18 18 18 7E 18 18 10 00 00 00 00 ENDCHAR STARTCHAR uni0288 ENCODING 648 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 30 30 30 36 1C 00 ENDCHAR STARTCHAR uni0289 ENCODING 649 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 FF 66 66 3B 00 00 00 00 ENDCHAR STARTCHAR uni028A ENCODING 650 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 EE 6C 6C C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni028B ENCODING 651 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni028C ENCODING 652 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 3C 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR uni028D ENCODING 653 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C FE D6 D6 D6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni028E ENCODING 654 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 60 C0 FC C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni028F ENCODING 655 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 3C 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni0290 ENCODING 656 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 30 60 C6 FE 06 06 03 00 ENDCHAR STARTCHAR uni0291 ENCODING 657 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 30 66 CB FE 10 00 00 00 ENDCHAR STARTCHAR uni0292 ENCODING 658 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 06 0C 18 3C 06 06 06 C6 7C 00 ENDCHAR STARTCHAR uni0293 ENCODING 659 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 06 0C 18 3C 06 06 7E C7 7C 00 ENDCHAR STARTCHAR uni0294 ENCODING 660 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 06 1C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni0295 ENCODING 661 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C0 70 30 30 30 30 78 00 00 00 00 ENDCHAR STARTCHAR uni0296 ENCODING 662 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 1C 06 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0297 ENCODING 663 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C0 C0 C0 C6 7C 00 ENDCHAR STARTCHAR uni0298 ENCODING 664 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C3 C3 DB DB C3 C3 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0299 ENCODING 665 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FC 66 66 7C 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni029A ENCODING 666 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 76 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni029B ENCODING 667 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 03 7E C6 C0 CE C6 C6 7A 00 00 00 00 ENDCHAR STARTCHAR uni029C ENCODING 668 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR j ENCODING 669 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 0C 00 1C 0C 0C 0C 0C 0C 0C 7E CC 78 00 ENDCHAR STARTCHAR uni029D ENCODING 670 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CE CC 6C 3C 3C 6C CC 0C 0C 0E 00 ENDCHAR STARTCHAR uni029E ENCODING 671 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F0 60 60 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni029F ENCODING 672 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 06 0D 7C CC CC CC CC CC 7C 0C 0C 1E 00 ENDCHAR STARTCHAR uni02A0 ENCODING 673 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 06 1C 18 7E 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni02A1 ENCODING 674 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C0 70 30 FC 30 30 78 00 00 00 00 ENDCHAR STARTCHAR uni02A2 ENCODING 675 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 7F D9 DA DA DA DC 6F 00 00 00 00 ENDCHAR STARTCHAR uni02A3 ENCODING 676 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 7F DB DB DE DE DB 6B 03 1B 0E 00 ENDCHAR STARTCHAR uni02A4 ENCODING 677 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 7F D9 DA DA DB DD 6F 04 00 00 00 ENDCHAR STARTCHAR uni02A5 ENCODING 678 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 60 60 F6 6D 6C 66 63 6B 36 00 00 00 00 ENDCHAR STARTCHAR uni02A6 ENCODING 679 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 26 6D 6C FC 6C 6C 6C 6C 6C 3C 0C 2C 18 00 ENDCHAR STARTCHAR uni02A7 ENCODING 680 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 60 60 F6 6D 6C 6C 6E 6D 36 00 00 00 00 ENDCHAR STARTCHAR uni02A8 ENCODING 681 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D8 C0 FE DB DB DB DB DB DB 03 03 0E 00 ENDCHAR STARTCHAR uni02A9 ENCODING 682 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 66 6D 6C 66 63 6B F6 00 00 00 00 ENDCHAR STARTCHAR uni02AA ENCODING 683 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 6F 6B 63 66 6C 6D FF 00 00 00 00 ENDCHAR STARTCHAR uni02AB ENCODING 684 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 D6 7C 6C 28 C6 D6 7C 6C 28 00 00 00 00 ENDCHAR STARTCHAR uni02AC ENCODING 685 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 C6 C6 00 00 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni02B0 ENCODING 688 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 F0 D8 D8 D8 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B1 ENCODING 689 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 C0 F0 D8 D8 D8 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B2 ENCODING 690 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 00 38 18 18 D8 70 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B3 ENCODING 691 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 B0 D8 C0 C0 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B4 ENCODING 692 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 18 D8 68 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B5 ENCODING 693 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 18 D8 68 0C 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B6 ENCODING 694 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 D8 D8 F0 D8 D8 F0 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B7 ENCODING 695 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C6 D6 7C 6C 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B8 ENCODING 696 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 D8 D8 78 18 70 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02B9 ENCODING 697 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 60 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02BA ENCODING 698 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 36 6C D8 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02BB ENCODING 699 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57929 ENCODING 700 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii64937 ENCODING 701 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 30 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02BE ENCODING 702 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 0C 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02BF ENCODING 703 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 60 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C0 ENCODING 704 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D8 18 30 30 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C1 ENCODING 705 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D8 C0 60 60 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C2 ENCODING 706 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 70 C0 70 18 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C3 ENCODING 707 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 70 18 70 C0 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C4 ENCODING 708 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 20 20 70 70 D8 D8 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C5 ENCODING 709 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 D8 D8 70 70 20 20 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR circumflex ENCODING 710 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR caron ENCODING 711 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02C8 ENCODING 712 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR macron ENCODING 713 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02CA ENCODING 714 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02CB ENCODING 715 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02CC ENCODING 716 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 18 18 00 ENDCHAR STARTCHAR uni02CD ENCODING 717 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 7C 00 00 ENDCHAR STARTCHAR uni02CE ENCODING 718 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 18 0C 00 ENDCHAR STARTCHAR uni02CF ENCODING 719 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 30 60 00 ENDCHAR STARTCHAR breve ENCODING 728 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR dotaccent ENCODING 729 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR ring ENCODING 730 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 38 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR ogonek ENCODING 731 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 30 1C 00 ENDCHAR STARTCHAR tilde ENCODING 732 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR hungarumlaut ENCODING 733 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 CC 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni02EE ENCODING 750 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 6C 6C 48 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR gravecomb ENCODING 768 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR acutecomb ENCODING 769 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR tildecomb ENCODING 771 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 34 58 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR hookabovecomb ENCODING 777 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 18 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0312 ENCODING 786 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0313 ENCODING 787 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0314 ENCODING 788 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 30 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR dotbelowcomb ENCODING 803 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 18 18 00 ENDCHAR STARTCHAR uni0340 ENCODING 832 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0341 ENCODING 833 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0374 ENCODING 884 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 20 40 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0375 ENCODING 885 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 10 20 60 00 00 00 ENDCHAR STARTCHAR uni037A ENCODING 890 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 30 34 18 00 ENDCHAR STARTCHAR uni037E ENCODING 894 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 00 00 00 18 18 30 00 00 00 00 ENDCHAR STARTCHAR tonos ENCODING 900 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR dieresistonos ENCODING 901 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 6C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR Alphatonos ENCODING 902 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 10 38 6C C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR anoteleia ENCODING 903 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 18 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR Epsilontonos ENCODING 904 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 3E 32 30 34 3C 34 30 30 32 3E 00 00 00 00 ENDCHAR STARTCHAR Etatonos ENCODING 905 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 33 33 33 33 3F 33 33 33 33 33 00 00 00 00 ENDCHAR STARTCHAR Iotatonos ENCODING 906 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 3C 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Omicrontonos ENCODING 908 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 3C 66 66 66 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR Upsilontonos ENCODING 910 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 66 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Omegatonos ENCODING 911 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 3E 63 63 63 63 63 36 36 36 77 00 00 00 00 ENDCHAR STARTCHAR iotadieresistonos ENCODING 912 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 6C 00 38 18 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR Alpha ENCODING 913 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 6C C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Beta ENCODING 914 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR Gamma ENCODING 915 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 60 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR Delta ENCODING 916 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 38 38 6C 6C C6 C6 C6 FE 00 00 00 00 ENDCHAR STARTCHAR Epsilon ENCODING 917 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR Zeta ENCODING 918 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 86 0C 18 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR Eta ENCODING 919 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Theta ENCODING 920 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 FE C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Iota ENCODING 921 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Kappa ENCODING 922 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR Lambda ENCODING 923 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 38 38 6C 6C C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Mu ENCODING 924 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 EE FE FE D6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Nu ENCODING 925 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Xi ENCODING 926 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 82 44 7C 44 00 82 C6 FE 00 00 00 00 ENDCHAR STARTCHAR Omicron ENCODING 927 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR Pi ENCODING 928 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 C6 C6 C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR Rho ENCODING 929 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR Sigma ENCODING 931 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 62 30 18 18 30 62 C6 FE 00 00 00 00 ENDCHAR STARTCHAR Tau ENCODING 932 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Upsilon ENCODING 933 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Phi ENCODING 934 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 7C D6 D6 D6 D6 D6 7C 10 10 00 00 00 00 ENDCHAR STARTCHAR Chi ENCODING 935 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 6C 7C 38 38 7C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR Psi ENCODING 936 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 92 D6 D6 D6 D6 D6 7C 10 10 00 00 00 00 ENDCHAR STARTCHAR Omega ENCODING 937 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 6C 6C 6C EE 00 00 00 00 ENDCHAR STARTCHAR Iotadieresis ENCODING 938 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 66 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR Upsilondieresis ENCODING 939 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 66 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR alphatonos ENCODING 940 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR epsilontonos ENCODING 941 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 C0 78 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR etatonos ENCODING 942 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 DC 66 66 66 66 66 66 06 06 06 00 ENDCHAR STARTCHAR iotatonos ENCODING 943 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 38 18 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR upsilondieresistonos ENCODING 944 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 6C 00 CC C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR alpha ENCODING 945 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR beta ENCODING 946 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 6C 66 66 66 66 6C 60 60 60 00 ENDCHAR STARTCHAR gamma ENCODING 947 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 46 6C 2C 2C 38 18 18 18 18 00 ENDCHAR STARTCHAR delta ENCODING 948 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 30 18 7C C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR epsilon ENCODING 949 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 78 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR zeta ENCODING 950 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 46 7C 18 30 60 60 C0 C0 C0 7C 06 06 1C 00 ENDCHAR STARTCHAR eta ENCODING 951 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 06 06 06 00 ENDCHAR STARTCHAR theta ENCODING 952 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 7E 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR iota ENCODING 953 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 18 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR kappa ENCODING 954 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 E6 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR lambda ENCODING 955 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 20 30 10 38 38 6C 64 C6 C2 00 00 00 00 ENDCHAR STARTCHAR mu ENCODING 956 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC F6 C0 C0 C0 00 ENDCHAR STARTCHAR nu ENCODING 957 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 66 6C 3C 38 10 00 00 00 00 ENDCHAR STARTCHAR xi ENCODING 958 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 3C 30 60 3C 60 C0 C0 C0 7C 06 06 1C 00 ENDCHAR STARTCHAR omicron ENCODING 959 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR pi ENCODING 960 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 6C 6C 6C 6C 6C 66 00 00 00 00 ENDCHAR STARTCHAR rho ENCODING 961 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 66 66 66 66 7C 60 60 60 00 ENDCHAR STARTCHAR sigma1 ENCODING 962 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 7C 06 06 1C 00 00 ENDCHAR STARTCHAR sigma ENCODING 963 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR tau ENCODING 964 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E 18 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR upsilon ENCODING 965 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR phi ENCODING 966 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C D6 D6 D6 D6 D6 7C 10 10 10 00 ENDCHAR STARTCHAR chi ENCODING 967 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 86 46 2C 2C 18 30 68 68 C4 C2 00 ENDCHAR STARTCHAR psi ENCODING 968 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 92 D6 D6 D6 D6 D6 7C 10 10 10 00 ENDCHAR STARTCHAR omega ENCODING 969 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C C6 D6 D6 D6 D6 6C 00 00 00 00 ENDCHAR STARTCHAR iotadieresis ENCODING 970 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 00 38 18 18 18 18 18 0E 00 00 00 00 ENDCHAR STARTCHAR upsilondieresis ENCODING 971 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 CC C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR omicrontonos ENCODING 972 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR upsilontonos ENCODING 973 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 CC C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR omegatonos ENCODING 974 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 6C C6 D6 D6 D6 D6 6C 00 00 00 00 ENDCHAR STARTCHAR uni03D0 ENCODING 976 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 6C 7C 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR theta1 ENCODING 977 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 36 1E C6 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR Upsilon1 ENCODING 978 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C2 65 24 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni03D3 ENCODING 979 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 C0 21 32 12 1C 0C 0C 0C 0C 0C 1E 00 00 00 00 ENDCHAR STARTCHAR uni03D4 ENCODING 980 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C2 65 24 38 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR phi1 ENCODING 981 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 10 7C D6 D6 D6 D6 D6 7C 10 10 10 00 ENDCHAR STARTCHAR omega1 ENCODING 982 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 6C C6 D6 D6 D6 6C 00 00 00 00 ENDCHAR STARTCHAR uni03D7 ENCODING 983 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 46 A6 2C 38 68 CA C4 0C 18 00 00 ENDCHAR STARTCHAR uni03DA ENCODING 986 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 60 3C 06 06 1C 00 00 ENDCHAR STARTCHAR uni03DB ENCODING 987 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E C0 C0 C0 C0 C0 7C 06 06 1C 00 ENDCHAR STARTCHAR uni03DC ENCODING 988 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 60 78 68 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni03DD ENCODING 989 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E 32 30 30 3C 34 30 30 30 30 00 ENDCHAR STARTCHAR uni03DE ENCODING 990 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 30 30 60 63 FF C6 06 0C 0C 06 00 00 00 00 ENDCHAR STARTCHAR uni03DF ENCODING 991 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 60 60 FE FE 0C 0C 18 18 00 00 00 00 ENDCHAR STARTCHAR uni03E0 ENCODING 992 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 AC 26 26 0B 0B 1B 1B 1B 1B 03 02 04 00 ENDCHAR STARTCHAR uni03E1 ENCODING 993 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C0 60 30 18 28 4C 14 24 06 02 02 00 ENDCHAR STARTCHAR uni03E2 ENCODING 994 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB DB DB DB DB DB DB DB 6D 03 3E 00 00 ENDCHAR STARTCHAR uni03E3 ENCODING 995 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DB DB DB DB DB DB 6D 03 7E 00 00 ENDCHAR STARTCHAR uni03E4 ENCODING 996 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 D6 C6 C6 C6 7E 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni03E5 ENCODING 997 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 36 66 66 66 66 3E 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni03E6 ENCODING 998 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 C0 FC C6 C6 C6 C6 C6 06 76 9C 00 ENDCHAR STARTCHAR uni03E7 ENCODING 999 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 7C D6 66 06 06 66 BC 00 00 00 00 ENDCHAR STARTCHAR uni03E8 ENCODING 1000 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 06 3C 60 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni03E9 ENCODING 1001 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 26 1C 70 C0 C2 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni03EA ENCODING 1002 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 68 38 30 38 38 4C 4C 86 FE 00 00 00 00 ENDCHAR STARTCHAR uni03EB ENCODING 1003 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 64 BA 30 38 28 4C 7C 00 00 00 00 ENDCHAR STARTCHAR uni03EC ENCODING 1004 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E C0 CC D6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni03ED ENCODING 1005 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E C0 DC C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni03EE ENCODING 1006 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 7E 99 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni03EF ENCODING 1007 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 1C 18 7E 58 18 18 18 38 18 00 00 00 00 ENDCHAR STARTCHAR uni03F0 ENCODING 1008 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 46 A6 2C 38 68 CA C4 00 00 00 00 ENDCHAR STARTCHAR uni03F1 ENCODING 1009 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 FC C0 60 3C 06 00 ENDCHAR STARTCHAR uni03F2 ENCODING 1010 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni03F3 ENCODING 1011 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 06 00 0E 06 06 06 06 06 06 66 66 3C 00 ENDCHAR STARTCHAR uni0400 ENCODING 1024 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 18 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR afii10023 ENCODING 1025 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR afii10051 ENCODING 1026 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE B2 30 3E 33 33 33 33 33 33 03 06 00 00 ENDCHAR STARTCHAR afii10052 ENCODING 1027 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 FE 66 62 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR afii10053 ENCODING 1028 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 F8 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR afii10054 ENCODING 1029 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 60 38 0C 06 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10055 ENCODING 1030 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR afii10056 ENCODING 1031 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 66 00 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR afii10057 ENCODING 1032 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 0C 0C 0C 0C 0C CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR afii10058 ENCODING 1033 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 D8 D8 D8 DE DB DB DB DB DE 00 00 00 00 ENDCHAR STARTCHAR afii10059 ENCODING 1034 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D8 D8 D8 D8 FE DB DB DB DB DE 00 00 00 00 ENDCHAR STARTCHAR afii10060 ENCODING 1035 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE B2 30 3E 33 33 33 33 33 33 00 00 00 00 ENDCHAR STARTCHAR afii10061 ENCODING 1036 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 E6 66 66 6C 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni040D ENCODING 1037 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 18 00 C6 C6 CE DE FE F6 E6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10062 ENCODING 1038 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 C6 C6 C6 C6 7E 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10145 ENCODING 1039 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 C6 C6 FE 38 10 10 00 ENDCHAR STARTCHAR afii10017 ENCODING 1040 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 6C C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10018 ENCODING 1041 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 60 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR afii10019 ENCODING 1042 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR afii10020 ENCODING 1043 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 60 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR afii10021 ENCODING 1044 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 6C 6C 6C 6C 6C 6C 6C 6C FE C6 82 00 00 ENDCHAR STARTCHAR afii10022 ENCODING 1045 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR afii10024 ENCODING 1046 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D6 D6 D6 7C 38 7C D6 D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR afii10025 ENCODING 1047 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 86 06 3C 06 06 86 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10026 ENCODING 1048 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 CE DE FE F6 E6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10027 ENCODING 1049 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 C6 C6 C6 CE DE FE F6 E6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10028 ENCODING 1050 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR afii10029 ENCODING 1051 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 66 66 66 66 66 66 66 66 C6 00 00 00 00 ENDCHAR STARTCHAR afii10030 ENCODING 1052 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 EE FE FE D6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10031 ENCODING 1053 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10032 ENCODING 1054 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10033 ENCODING 1055 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 C6 C6 C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10034 ENCODING 1056 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR afii10035 ENCODING 1057 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR afii10036 ENCODING 1058 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR afii10037 ENCODING 1059 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 7E 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10038 ENCODING 1060 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 7C D6 D6 D6 D6 D6 7C 10 10 00 00 00 00 ENDCHAR STARTCHAR afii10039 ENCODING 1061 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 6C 7C 38 38 7C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10040 ENCODING 1062 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC CC CC CC CC CC CC CC CC FE 06 02 00 00 ENDCHAR STARTCHAR afii10041 ENCODING 1063 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 7E 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR afii10042 ENCODING 1064 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 D6 D6 D6 D6 D6 D6 D6 D6 FE 00 00 00 00 ENDCHAR STARTCHAR afii10043 ENCODING 1065 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 D6 D6 D6 D6 D6 D6 D6 D6 FF 03 01 00 00 ENDCHAR STARTCHAR afii10044 ENCODING 1066 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 B0 B0 30 3C 36 36 36 36 7C 00 00 00 00 ENDCHAR STARTCHAR afii10045 ENCODING 1067 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C3 C3 C3 C3 F3 DB DB DB DB F3 00 00 00 00 ENDCHAR STARTCHAR afii10046 ENCODING 1068 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR afii10047 ENCODING 1069 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC 86 06 3E 06 06 86 CC 78 00 00 00 00 ENDCHAR STARTCHAR afii10048 ENCODING 1070 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 9C B6 B6 B6 F6 B6 B6 B6 B6 9C 00 00 00 00 ENDCHAR STARTCHAR afii10049 ENCODING 1071 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E CC CC CC 7C 6C 6C 6C 6C CE 00 00 00 00 ENDCHAR STARTCHAR afii10065 ENCODING 1072 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR afii10066 ENCODING 1073 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 7C C0 C0 FC C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10067 ENCODING 1074 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FC 66 66 7C 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR afii10068 ENCODING 1075 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 66 62 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR afii10069 ENCODING 1076 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 6C 6C 6C 6C 6C FE C6 82 00 00 ENDCHAR STARTCHAR afii10070 ENCODING 1077 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10072 ENCODING 1078 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D6 D6 D6 7C D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR afii10073 ENCODING 1079 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 3C 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10074 ENCODING 1080 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 CE DE FE F6 E6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10075 ENCODING 1081 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 C6 CE DE FE F6 E6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10076 ENCODING 1082 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 E6 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR afii10077 ENCODING 1083 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3E 66 66 66 66 66 C6 00 00 00 00 ENDCHAR STARTCHAR afii10078 ENCODING 1084 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 EE FE FE D6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10079 ENCODING 1085 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10080 ENCODING 1086 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10081 ENCODING 1087 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10082 ENCODING 1088 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 7C 60 60 F0 00 ENDCHAR STARTCHAR afii10083 ENCODING 1089 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10084 ENCODING 1090 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E 5A 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR afii10085 ENCODING 1091 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR afii10086 ENCODING 1092 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 7C D6 D6 D6 D6 D6 7C 10 10 10 00 ENDCHAR STARTCHAR afii10087 ENCODING 1093 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 6C 38 38 38 6C C6 00 00 00 00 ENDCHAR STARTCHAR afii10088 ENCODING 1094 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC FE 06 02 00 00 ENDCHAR STARTCHAR afii10089 ENCODING 1095 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 7E 06 06 06 00 00 00 00 ENDCHAR STARTCHAR afii10090 ENCODING 1096 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 D6 D6 D6 D6 D6 FE 00 00 00 00 ENDCHAR STARTCHAR afii10091 ENCODING 1097 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 D6 D6 D6 D6 D6 FF 03 01 00 00 ENDCHAR STARTCHAR afii10092 ENCODING 1098 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F8 B0 30 3C 36 36 7C 00 00 00 00 ENDCHAR STARTCHAR afii10093 ENCODING 1099 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C3 C3 C3 F3 DB DB F3 00 00 00 00 ENDCHAR STARTCHAR afii10094 ENCODING 1100 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F0 60 60 7C 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR afii10095 ENCODING 1101 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 3E 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10096 ENCODING 1102 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 9C B6 B6 F6 B6 B6 9C 00 00 00 00 ENDCHAR STARTCHAR afii10097 ENCODING 1103 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E CC CC 7C 6C 6C CE 00 00 00 00 ENDCHAR STARTCHAR uni0450 ENCODING 1104 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10071 ENCODING 1105 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10099 ENCODING 1106 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 F8 60 6C 76 66 66 66 66 E6 06 06 1C 00 ENDCHAR STARTCHAR afii10100 ENCODING 1107 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 FE 66 62 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR afii10101 ENCODING 1108 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 F8 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10102 ENCODING 1109 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10103 ENCODING 1110 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR afii10104 ENCODING 1111 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR afii10105 ENCODING 1112 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 06 00 0E 06 06 06 06 06 06 66 66 3C 00 ENDCHAR STARTCHAR afii10106 ENCODING 1113 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 D8 D8 DE DB DB DE 00 00 00 00 ENDCHAR STARTCHAR afii10107 ENCODING 1114 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D8 D8 D8 FE DB DB DE 00 00 00 00 ENDCHAR STARTCHAR afii10108 ENCODING 1115 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 F8 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR afii10109 ENCODING 1116 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 E6 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni045D ENCODING 1117 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 C6 CE DE FE F6 E6 C6 00 00 00 00 ENDCHAR STARTCHAR afii10110 ENCODING 1118 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR afii10193 ENCODING 1119 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 C6 C6 C6 FE 38 10 10 00 ENDCHAR STARTCHAR uni0460 ENCODING 1120 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C C6 C6 D6 D6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni0461 ENCODING 1121 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR afii10146 ENCODING 1122 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 FC B4 30 3C 36 36 36 36 7C 00 00 00 00 ENDCHAR STARTCHAR afii10194 ENCODING 1123 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 30 FC B4 30 3C 36 36 7C 00 00 00 00 ENDCHAR STARTCHAR uni0464 ENCODING 1124 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CE DB D9 D8 FE D8 D8 D9 DB CE 00 00 00 00 ENDCHAR STARTCHAR uni0465 ENCODING 1125 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CE DB D8 FE D8 DB CE 00 00 00 00 ENDCHAR STARTCHAR uni0466 ENCODING 1126 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 38 6C 6C 6C FE D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni0467 ENCODING 1127 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 38 38 6C 7C D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni0468 ENCODING 1128 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 88 8C 9C 96 F6 B6 BF AB EB EB 00 00 00 00 ENDCHAR STARTCHAR uni0469 ENCODING 1129 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 88 8C 9C F6 BE AB EB 00 00 00 00 ENDCHAR STARTCHAR uni046A ENCODING 1130 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 6C 6C 38 7C D6 D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni046B ENCODING 1131 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE C6 6C 7C D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni046C ENCODING 1132 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF A3 B2 96 FC 9C BE AA AB EB 00 00 00 00 ENDCHAR STARTCHAR uni046D ENCODING 1133 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 BF A3 96 FE AB AB EB 00 00 00 00 ENDCHAR STARTCHAR uni046E ENCODING 1134 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 10 7C C6 06 06 7C 06 06 06 7C C0 7C 00 00 ENDCHAR STARTCHAR uni046F ENCODING 1135 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 6C 38 10 00 7C 86 06 7C 06 06 7C C0 7C 00 00 ENDCHAR STARTCHAR uni0470 ENCODING 1136 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 96 D6 D6 D6 D6 D6 7C 10 10 00 00 00 00 ENDCHAR STARTCHAR uni0471 ENCODING 1137 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 10 96 D6 D6 D6 D6 D6 7C 10 10 10 00 ENDCHAR STARTCHAR afii10147 ENCODING 1138 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 FE C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10195 ENCODING 1139 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 FE C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10148 ENCODING 1140 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C2 C6 C6 C4 CC 6C 68 78 38 30 00 00 00 00 ENDCHAR STARTCHAR afii10196 ENCODING 1141 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C2 C6 64 6C 38 38 10 00 00 00 00 ENDCHAR STARTCHAR uni0476 ENCODING 1142 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC 66 00 C2 C6 C4 C4 6C 68 78 38 30 00 00 00 00 ENDCHAR STARTCHAR uni0477 ENCODING 1143 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC 66 00 C2 C6 64 6C 38 38 10 00 00 00 00 ENDCHAR STARTCHAR uni0478 ENCODING 1144 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D8 D8 DB DB DB DB DB DB 6F 03 06 1C 00 ENDCHAR STARTCHAR uni0479 ENCODING 1145 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 73 DB DB DB DB DB 6F 03 06 1C 00 ENDCHAR STARTCHAR uni047A ENCODING 1146 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 7C D6 C6 C6 C6 C6 C6 C6 D6 7C 10 00 00 00 ENDCHAR STARTCHAR uni047B ENCODING 1147 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 7C D6 C6 C6 C6 D6 7C 10 00 00 00 ENDCHAR STARTCHAR uni047C ENCODING 1148 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 7C 40 6C C6 C6 D6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni047D ENCODING 1149 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 04 7C 40 00 6C C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni047E ENCODING 1150 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 54 00 6C C6 C6 D6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni047F ENCODING 1151 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C 54 00 6C C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni0480 ENCODING 1152 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 C0 60 3C 0C 0C 0C 00 ENDCHAR STARTCHAR uni0481 ENCODING 1153 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C0 78 18 18 00 00 ENDCHAR STARTCHAR uni0482 ENCODING 1154 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 06 3C 0F 18 18 F0 3C 60 60 00 00 00 00 ENDCHAR STARTCHAR uni0483 ENCODING 1155 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 04 7C 40 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0484 ENCODING 1156 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 24 44 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0485 ENCODING 1157 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 40 7C 40 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0486 ENCODING 1158 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 04 7C 04 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0488 ENCODING 1160 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 66 00 C3 00 66 18 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0489 ENCODING 1161 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 50 46 00 82 41 00 62 0A 10 00 00 00 00 ENDCHAR STARTCHAR uni048A ENCODING 1162 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 C6 C6 C6 CE DE FE F6 E6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni048B ENCODING 1163 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 C6 CE DE FE F6 E6 C7 03 01 00 00 ENDCHAR STARTCHAR uni048C ENCODING 1164 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 F0 60 60 60 7C 66 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni048D ENCODING 1165 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 60 F0 60 60 7C 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni048E ENCODING 1166 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 6E 64 7A 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni048F ENCODING 1167 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 6E 64 7A 60 60 F0 00 ENDCHAR STARTCHAR afii10050 ENCODING 1168 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 02 06 FE 60 60 60 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR afii10098 ENCODING 1169 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 02 06 FE 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni0492 ENCODING 1170 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 60 F8 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni0493 ENCODING 1171 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 66 62 F8 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni0494 ENCODING 1172 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 60 7C 66 66 66 66 F6 06 16 0C 00 ENDCHAR STARTCHAR uni0495 ENCODING 1173 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 66 62 78 6C 66 F6 06 16 0C 00 ENDCHAR STARTCHAR uni0496 ENCODING 1174 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D6 D6 D6 7C 38 7C D6 D6 D6 D7 03 01 00 00 ENDCHAR STARTCHAR uni0497 ENCODING 1175 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D6 D6 D6 7C D6 D6 D7 03 01 00 00 ENDCHAR STARTCHAR uni0498 ENCODING 1176 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 86 06 3C 06 06 86 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uni0499 ENCODING 1177 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 3C 06 C6 7C 30 60 38 00 ENDCHAR STARTCHAR uni049A ENCODING 1178 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E7 03 01 00 00 ENDCHAR STARTCHAR uni049B ENCODING 1179 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 E6 6C 78 78 6C 66 E7 03 01 00 00 ENDCHAR STARTCHAR uni049C ENCODING 1180 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 D6 D6 DC F8 DC D6 D6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni049D ENCODING 1181 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 D6 DC F8 DC D6 C6 00 00 00 00 ENDCHAR STARTCHAR uni049E ENCODING 1182 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 F6 6C 78 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni049F ENCODING 1183 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 F0 66 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni04A0 ENCODING 1184 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F3 B3 B3 36 3C 3C 36 33 33 73 00 00 00 00 ENDCHAR STARTCHAR uni04A1 ENCODING 1185 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F3 B6 BC 3C 36 33 73 00 00 00 00 ENDCHAR STARTCHAR uni04A2 ENCODING 1186 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04A3 ENCODING 1187 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 FE C6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04A4 ENCODING 1188 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DF DB D9 D8 F8 D8 D8 D8 D8 D8 00 00 00 00 ENDCHAR STARTCHAR uni04A5 ENCODING 1189 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DF DB D9 F8 D8 D8 D8 00 00 00 00 ENDCHAR STARTCHAR uni04A6 ENCODING 1190 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 D8 D8 D8 DE DB DB DB DB DB 03 0B 06 00 ENDCHAR STARTCHAR uni04A7 ENCODING 1191 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D8 D8 D8 FE DB DB DB 03 0B 06 00 ENDCHAR STARTCHAR uni04A8 ENCODING 1192 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C2 CC D6 D6 D6 D6 D6 CC 7A 00 00 00 00 ENDCHAR STARTCHAR uni04A9 ENCODING 1193 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C2 CC D6 D6 CC 7A 00 00 00 00 ENDCHAR STARTCHAR uni04AA ENCODING 1194 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 C2 66 3C 18 0C 38 00 ENDCHAR STARTCHAR uni04AB ENCODING 1195 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C6 7C 18 0C 38 00 ENDCHAR STARTCHAR uni04AC ENCODING 1196 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 0C 04 00 00 ENDCHAR STARTCHAR uni04AD ENCODING 1197 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E 5A 18 18 18 18 3C 0C 04 00 00 ENDCHAR STARTCHAR uni04AE ENCODING 1198 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni04AF ENCODING 1199 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 66 66 3C 18 18 18 3C 00 ENDCHAR STARTCHAR uni04B0 ENCODING 1200 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 3C 18 7E 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni04B1 ENCODING 1201 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 66 66 3C 18 7E 18 3C 00 ENDCHAR STARTCHAR uni04B2 ENCODING 1202 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 6C 7C 38 38 7C 6C C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04B3 ENCODING 1203 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 6C 38 38 38 6C C7 03 01 00 00 ENDCHAR STARTCHAR uni04B4 ENCODING 1204 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F6 66 66 66 66 66 66 66 66 7F 03 01 00 00 ENDCHAR STARTCHAR uni04B5 ENCODING 1205 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F6 66 66 66 66 66 7F 03 01 00 00 ENDCHAR STARTCHAR uni04B6 ENCODING 1206 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 7E 06 06 06 07 03 01 00 00 ENDCHAR STARTCHAR uni04B7 ENCODING 1207 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 7E 06 06 07 03 01 00 00 ENDCHAR STARTCHAR uni04B8 ENCODING 1208 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 D6 D6 7E 16 16 06 06 00 00 00 00 ENDCHAR STARTCHAR uni04B9 ENCODING 1209 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 D6 D6 7E 16 16 06 00 00 00 00 ENDCHAR STARTCHAR uni04BA ENCODING 1210 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 C0 FC C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04BB ENCODING 1211 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C0 C0 C0 FC C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04BC ENCODING 1212 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 33 B3 B3 7F 30 30 30 33 1E 00 00 00 00 ENDCHAR STARTCHAR uni04BD ENCODING 1213 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 9E B3 7F 30 30 33 1E 00 00 00 00 ENDCHAR STARTCHAR uni04BE ENCODING 1214 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 33 B3 B3 7F 30 30 30 33 1E 0C 18 0E 00 ENDCHAR STARTCHAR uni04BF ENCODING 1215 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 9E B3 7F 30 30 33 1E 0C 18 0E 00 ENDCHAR STARTCHAR uni04C0 ENCODING 1216 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni04C1 ENCODING 1217 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 D6 D6 D6 7C 38 7C D6 D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni04C2 ENCODING 1218 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 D6 D6 D6 7C D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni04C3 ENCODING 1219 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 06 16 0C 00 ENDCHAR STARTCHAR uni04C4 ENCODING 1220 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 E6 6C 78 78 6C 66 E6 06 16 0C 00 ENDCHAR STARTCHAR uni04C5 ENCODING 1221 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 66 66 66 66 66 66 66 66 C7 03 01 00 00 ENDCHAR STARTCHAR uni04C6 ENCODING 1222 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3E 66 66 66 66 66 C7 03 01 00 00 ENDCHAR STARTCHAR uni04C7 ENCODING 1223 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 06 16 0C 00 ENDCHAR STARTCHAR uni04C8 ENCODING 1224 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 FE C6 C6 C6 06 16 0C 00 ENDCHAR STARTCHAR uni04C9 ENCODING 1225 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04CA ENCODING 1226 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 FE C6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04CB ENCODING 1227 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 7E 06 06 06 0E 0C 08 00 00 ENDCHAR STARTCHAR uni04CC ENCODING 1228 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 7E 06 06 0E 0C 08 00 00 ENDCHAR STARTCHAR uni04CD ENCODING 1229 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 EE FE FE D6 C6 C6 C6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04CE ENCODING 1230 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 EE FE FE D6 C6 C7 03 01 00 00 ENDCHAR STARTCHAR uni04D0 ENCODING 1232 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04D1 ENCODING 1233 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni04D2 ENCODING 1234 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04D3 ENCODING 1235 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni04D4 ENCODING 1236 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 6C CC CC FE CC CC CC CC CE 00 00 00 00 ENDCHAR STARTCHAR uni04D5 ENCODING 1237 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC 76 36 7E D8 D8 6E 00 00 00 00 ENDCHAR STARTCHAR uni04D6 ENCODING 1238 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni04D7 ENCODING 1239 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04D8 ENCODING 1240 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 06 06 06 FE C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii10846 ENCODING 1241 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 06 FE C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04DA ENCODING 1242 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 7C C6 06 06 FE C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04DB ENCODING 1243 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 06 06 FE C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04DC ENCODING 1244 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 D6 D6 D6 7C 38 7C D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni04DD ENCODING 1245 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 D6 D6 D6 7C D6 D6 D6 00 00 00 00 ENDCHAR STARTCHAR uni04DE ENCODING 1246 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 7C C6 86 06 3C 06 86 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04DF ENCODING 1247 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 06 3C 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04E0 ENCODING 1248 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 06 0C 18 3C 06 06 86 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04E1 ENCODING 1249 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 06 0C 18 3C 06 06 06 C6 7C 00 ENDCHAR STARTCHAR uni04E2 ENCODING 1250 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 C6 C6 CE DE FE F6 E6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04E3 ENCODING 1251 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 C6 CE DE FE F6 E6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04E4 ENCODING 1252 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 CE DE FE F6 E6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04E5 ENCODING 1253 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C6 CE DE FE F6 E6 C6 00 00 00 00 ENDCHAR STARTCHAR uni04E6 ENCODING 1254 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04E7 ENCODING 1255 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04E8 ENCODING 1256 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 FE C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04E9 ENCODING 1257 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 FE C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04EA ENCODING 1258 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 7C C6 C6 C6 FE C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04EB ENCODING 1259 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 C6 FE C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04EC ENCODING 1260 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 78 CC 86 06 3E 06 86 CC 78 00 00 00 00 ENDCHAR STARTCHAR uni04ED ENCODING 1261 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 7C C6 06 3E 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04EE ENCODING 1262 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 C6 C6 C6 C6 7E 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04EF ENCODING 1263 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni04F0 ENCODING 1264 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 C6 C6 7E 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04F1 ENCODING 1265 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni04F2 ENCODING 1266 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 66 CC 00 C6 C6 C6 C6 7E 06 06 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni04F3 ENCODING 1267 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 CC 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni04F4 ENCODING 1268 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 C6 C6 7E 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni04F5 ENCODING 1269 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C6 C6 C6 7E 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni04F8 ENCODING 1272 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C3 C3 C3 F3 DB DB DB DB F3 00 00 00 00 ENDCHAR STARTCHAR uni04F9 ENCODING 1273 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C3 C3 C3 F3 DB DB F3 00 00 00 00 ENDCHAR STARTCHAR uni0500 ENCODING 1280 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 0C 0C 0C 7C CC CC CC CC 7E 00 00 00 00 ENDCHAR STARTCHAR uni0501 ENCODING 1281 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni0502 ENCODING 1282 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 0C 0C 0C 7C CD CD CD CD 76 00 00 00 00 ENDCHAR STARTCHAR uni0503 ENCODING 1283 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CD CD CD 76 00 00 00 00 ENDCHAR STARTCHAR uni0504 ENCODING 1284 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC 8C 0C 38 0D 0D 0D 0D 06 00 00 00 00 ENDCHAR STARTCHAR uni0505 ENCODING 1285 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 CC 0C 39 0D 0D 06 00 00 00 00 ENDCHAR STARTCHAR uni0506 ENCODING 1286 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 86 06 3C 06 06 06 06 07 03 01 00 00 ENDCHAR STARTCHAR uni0507 ENCODING 1287 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 06 3C 06 06 07 03 01 00 00 ENDCHAR STARTCHAR uni0508 ENCODING 1288 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 6C 6C 6C 6C 6D 6D 6D 6D C6 00 00 00 00 ENDCHAR STARTCHAR uni0509 ENCODING 1289 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 6C 6C 6D 6D 6D C6 00 00 00 00 ENDCHAR STARTCHAR uni050A ENCODING 1290 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC CC CC CC FC CD CD CD CD C6 00 00 00 00 ENDCHAR STARTCHAR uni050B ENCODING 1291 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC FD CD CD C6 00 00 00 00 ENDCHAR STARTCHAR uni050C ENCODING 1292 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 CE C6 C6 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni050D ENCODING 1293 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 CE C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni050E ENCODING 1294 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 1B 1B 1B 1B 0E 00 00 00 00 ENDCHAR STARTCHAR uni050F ENCODING 1295 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7E 5A 18 1B 1B 1B 0E 00 00 00 00 ENDCHAR STARTCHAR uni0530 ENCODING 1328 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 64 94 BA 52 4C 30 00 00 00 00 00 ENDCHAR STARTCHAR uni0531 ENCODING 1329 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC CC CC CC CC CC CC CC CF 7B 00 00 00 00 ENDCHAR STARTCHAR uni0532 ENCODING 1330 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 60 60 7E 60 60 00 00 00 00 ENDCHAR STARTCHAR uni0533 ENCODING 1331 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC CC CC CC 7F 0C 0C 0C 0C 00 00 00 00 ENDCHAR STARTCHAR uni0534 ENCODING 1332 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC CC CC CC CF 0C 0C 0C 0C 00 00 00 00 ENDCHAR STARTCHAR uni0535 ENCODING 1333 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 7E 60 60 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0536 ENCODING 1334 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 3E 06 0C D8 FE C3 00 00 00 ENDCHAR STARTCHAR uni0537 ENCODING 1335 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 7E 60 60 60 60 60 60 7C 06 00 00 00 ENDCHAR STARTCHAR uni0538 ENCODING 1336 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 66 60 60 60 7E 00 00 00 00 ENDCHAR STARTCHAR uni0539 ENCODING 1337 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 CF D6 D6 D6 D6 CC C0 C0 00 00 00 00 ENDCHAR STARTCHAR uni053A ENCODING 1338 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 0C 0C 0C 7F CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni053B ENCODING 1339 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 7C 66 66 66 66 66 60 60 00 00 00 00 ENDCHAR STARTCHAR uni053C ENCODING 1340 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 60 60 60 60 60 60 60 7C 06 00 00 00 ENDCHAR STARTCHAR uni053D ENCODING 1341 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 F6 D6 D6 D6 D6 CC C0 C0 00 00 00 00 ENDCHAR STARTCHAR uni053E ENCODING 1342 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 7F 24 66 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni053F ENCODING 1343 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 66 66 66 66 66 3E 06 06 00 00 00 00 ENDCHAR STARTCHAR uni0540 ENCODING 1344 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 30 18 0C 18 30 60 F0 3C 0E 04 00 00 00 ENDCHAR STARTCHAR uni0541 ENCODING 1345 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 06 06 06 6C D8 6E 00 00 00 00 ENDCHAR STARTCHAR uni0542 ENCODING 1346 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC CC CC CC CC 0C 0C 0C 0F 00 00 00 00 ENDCHAR STARTCHAR uni0543 ENCODING 1347 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 30 60 F8 6C 66 66 66 66 7E 00 00 00 00 ENDCHAR STARTCHAR uni0544 ENCODING 1348 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CF CC CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni0545 ENCODING 1349 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 06 06 7C 06 06 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0546 ENCODING 1350 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 60 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0547 ENCODING 1351 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 06 3E 66 60 60 60 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0548 ENCODING 1352 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR uni0549 ENCODING 1353 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 06 06 06 6C 38 0E 00 00 00 00 ENDCHAR STARTCHAR uni054A ENCODING 1354 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C D6 D6 D6 D6 D6 16 16 06 06 00 00 00 00 ENDCHAR STARTCHAR uni054B ENCODING 1355 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 76 1E 0E 0C D8 FE C3 00 00 00 ENDCHAR STARTCHAR uni054C ENCODING 1356 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC CC CC CC CF CC CC CC CC 00 00 00 00 ENDCHAR STARTCHAR uni054D ENCODING 1357 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni054E ENCODING 1358 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 0C CC CC CC CC 7C 0C 0C 0F 00 00 00 00 ENDCHAR STARTCHAR uni054F ENCODING 1359 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 60 30 18 0C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0550 ENCODING 1360 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 66 60 60 60 60 00 00 00 00 ENDCHAR STARTCHAR uni0551 ENCODING 1361 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 3C 66 06 06 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0552 ENCODING 1362 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 7C 66 66 66 66 63 60 60 00 00 00 00 ENDCHAR STARTCHAR uni0553 ENCODING 1363 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 7C D6 D6 D6 D6 D6 D6 7C 10 00 00 00 00 ENDCHAR STARTCHAR uni0554 ENCODING 1364 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 7C 60 60 FE 60 60 00 00 00 00 ENDCHAR STARTCHAR uni0555 ENCODING 1365 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0556 ENCODING 1366 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D0 D0 D0 7C 16 16 16 D6 7C 00 00 00 00 ENDCHAR STARTCHAR uni0559 ENCODING 1369 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 30 18 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni055A ENCODING 1370 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 18 18 30 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni055B ENCODING 1371 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 60 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni055C ENCODING 1372 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 06 3C 60 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni055D ENCODING 1373 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 18 0C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni055E ENCODING 1374 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1C 36 6C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni055F ENCODING 1375 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 60 3E 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0561 ENCODING 1377 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D6 D6 D6 D6 D6 D6 6A 00 00 00 00 ENDCHAR STARTCHAR uni0562 ENCODING 1378 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C 66 66 66 60 60 7E 60 60 60 00 ENDCHAR STARTCHAR uni0563 ENCODING 1379 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C CC CC CC CC CC 7F 0C 0C 0C 00 ENDCHAR STARTCHAR uni0564 ENCODING 1380 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F8 CC CC CC CC CC CF 0C 0C 0C 00 ENDCHAR STARTCHAR uni0565 ENCODING 1381 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 7E 60 60 66 66 66 66 3E 00 00 00 00 ENDCHAR STARTCHAR uni0566 ENCODING 1382 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C CC CC CC CC CC 7C 0C 0C 0F 00 ENDCHAR STARTCHAR uni0567 ENCODING 1383 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 60 7C 60 60 60 60 60 78 0C 18 00 00 ENDCHAR STARTCHAR uni0568 ENCODING 1384 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C 66 66 66 66 66 66 60 60 7E 00 ENDCHAR STARTCHAR uni0569 ENCODING 1385 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FC C6 C6 CF D6 D6 CC C0 C0 C0 00 ENDCHAR STARTCHAR uni056A ENCODING 1386 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 0C 0C 7F CC CC CC CC CC 7C 00 00 00 00 ENDCHAR STARTCHAR uni056B ENCODING 1387 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 60 7C 66 66 66 66 66 66 60 60 60 00 ENDCHAR STARTCHAR uni056C ENCODING 1388 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 30 30 30 30 30 30 30 30 30 3E 00 ENDCHAR STARTCHAR uni056D ENCODING 1389 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 F6 D6 D6 D6 D6 D6 CA C0 C0 C0 00 ENDCHAR STARTCHAR uni056E ENCODING 1390 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 38 0C 7F CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni056F ENCODING 1391 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 60 66 66 66 66 66 66 3E 06 06 06 00 ENDCHAR STARTCHAR uni0570 ENCODING 1392 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 60 7C 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR uni0571 ENCODING 1393 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 1C 0C 18 3C 64 66 62 63 3D 00 00 00 00 ENDCHAR STARTCHAR uni0572 ENCODING 1394 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F8 CC CC CC CC CC CC 0C 0C 0F 00 ENDCHAR STARTCHAR uni0573 ENCODING 1395 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 18 30 F8 6C 66 66 66 66 3E 00 00 00 00 ENDCHAR STARTCHAR uni0574 ENCODING 1396 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0F 0C 0C CC CC CC CC CC CC 7C 00 00 00 00 ENDCHAR STARTCHAR uni0575 ENCODING 1397 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 0C 0C 0C 0C 0C 0C 0C 6C 38 00 ENDCHAR STARTCHAR uni0576 ENCODING 1398 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 66 66 66 66 66 66 3E 00 00 00 00 ENDCHAR STARTCHAR uni0577 ENCODING 1399 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 66 66 06 0C 18 30 60 3E 00 ENDCHAR STARTCHAR uni0578 ENCODING 1400 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR uni0579 ENCODING 1401 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 18 18 0C 06 0C 18 30 60 3E 00 ENDCHAR STARTCHAR uni057A ENCODING 1402 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 D6 D6 D6 D6 D6 D6 7E 06 06 06 00 ENDCHAR STARTCHAR uni057B ENCODING 1403 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 66 66 76 1C 18 30 60 3E 00 ENDCHAR STARTCHAR uni057C ENCODING 1404 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 F8 CC CC CC CC CC CF 00 00 00 00 ENDCHAR STARTCHAR uni057D ENCODING 1405 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 66 66 66 3E 00 00 00 00 ENDCHAR STARTCHAR uni057E ENCODING 1406 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 0C 0C CC CC CC CC CC CC 7C 0C 0C 0F 00 ENDCHAR STARTCHAR uni057F ENCODING 1407 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC D6 D6 D6 D6 D6 76 00 00 00 00 ENDCHAR STARTCHAR uni0580 ENCODING 1408 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C 66 66 66 66 66 66 60 60 60 00 ENDCHAR STARTCHAR uni0581 ENCODING 1409 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3E 66 66 66 66 66 3E 06 66 3C 00 ENDCHAR STARTCHAR uni0582 ENCODING 1410 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 30 30 30 30 30 30 3E 00 00 00 00 ENDCHAR STARTCHAR uni0583 ENCODING 1411 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 10 DC D6 D6 D6 D6 D6 76 10 10 10 00 ENDCHAR STARTCHAR uni0584 ENCODING 1412 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C 66 66 66 66 7C 60 FE 60 60 00 ENDCHAR STARTCHAR uni0585 ENCODING 1413 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni0586 ENCODING 1414 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 D0 D0 7C 16 16 16 16 D6 7C 10 10 10 00 ENDCHAR STARTCHAR uni0587 ENCODING 1415 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 C0 C0 CC CC CC CC 77 00 00 00 00 ENDCHAR STARTCHAR uni0589 ENCODING 1417 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 18 00 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni058A ENCODING 1418 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C0 C6 7C 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0591 ENCODING 1425 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 10 10 38 6C ENDCHAR STARTCHAR uni0592 ENCODING 1426 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 00 66 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0593 ENCODING 1427 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 38 10 38 20 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0594 ENCODING 1428 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0595 ENCODING 1429 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 60 6C 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0596 ENCODING 1430 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 10 18 0C 00 ENDCHAR STARTCHAR uni0597 ENCODING 1431 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 10 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0598 ENCODING 1432 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 74 D6 5C 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0599 ENCODING 1433 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 60 20 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni059A ENCODING 1434 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 03 06 03 00 ENDCHAR STARTCHAR uni059B ENCODING 1435 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 28 18 30 00 ENDCHAR STARTCHAR uni059C ENCODING 1436 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 10 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni059D ENCODING 1437 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 06 04 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni059E ENCODING 1438 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1B 36 24 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni059F ENCODING 1439 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 44 AA 6C 28 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05A0 ENCODING 1440 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 0A 0C 08 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05A1 ENCODING 1441 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 40 50 E0 80 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05A3 ENCODING 1443 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 0C 0C 3C 00 ENDCHAR STARTCHAR uni05A4 ENCODING 1444 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 30 18 00 ENDCHAR STARTCHAR uni05A5 ENCODING 1445 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 10 30 60 00 ENDCHAR STARTCHAR uni05A6 ENCODING 1446 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 24 6C D8 00 ENDCHAR STARTCHAR uni05A7 ENCODING 1447 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 30 08 30 ENDCHAR STARTCHAR uni05A8 ENCODING 1448 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 10 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05A9 ENCODING 1449 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 40 A0 60 20 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05AA ENCODING 1450 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 6C 38 10 10 ENDCHAR STARTCHAR uni05AB ENCODING 1451 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 30 18 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05AC ENCODING 1452 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 3C 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05AD ENCODING 1453 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 04 06 03 00 ENDCHAR STARTCHAR uni05AE ENCODING 1454 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 48 A8 90 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05AF ENCODING 1455 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 38 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57799 ENCODING 1456 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 00 18 00 ENDCHAR STARTCHAR afii57801 ENCODING 1457 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 DB 00 33 00 ENDCHAR STARTCHAR afii57800 ENCODING 1458 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 F6 00 06 00 ENDCHAR STARTCHAR afii57802 ENCODING 1459 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 F6 60 66 00 ENDCHAR STARTCHAR afii57793 ENCODING 1460 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 ENDCHAR STARTCHAR afii57794 ENCODING 1461 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 66 00 00 00 ENDCHAR STARTCHAR afii57795 ENCODING 1462 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 66 00 18 00 ENDCHAR STARTCHAR afii57798 ENCODING 1463 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 7E 00 00 ENDCHAR STARTCHAR afii57797 ENCODING 1464 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 7E 18 18 ENDCHAR STARTCHAR afii57806 ENCODING 1465 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 60 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57796 ENCODING 1467 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 C0 18 03 00 ENDCHAR STARTCHAR afii57807 ENCODING 1468 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 18 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57839 ENCODING 1469 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 18 18 18 ENDCHAR STARTCHAR afii57645 ENCODING 1470 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7E FC 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57841 ENCODING 1471 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57842 ENCODING 1472 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR afii57804 ENCODING 1473 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 06 06 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57803 ENCODING 1474 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57658 ENCODING 1475 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 00 00 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni05C4 ENCODING 1476 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57664 ENCODING 1488 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C6 C6 66 76 DC CC C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii57665 ENCODING 1489 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 F8 0C 0C 0C 0C 0C 0C FE 00 00 00 00 ENDCHAR STARTCHAR afii57666 ENCODING 1490 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 0C 0C 0C 0C 1C 36 E6 00 00 00 00 ENDCHAR STARTCHAR afii57667 ENCODING 1491 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 0C 0C 0C 0C 0C 0C 0C 00 00 00 00 ENDCHAR STARTCHAR afii57668 ENCODING 1492 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 06 06 06 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii57669 ENCODING 1493 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR afii57670 ENCODING 1494 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 7E 18 18 18 0C 0C 18 30 00 00 00 00 ENDCHAR STARTCHAR afii57671 ENCODING 1495 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 66 C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR afii57672 ENCODING 1496 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 CC D6 D6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii57673 ENCODING 1497 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 18 18 18 30 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57674 ENCODING 1498 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 06 06 06 0C 0C 0C 0C 0C 0C 0E 00 ENDCHAR STARTCHAR afii57675 ENCODING 1499 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 06 06 06 06 06 06 FC 00 00 00 00 ENDCHAR STARTCHAR afii57676 ENCODING 1500 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 FC 06 06 06 06 0C 18 18 00 00 00 00 ENDCHAR STARTCHAR afii57677 ENCODING 1501 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 66 C6 C6 C6 C6 C6 FE 00 00 00 00 ENDCHAR STARTCHAR afii57678 ENCODING 1502 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 DC 76 66 C6 C6 C6 C6 DE 00 00 00 00 ENDCHAR STARTCHAR afii57679 ENCODING 1503 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 0C 0C 18 18 18 18 18 18 18 1C 00 ENDCHAR STARTCHAR afii57680 ENCODING 1504 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 0C 0C 0C 0C 0C 0C 7C 00 00 00 00 ENDCHAR STARTCHAR afii57681 ENCODING 1505 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 66 C6 C6 C6 C6 CC 78 00 00 00 00 ENDCHAR STARTCHAR afii57682 ENCODING 1506 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 EE 66 66 66 66 66 2C F8 00 00 00 00 ENDCHAR STARTCHAR afii57683 ENCODING 1507 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 F8 4C CC CC EC 0C 0C 0C 0C 0C 0E 00 ENDCHAR STARTCHAR afii57684 ENCODING 1508 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 46 C6 C6 E6 06 06 FE 00 00 00 00 ENDCHAR STARTCHAR afii57685 ENCODING 1509 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 EE 66 66 6C 78 60 60 60 60 60 70 00 ENDCHAR STARTCHAR afii57686 ENCODING 1510 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 EE 66 66 34 18 0C 06 FE 00 00 00 00 ENDCHAR STARTCHAR afii57687 ENCODING 1511 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 06 06 66 64 6C 6E 60 60 60 60 00 ENDCHAR STARTCHAR afii57688 ENCODING 1512 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 06 06 06 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR afii57689 ENCODING 1513 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 D6 D6 D6 D6 D6 F6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR afii57690 ENCODING 1514 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 66 66 66 66 66 E6 E6 00 00 00 00 ENDCHAR STARTCHAR afii57716 ENCODING 1520 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 CC 66 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR afii57717 ENCODING 1521 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 CC 66 66 66 C6 06 06 06 00 00 00 00 ENDCHAR STARTCHAR afii57718 ENCODING 1522 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 CC 66 66 66 CC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05F3 ENCODING 1523 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni05F4 ENCODING 1524 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 CC 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57388 ENCODING 1548 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 10 18 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57403 ENCODING 1563 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 18 00 00 00 18 18 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57407 ENCODING 1567 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 22 20 10 08 08 00 08 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57409 ENCODING 1569 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 20 1E 20 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57410 ENCODING 1570 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 02 3C 40 10 10 10 10 10 10 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57411 ENCODING 1571 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 20 1C 20 08 08 08 08 08 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57412 ENCODING 1572 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1C 20 1C 20 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR afii57413 ENCODING 1573 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 08 08 08 08 00 18 20 1C 20 00 00 ENDCHAR STARTCHAR afii57414 ENCODING 1574 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 40 38 40 07 08 88 86 81 82 7C 00 00 00 00 ENDCHAR STARTCHAR afii57415 ENCODING 1575 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 08 08 08 08 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57416 ENCODING 1576 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 00 08 00 00 00 00 ENDCHAR STARTCHAR afii57417 ENCODING 1577 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 28 00 00 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57418 ENCODING 1578 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 14 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57419 ENCODING 1579 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57420 ENCODING 1580 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 80 88 80 41 3E 00 00 00 ENDCHAR STARTCHAR afii57421 ENCODING 1581 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR afii57422 ENCODING 1582 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 20 00 00 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR afii57423 ENCODING 1583 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57424 ENCODING 1584 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57425 ENCODING 1585 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR afii57426 ENCODING 1586 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR afii57427 ENCODING 1587 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 01 15 88 84 84 78 00 00 00 00 00 ENDCHAR STARTCHAR afii57428 ENCODING 1588 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 01 15 88 84 84 78 00 00 00 00 00 ENDCHAR STARTCHAR afii57429 ENCODING 1589 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 09 31 9E 88 88 70 00 00 00 00 00 ENDCHAR STARTCHAR afii57430 ENCODING 1590 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 09 31 9E 88 88 70 00 00 00 00 00 ENDCHAR STARTCHAR afii57431 ENCODING 1591 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 20 20 2C 32 A2 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57432 ENCODING 1592 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 20 20 2C 32 A2 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57433 ENCODING 1593 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 80 8C 70 40 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR afii57434 ENCODING 1594 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 40 00 00 70 80 8C 70 40 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR afii57440 ENCODING 1600 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57441 ENCODING 1601 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57442 ENCODING 1602 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0A 00 06 09 09 47 81 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR afii57443 ENCODING 1603 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 19 21 19 21 01 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57444 ENCODING 1604 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 02 02 02 02 02 42 82 82 84 78 00 00 00 00 00 ENDCHAR STARTCHAR afii57445 ENCODING 1605 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0C 12 12 3C 40 40 40 40 40 40 00 00 ENDCHAR STARTCHAR afii57446 ENCODING 1606 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR afii57470 ENCODING 1607 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 40 30 4E 49 39 E6 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57448 ENCODING 1608 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR afii57449 ENCODING 1609 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR afii57450 ENCODING 1610 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 81 7E 00 00 24 00 ENDCHAR STARTCHAR afii57451 ENCODING 1611 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 0C 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57452 ENCODING 1612 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 12 CA 2C 70 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57453 ENCODING 1613 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 0C 30 0C 30 00 00 ENDCHAR STARTCHAR afii57454 ENCODING 1614 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57455 ENCODING 1615 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 14 0C 08 10 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57456 ENCODING 1616 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 0C 30 00 00 ENDCHAR STARTCHAR afii57457 ENCODING 1617 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0A 2A 2C 10 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57458 ENCODING 1618 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 24 18 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0653 ENCODING 1619 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 01 7E 80 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0654 ENCODING 1620 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 10 0C 10 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0655 ENCODING 1621 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 0C 10 0C 10 ENDCHAR STARTCHAR afii57392 ENCODING 1632 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 30 78 30 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57393 ENCODING 1633 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 70 70 38 18 18 08 08 08 00 00 00 00 00 ENDCHAR STARTCHAR afii57394 ENCODING 1634 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 44 FC F8 60 30 30 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR afii57395 ENCODING 1635 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 4A FE F4 60 30 30 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR afii57396 ENCODING 1636 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 20 40 30 10 20 42 7C 38 00 00 00 00 00 ENDCHAR STARTCHAR afii57397 ENCODING 1637 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 2C 44 42 82 82 FE 7C 00 00 00 00 00 ENDCHAR STARTCHAR afii57398 ENCODING 1638 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 F8 78 08 08 08 0C 0E 06 00 00 00 00 00 ENDCHAR STARTCHAR afii57399 ENCODING 1639 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 82 C6 C6 6C 28 38 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR afii57400 ENCODING 1640 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 10 38 28 6C C6 C6 82 00 00 00 00 00 ENDCHAR STARTCHAR afii57401 ENCODING 1641 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 F8 88 F8 78 08 0C 0E 06 00 00 00 00 00 ENDCHAR STARTCHAR afii57381 ENCODING 1642 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 91 92 64 08 10 26 49 89 06 00 00 00 00 ENDCHAR STARTCHAR uni066B ENCODING 1643 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 18 18 30 30 60 60 00 00 ENDCHAR STARTCHAR uni066C ENCODING 1644 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 18 10 20 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii63167 ENCODING 1645 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 38 FE 7C 38 6C 44 00 00 00 00 00 ENDCHAR STARTCHAR uni0670 ENCODING 1648 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 10 10 10 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0671 ENCODING 1649 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 06 29 5E 00 04 04 04 04 04 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0672 ENCODING 1650 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 06 28 5E 00 04 04 04 04 04 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0673 ENCODING 1651 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 04 04 04 04 04 00 06 28 5E 00 00 00 ENDCHAR STARTCHAR uni0674 ENCODING 1652 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 07 08 07 08 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0675 ENCODING 1653 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 04 03 14 10 10 10 10 10 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0676 ENCODING 1654 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 04 03 04 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni0677 ENCODING 1655 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 23 54 33 24 40 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni0678 ENCODING 1656 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 04 03 04 00 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR afii57511 ENCODING 1657 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni067A ENCODING 1658 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 08 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni067B ENCODING 1659 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uni067C ENCODING 1660 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 14 40 81 81 7E 08 14 08 00 00 00 00 ENDCHAR STARTCHAR uni067D ENCODING 1661 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 08 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57506 ENCODING 1662 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 00 14 00 08 00 00 ENDCHAR STARTCHAR uni067F ENCODING 1663 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 14 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0680 ENCODING 1664 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 00 14 00 14 00 00 ENDCHAR STARTCHAR uni0681 ENCODING 1665 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 06 08 06 08 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR uni0682 ENCODING 1666 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 08 00 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR uni0683 ENCODING 1667 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 80 94 80 41 3E 00 00 00 ENDCHAR STARTCHAR uni0684 ENCODING 1668 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 88 80 88 41 3E 00 00 00 ENDCHAR STARTCHAR uni0685 ENCODING 1669 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR afii57507 ENCODING 1670 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 94 80 88 41 3E 00 00 00 ENDCHAR STARTCHAR uni0687 ENCODING 1671 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 94 80 94 41 3E 00 00 00 ENDCHAR STARTCHAR afii57512 ENCODING 1672 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 38 28 70 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0689 ENCODING 1673 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 04 02 42 3C 08 14 08 00 00 00 00 ENDCHAR STARTCHAR uni068A ENCODING 1674 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 04 02 42 3C 00 00 08 00 00 00 00 ENDCHAR STARTCHAR uni068B ENCODING 1675 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 38 28 70 08 04 02 42 3C 00 00 08 00 00 00 00 ENDCHAR STARTCHAR uni068C ENCODING 1676 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni068D ENCODING 1677 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 04 02 42 3C 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uni068E ENCODING 1678 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni068F ENCODING 1679 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 00 08 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni0690 ENCODING 1680 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 00 14 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57513 ENCODING 1681 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uni0692 ENCODING 1682 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 08 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uni0693 ENCODING 1683 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 02 02 04 1C 6A 04 00 00 00 00 ENDCHAR STARTCHAR uni0694 ENCODING 1684 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 02 02 04 18 62 00 00 00 00 00 ENDCHAR STARTCHAR uni0695 ENCODING 1685 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 02 02 04 18 60 00 14 08 00 00 ENDCHAR STARTCHAR uni0696 ENCODING 1686 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 02 12 04 18 62 00 00 00 00 00 ENDCHAR STARTCHAR uni0697 ENCODING 1687 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 14 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR afii57508 ENCODING 1688 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uni0699 ENCODING 1689 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 00 14 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uni069A ENCODING 1690 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 00 01 15 88 88 8A 70 00 00 00 00 00 ENDCHAR STARTCHAR uni069B ENCODING 1691 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 01 15 88 88 90 65 00 02 00 00 00 ENDCHAR STARTCHAR uni069C ENCODING 1692 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 04 00 0A 00 01 15 88 88 90 65 00 02 00 00 00 ENDCHAR STARTCHAR uni069D ENCODING 1693 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 09 31 9E 88 90 65 00 00 00 00 00 ENDCHAR STARTCHAR uni069E ENCODING 1694 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 0A 00 06 09 31 9E 88 88 70 00 00 00 00 00 ENDCHAR STARTCHAR uni069F ENCODING 1695 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 2A 20 20 2C 32 A2 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06A0 ENCODING 1696 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 00 50 00 70 80 8C 70 40 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR uni06A1 ENCODING 1697 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06A2 ENCODING 1698 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 49 85 83 7E 00 02 00 00 00 00 00 ENDCHAR STARTCHAR uni06A3 ENCODING 1699 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 49 85 83 7E 00 08 00 00 00 00 00 ENDCHAR STARTCHAR afii57505 ENCODING 1700 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 0A 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06A5 ENCODING 1701 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 49 85 83 7E 00 0A 00 04 00 00 00 ENDCHAR STARTCHAR uni06A6 ENCODING 1702 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0A 00 0A 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06A7 ENCODING 1703 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 09 09 47 81 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uni06A8 ENCODING 1704 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 0A 00 06 09 09 47 81 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uni06A9 ENCODING 1705 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 01 02 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06AA ENCODING 1706 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 20 40 3E 01 81 7E 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06AB ENCODING 1707 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 01 02 05 0B 48 84 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06AC ENCODING 1708 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 19 21 19 21 01 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06AD ENCODING 1709 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 00 29 01 19 21 19 A1 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06AE ENCODING 1710 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 19 21 19 21 01 81 7E 00 14 00 08 00 00 00 ENDCHAR STARTCHAR afii57509 ENCODING 1711 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06B0 ENCODING 1712 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 05 0B 48 84 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06B1 ENCODING 1713 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP A4 09 12 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06B2 ENCODING 1714 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 44 82 82 7C 00 14 00 00 00 00 00 ENDCHAR STARTCHAR uni06B3 ENCODING 1715 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 44 82 82 7C 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uni06B4 ENCODING 1716 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 44 09 A2 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06B5 ENCODING 1717 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 08 02 02 02 02 42 82 82 84 78 00 00 00 00 00 ENDCHAR STARTCHAR uni06B6 ENCODING 1718 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 02 02 02 02 02 42 82 82 84 78 00 00 00 00 00 ENDCHAR STARTCHAR uni06B7 ENCODING 1719 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 02 2A 02 02 02 42 82 82 84 78 00 00 00 00 00 ENDCHAR STARTCHAR uni06B8 ENCODING 1720 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 02 02 02 02 02 42 82 82 84 78 00 14 00 08 00 ENDCHAR STARTCHAR uni06B9 ENCODING 1721 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 00 00 41 81 81 81 42 3C 00 00 04 00 00 ENDCHAR STARTCHAR afii57514 ENCODING 1722 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR uni06BB ENCODING 1723 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR uni06BC ENCODING 1724 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 41 81 81 81 42 3C 08 14 08 00 00 ENDCHAR STARTCHAR uni06BD ENCODING 1725 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR uni06BE ENCODING 1726 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 38 4C 52 32 3C 40 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06BF ENCODING 1727 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 00 70 8F 30 40 94 80 88 41 3E 00 00 00 ENDCHAR STARTCHAR uni06C0 ENCODING 1728 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 40 38 40 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06C1 ENCODING 1729 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 0C 13 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06C2 ENCODING 1730 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 40 38 40 00 0C 13 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06C3 ENCODING 1731 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 14 00 00 00 0C 13 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06C4 ENCODING 1732 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 0E 12 2C 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06C5 ENCODING 1733 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 0E 02 3C 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06C6 ENCODING 1734 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 08 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06C7 ENCODING 1735 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 28 18 10 20 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06C8 ENCODING 1736 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 08 08 08 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06C9 ENCODING 1737 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 14 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06CA ENCODING 1738 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 14 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06CB ENCODING 1739 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06CC ENCODING 1740 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR uni06CD ENCODING 1741 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 20 47 88 08 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR uni06CE ENCODING 1742 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 50 20 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR uni06CF ENCODING 1743 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uni06D0 ENCODING 1744 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 82 7C 00 08 00 08 ENDCHAR STARTCHAR uni06D1 ENCODING 1745 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 82 7C 00 14 00 08 ENDCHAR STARTCHAR afii57519 ENCODING 1746 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 14 60 80 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni06D3 ENCODING 1747 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 80 60 80 08 14 60 80 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni06D4 ENCODING 1748 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 3C 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii57534 ENCODING 1749 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06D6 ENCODING 1750 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 40 40 43 55 7E 80 7C 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06D7 ENCODING 1751 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 2A 20 26 2A 7C 80 7C 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06D8 ENCODING 1752 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0E 1C 60 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06D9 ENCODING 1753 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 14 08 14 18 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06DA ENCODING 1754 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 2C 10 28 22 1C 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06DB ENCODING 1755 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06DC ENCODING 1756 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 15 8A 90 60 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06DD ENCODING 1757 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 5A A5 66 5B 81 81 81 81 81 81 5A 66 A5 5A 00 ENDCHAR STARTCHAR uni06DE ENCODING 1758 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 66 42 42 81 99 99 81 42 42 66 18 00 00 ENDCHAR STARTCHAR uni06DF ENCODING 1759 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 1C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E0 ENCODING 1760 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E1 ENCODING 1761 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 26 08 70 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E2 ENCODING 1762 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 10 10 10 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E3 ENCODING 1763 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 15 8A 90 60 ENDCHAR STARTCHAR uni06E4 ENCODING 1764 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 32 2C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E5 ENCODING 1765 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 14 0C 04 08 30 00 00 00 00 00 ENDCHAR STARTCHAR uni06E6 ENCODING 1766 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 10 30 40 3E 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E7 ENCODING 1767 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 30 40 3E 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E8 ENCODING 1768 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 22 22 1C 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06E9 ENCODING 1769 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 28 54 AA 92 54 54 54 54 54 54 54 82 FE 00 00 ENDCHAR STARTCHAR uni06EA ENCODING 1770 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 08 14 22 14 08 ENDCHAR STARTCHAR uni06EB ENCODING 1771 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 14 22 14 08 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06EC ENCODING 1772 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 3C 3C 18 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06ED ENCODING 1773 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 0C 0C 10 10 10 ENDCHAR STARTCHAR uni06F0 ENCODING 1776 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 44 44 38 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni06F1 ENCODING 1777 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 70 70 38 18 18 08 08 08 00 00 00 00 00 ENDCHAR STARTCHAR uni06F2 ENCODING 1778 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 44 FC F8 60 30 30 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni06F3 ENCODING 1779 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 4A FE F4 60 30 30 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni06F4 ENCODING 1780 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 4E F0 FE 7C 30 30 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni06F5 ENCODING 1781 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 38 2C 44 42 82 92 FE 6C 00 00 00 00 00 ENDCHAR STARTCHAR uni06F6 ENCODING 1782 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 60 7E 3C 30 60 40 80 00 00 00 00 00 ENDCHAR STARTCHAR uni06F7 ENCODING 1783 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 82 C6 C6 6C 28 38 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni06F8 ENCODING 1784 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 10 38 28 6C C6 C6 82 00 00 00 00 00 ENDCHAR STARTCHAR uni06F9 ENCODING 1785 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 F8 88 F8 78 08 0C 0E 06 00 00 00 00 00 ENDCHAR STARTCHAR uni06FA ENCODING 1786 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 01 15 88 88 88 72 00 00 00 00 00 ENDCHAR STARTCHAR uni06FB ENCODING 1787 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 09 31 9E 88 88 72 00 00 00 00 00 ENDCHAR STARTCHAR uni06FC ENCODING 1788 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 40 00 00 70 80 8C 70 40 80 88 80 41 3E 00 00 ENDCHAR STARTCHAR uni06FD ENCODING 1789 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 20 1E 20 00 14 14 14 14 00 00 ENDCHAR STARTCHAR uni06FE ENCODING 1790 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0C 12 12 3C 40 54 54 54 54 40 00 00 ENDCHAR STARTCHAR m ENCODING 4307 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C 92 92 92 92 92 4C 30 4C 02 00 ENDCHAR STARTCHAR m ENCODING 4311 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C 92 92 92 92 92 64 00 00 00 00 ENDCHAR STARTCHAR m ENCODING 4314 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 54 AA AA AA 82 82 40 30 4C 02 00 ENDCHAR STARTCHAR m ENCODING 4317 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C 92 92 92 82 82 44 00 00 00 00 ENDCHAR STARTCHAR m ENCODING 4326 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C 92 92 92 82 82 40 30 4C 02 00 ENDCHAR STARTCHAR uni1E00 ENCODING 7680 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 6C C6 C6 FE C6 C6 C6 C6 00 38 6C 38 ENDCHAR STARTCHAR uni1E01 ENCODING 7681 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 0C 7C CC CC CC 76 00 38 6C 38 ENDCHAR STARTCHAR uni1E02 ENCODING 7682 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 FC 66 66 66 7C 66 66 66 FC 00 00 00 00 ENDCHAR STARTCHAR uni1E03 ENCODING 7683 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 0C EC 60 60 78 6C 66 66 66 66 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E04 ENCODING 7684 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 66 66 66 66 FC 00 18 18 00 ENDCHAR STARTCHAR uni1E05 ENCODING 7685 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 78 6C 66 66 66 66 7C 00 18 18 00 ENDCHAR STARTCHAR uni1E06 ENCODING 7686 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 66 66 66 66 FC 00 7C 00 00 ENDCHAR STARTCHAR uni1E07 ENCODING 7687 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 78 6C 66 66 66 66 7C 00 7C 00 00 ENDCHAR STARTCHAR uni1E08 ENCODING 7688 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 3C 66 C2 C0 C0 C0 C2 66 3C 18 0C 38 00 ENDCHAR STARTCHAR uni1E09 ENCODING 7689 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 7C C6 C0 C0 C0 C6 7C 18 0C 38 00 ENDCHAR STARTCHAR uni1E0A ENCODING 7690 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 F8 6C 66 66 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR uni1E0B ENCODING 7691 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 60 0C 0C 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1E0C ENCODING 7692 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 66 66 66 66 6C F8 00 30 30 00 ENDCHAR STARTCHAR uni1E0D ENCODING 7693 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 00 30 30 00 ENDCHAR STARTCHAR uni1E0E ENCODING 7694 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 66 66 66 66 6C F8 00 7C 00 00 ENDCHAR STARTCHAR uni1E0F ENCODING 7695 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 00 7C 00 00 ENDCHAR STARTCHAR uni1E10 ENCODING 7696 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 66 66 66 66 6C F8 30 18 70 00 ENDCHAR STARTCHAR uni1E11 ENCODING 7697 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 30 18 70 00 ENDCHAR STARTCHAR uni1E12 ENCODING 7698 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 66 66 66 66 6C F8 10 38 6C 00 ENDCHAR STARTCHAR uni1E13 ENCODING 7699 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 10 38 6C 00 ENDCHAR STARTCHAR uni1E14 ENCODING 7700 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 7C 00 FE 62 68 78 68 62 FE 00 00 00 00 ENDCHAR STARTCHAR uni1E15 ENCODING 7701 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 7C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E16 ENCODING 7702 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 7C 00 FE 62 68 78 68 62 FE 00 00 00 00 ENDCHAR STARTCHAR uni1E17 ENCODING 7703 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 7C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E18 ENCODING 7704 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 10 38 6C 00 ENDCHAR STARTCHAR uni1E19 ENCODING 7705 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 10 38 6C 00 ENDCHAR STARTCHAR uni1E1A ENCODING 7706 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 00 76 DC 00 ENDCHAR STARTCHAR uni1E1B ENCODING 7707 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 00 76 DC 00 ENDCHAR STARTCHAR uni1E1C ENCODING 7708 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 FE 66 62 68 78 68 62 66 FE 18 0C 38 00 ENDCHAR STARTCHAR uni1E1D ENCODING 7709 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 7C C6 FE C0 C0 C6 7C 18 0C 38 00 ENDCHAR STARTCHAR uni1E1E ENCODING 7710 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 FE 66 62 68 78 68 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni1E1F ENCODING 7711 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 38 6C 64 F0 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni1E20 ENCODING 7712 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 3C 66 C2 C0 DE C6 C6 66 3A 00 00 00 00 ENDCHAR STARTCHAR uni1E21 ENCODING 7713 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 76 CC CC CC CC CC 7C 0C CC 78 00 ENDCHAR STARTCHAR uni1E22 ENCODING 7714 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 C6 C6 C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E23 ENCODING 7715 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C E0 60 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni1E24 ENCODING 7716 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1E25 ENCODING 7717 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 6C 76 66 66 66 66 E6 00 18 18 00 ENDCHAR STARTCHAR uni1E26 ENCODING 7718 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 C6 C6 FE C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E27 ENCODING 7719 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 E0 60 6C 76 66 66 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni1E28 ENCODING 7720 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 60 30 E0 00 ENDCHAR STARTCHAR uni1E29 ENCODING 7721 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 6C 76 66 66 66 66 E6 30 18 70 00 ENDCHAR STARTCHAR uni1E2A ENCODING 7722 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 FE C6 C6 C6 C6 C6 00 6C 38 00 ENDCHAR STARTCHAR uni1E2B ENCODING 7723 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 6C 76 66 66 66 66 E6 00 6C 38 00 ENDCHAR STARTCHAR uni1E2C ENCODING 7724 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 76 DC 00 ENDCHAR STARTCHAR uni1E2D ENCODING 7725 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 38 18 18 18 18 18 3C 00 76 DC 00 ENDCHAR STARTCHAR uni1E2E ENCODING 7726 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 66 00 3C 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1E2F ENCODING 7727 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 66 66 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1E30 ENCODING 7728 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 E6 66 66 6C 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni1E31 ENCODING 7729 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 0C EC 60 60 66 6C 78 78 6C 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni1E32 ENCODING 7730 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 18 18 00 ENDCHAR STARTCHAR uni1E33 ENCODING 7731 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 66 6C 78 78 6C 66 E6 00 18 18 00 ENDCHAR STARTCHAR uni1E34 ENCODING 7732 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 7C 00 00 ENDCHAR STARTCHAR uni1E35 ENCODING 7733 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 66 6C 78 78 6C 66 E6 00 7C 00 00 ENDCHAR STARTCHAR uni1E36 ENCODING 7734 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 60 60 60 62 66 FE 00 18 18 00 ENDCHAR STARTCHAR uni1E37 ENCODING 7735 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 3C 00 18 18 00 ENDCHAR STARTCHAR uni1E38 ENCODING 7736 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 F0 60 60 60 60 60 62 66 FE 00 18 18 00 ENDCHAR STARTCHAR uni1E39 ENCODING 7737 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 38 18 18 18 18 18 18 18 3C 00 18 18 00 ENDCHAR STARTCHAR uni1E3A ENCODING 7738 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 60 60 60 62 66 FE 00 7C 00 00 ENDCHAR STARTCHAR uni1E3B ENCODING 7739 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 3C 00 7E 00 00 ENDCHAR STARTCHAR uni1E3C ENCODING 7740 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 60 60 60 62 66 FE 10 38 6C 00 ENDCHAR STARTCHAR uni1E3D ENCODING 7741 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 3C 10 38 6C 00 ENDCHAR STARTCHAR uni1E3E ENCODING 7742 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 C6 EE FE FE D6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E3F ENCODING 7743 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 EC FE D6 D6 D6 D6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E40 ENCODING 7744 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 C6 EE FE FE D6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E41 ENCODING 7745 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 EC FE D6 D6 D6 D6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E42 ENCODING 7746 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 EE FE FE D6 C6 C6 C6 C6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1E43 ENCODING 7747 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 EC FE D6 D6 D6 D6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1E44 ENCODING 7748 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 C6 E6 F6 FE DE CE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E45 ENCODING 7749 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 DC 66 66 66 66 66 66 00 00 00 00 ENDCHAR STARTCHAR uni1E46 ENCODING 7750 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1E47 ENCODING 7751 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 00 18 18 00 ENDCHAR STARTCHAR uni1E48 ENCODING 7752 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 00 7C 00 00 ENDCHAR STARTCHAR uni1E49 ENCODING 7753 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 00 7C 00 00 ENDCHAR STARTCHAR uni1E4A ENCODING 7754 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 E6 F6 FE DE CE C6 C6 C6 C6 10 38 6C 00 ENDCHAR STARTCHAR uni1E4B ENCODING 7755 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 66 66 66 66 66 66 10 38 6C 00 ENDCHAR STARTCHAR uni1E4C ENCODING 7756 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 72 9C 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E4D ENCODING 7757 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 76 DC 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E4E ENCODING 7758 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 00 72 9C 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E4F ENCODING 7759 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 00 76 DC 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E50 ENCODING 7760 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 7C 00 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E51 ENCODING 7761 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 7C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E52 ENCODING 7762 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 7C 00 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E53 ENCODING 7763 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 7C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E54 ENCODING 7764 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 FC 66 66 66 7C 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni1E55 ENCODING 7765 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 DC 66 66 66 66 66 7C 60 60 F0 00 ENDCHAR STARTCHAR uni1E56 ENCODING 7766 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 FC 66 66 66 7C 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni1E57 ENCODING 7767 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 DC 66 66 66 66 66 7C 60 60 F0 00 ENDCHAR STARTCHAR uni1E58 ENCODING 7768 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 FC 66 66 66 7C 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni1E59 ENCODING 7769 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 DC 76 66 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni1E5A ENCODING 7770 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 6C 66 66 66 E6 00 18 18 00 ENDCHAR STARTCHAR uni1E5B ENCODING 7771 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 66 60 60 60 F0 00 18 18 00 ENDCHAR STARTCHAR uni1E5C ENCODING 7772 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 00 FC 66 66 66 7C 6C 66 66 E6 00 18 18 00 ENDCHAR STARTCHAR uni1E5D ENCODING 7773 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 00 DC 76 66 60 60 60 F0 00 18 18 00 ENDCHAR STARTCHAR uni1E5E ENCODING 7774 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 6C 66 66 66 E6 00 7C 00 00 ENDCHAR STARTCHAR uni1E5F ENCODING 7775 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 66 60 60 60 F0 00 7C 00 00 ENDCHAR STARTCHAR uni1E60 ENCODING 7776 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 7C C6 C6 60 38 0C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E61 ENCODING 7777 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E62 ENCODING 7778 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 60 38 0C 06 C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1E63 ENCODING 7779 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 60 38 0C C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1E64 ENCODING 7780 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 6C 18 00 7C C6 C6 70 1C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E65 ENCODING 7781 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 60 0C 18 00 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E66 ENCODING 7782 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 44 38 10 7C C6 C6 70 1C C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E67 ENCODING 7783 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 44 38 10 7C C6 60 38 0C C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E68 ENCODING 7784 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 7C C6 C6 60 38 0C C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1E69 ENCODING 7785 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 7C C6 60 38 0C C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1E6A ENCODING 7786 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 7E 7E 5A 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1E6B ENCODING 7787 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 06 16 30 30 FC 30 30 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR uni1E6C ENCODING 7788 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 00 18 18 00 ENDCHAR STARTCHAR uni1E6D ENCODING 7789 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 00 18 18 00 ENDCHAR STARTCHAR uni1E6E ENCODING 7790 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 00 7E 00 00 ENDCHAR STARTCHAR uni1E6F ENCODING 7791 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 00 7E 00 00 ENDCHAR STARTCHAR uni1E70 ENCODING 7792 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 18 18 18 18 18 3C 10 38 6C 00 ENDCHAR STARTCHAR uni1E71 ENCODING 7793 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 30 30 FC 30 30 30 30 36 1C 08 1C 36 00 ENDCHAR STARTCHAR uni1E72 ENCODING 7794 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 6C 6C 00 ENDCHAR STARTCHAR uni1E73 ENCODING 7795 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC 76 00 6C 6C 00 ENDCHAR STARTCHAR uni1E74 ENCODING 7796 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 76 DC 00 ENDCHAR STARTCHAR uni1E75 ENCODING 7797 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC 76 00 76 DC 00 ENDCHAR STARTCHAR uni1E76 ENCODING 7798 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 C6 C6 7C 10 38 6C 00 ENDCHAR STARTCHAR uni1E77 ENCODING 7799 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC 76 10 38 6C 00 ENDCHAR STARTCHAR uni1E78 ENCODING 7800 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 72 9C 00 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E79 ENCODING 7801 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 76 DC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1E7A ENCODING 7802 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 00 7C 00 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1E7B ENCODING 7803 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP CC CC 00 FC 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1E7C ENCODING 7804 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 C6 C6 C6 C6 C6 C6 6C 38 10 00 00 00 00 ENDCHAR STARTCHAR uni1E7D ENCODING 7805 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 66 66 66 66 66 3C 18 00 00 00 00 ENDCHAR STARTCHAR uni1E7E ENCODING 7806 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 6C 38 10 00 30 30 00 ENDCHAR STARTCHAR uni1E7F ENCODING 7807 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 66 66 3C 18 00 18 18 00 ENDCHAR STARTCHAR Wgrave ENCODING 7808 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 00 C6 C6 C6 D6 D6 D6 FE EE 6C 00 00 00 00 ENDCHAR STARTCHAR wgrave ENCODING 7809 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR Wacute ENCODING 7810 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 00 C6 C6 C6 D6 D6 D6 FE EE 6C 00 00 00 00 ENDCHAR STARTCHAR wacute ENCODING 7811 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 18 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR Wdieresis ENCODING 7812 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 C6 D6 D6 D6 FE EE 6C 00 00 00 00 ENDCHAR STARTCHAR wdieresis ENCODING 7813 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni1E86 ENCODING 7814 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 C6 C6 C6 D6 D6 D6 FE EE 6C 00 00 00 00 ENDCHAR STARTCHAR uni1E87 ENCODING 7815 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni1E88 ENCODING 7816 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 D6 D6 D6 FE EE 6C 00 30 30 00 ENDCHAR STARTCHAR uni1E89 ENCODING 7817 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 D6 D6 D6 FE 6C 00 30 30 00 ENDCHAR STARTCHAR uni1E8A ENCODING 7818 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 C6 C6 6C 7C 38 7C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E8B ENCODING 7819 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 C6 6C 38 38 38 6C C6 00 00 00 00 ENDCHAR STARTCHAR uni1E8C ENCODING 7820 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 C6 C6 6C 7C 38 7C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1E8D ENCODING 7821 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 C6 6C 38 38 38 6C C6 00 00 00 00 ENDCHAR STARTCHAR uni1E8E ENCODING 7822 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1E8F ENCODING 7823 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni1E90 ENCODING 7824 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 FE C6 8C 18 30 60 C2 C6 FE 00 00 00 00 ENDCHAR STARTCHAR uni1E91 ENCODING 7825 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 FE CC 18 30 60 C6 FE 00 00 00 00 ENDCHAR STARTCHAR uni1E92 ENCODING 7826 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 86 0C 18 30 60 C2 C6 FE 00 30 30 00 ENDCHAR STARTCHAR uni1E93 ENCODING 7827 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 30 60 C6 FE 00 30 30 00 ENDCHAR STARTCHAR uni1E94 ENCODING 7828 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 86 0C 18 30 60 C2 C6 FE 00 7C 00 00 ENDCHAR STARTCHAR uni1E95 ENCODING 7829 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE CC 18 30 60 C6 FE 00 7C 00 00 ENDCHAR STARTCHAR uni1E96 ENCODING 7830 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 60 60 6C 76 66 66 66 66 E6 00 7C 00 00 ENDCHAR STARTCHAR uni1E97 ENCODING 7831 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 6C 00 10 30 FC 30 30 30 30 36 1C 00 00 00 00 ENDCHAR STARTCHAR uni1E98 ENCODING 7832 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 38 00 C6 C6 D6 D6 D6 FE 6C 00 00 00 00 ENDCHAR STARTCHAR uni1E99 ENCODING 7833 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 6C 38 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni1E9A ENCODING 7834 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 0C 18 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1E9B ENCODING 7835 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 00 38 6C 64 60 60 60 60 60 F0 00 00 00 00 ENDCHAR STARTCHAR uni1EA0 ENCODING 7840 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 6C C6 C6 FE C6 C6 C6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1EA1 ENCODING 7841 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 78 0C 7C CC CC CC 76 00 30 30 00 ENDCHAR STARTCHAR uni1EA2 ENCODING 7842 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 0C 18 10 38 6C C6 C6 FE C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EA3 ENCODING 7843 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 0C 18 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EA4 ENCODING 7844 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 16 38 6C 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EA5 ENCODING 7845 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 16 38 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EA6 ENCODING 7846 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 68 1C 36 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EA7 ENCODING 7847 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 68 1C 36 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EA8 ENCODING 7848 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E 13 3A 6C 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EA9 ENCODING 7849 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E 13 3A 6C 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EAA ENCODING 7850 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 10 28 54 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EAB ENCODING 7851 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 10 38 44 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EAC ENCODING 7852 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 6C 10 38 6C C6 C6 FE C6 C6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1EAD ENCODING 7853 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 78 0C 7C CC CC CC 76 00 30 30 00 ENDCHAR STARTCHAR uni1EAE ENCODING 7854 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 44 38 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EAF ENCODING 7855 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 18 44 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EB0 ENCODING 7856 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 44 38 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EB1 ENCODING 7857 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 30 44 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EB2 ENCODING 7858 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 08 54 38 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EB3 ENCODING 7859 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 08 54 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EB4 ENCODING 7860 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 72 9C 44 38 10 38 6C C6 C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni1EB5 ENCODING 7861 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 72 9C 44 38 00 78 0C 7C CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EB6 ENCODING 7862 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 6C 38 00 10 38 6C C6 C6 FE C6 C6 C6 00 30 30 00 ENDCHAR STARTCHAR uni1EB7 ENCODING 7863 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 38 00 78 0C 7C CC CC CC 76 00 30 30 00 ENDCHAR STARTCHAR uni1EB8 ENCODING 7864 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 66 62 68 78 68 60 62 66 FE 00 18 18 00 ENDCHAR STARTCHAR uni1EB9 ENCODING 7865 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 FE C0 C0 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1EBA ENCODING 7866 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 0C 18 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni1EBB ENCODING 7867 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 0C 18 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EBC ENCODING 7868 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 00 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni1EBD ENCODING 7869 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EBE ENCODING 7870 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 23 76 88 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni1EBF ENCODING 7871 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 26 70 D8 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EC0 ENCODING 7872 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C4 6E 11 FE 66 62 68 78 68 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni1EC1 ENCODING 7873 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 64 0E 1B 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EC2 ENCODING 7874 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E 13 3A 6C 00 FE 62 68 78 68 62 FE 00 00 00 00 ENDCHAR STARTCHAR uni1EC3 ENCODING 7875 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E 13 3A 6C 00 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EC4 ENCODING 7876 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 10 38 44 FE 62 68 78 68 62 FE 00 00 00 00 ENDCHAR STARTCHAR uni1EC5 ENCODING 7877 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 10 38 44 7C C6 FE C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EC6 ENCODING 7878 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 FE 66 62 68 78 68 62 66 FE 00 18 18 00 ENDCHAR STARTCHAR uni1EC7 ENCODING 7879 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 7C C6 FE C0 C0 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1EC8 ENCODING 7880 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 0C 18 3C 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1EC9 ENCODING 7881 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 0C 18 00 38 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1ECA ENCODING 7882 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 18 18 00 ENDCHAR STARTCHAR uni1ECB ENCODING 7883 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 38 18 18 18 18 18 3C 00 18 18 00 ENDCHAR STARTCHAR uni1ECC ENCODING 7884 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 C6 C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1ECD ENCODING 7885 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C6 C6 C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1ECE ENCODING 7886 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 0C 18 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ECF ENCODING 7887 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 0C 18 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED0 ENCODING 7888 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 23 76 88 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED1 ENCODING 7889 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 26 70 D8 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED2 ENCODING 7890 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C4 6E 11 7C C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED3 ENCODING 7891 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 64 0E 1B 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED4 ENCODING 7892 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E 13 3A 44 7C C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED5 ENCODING 7893 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E 13 3A 6C 00 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED6 ENCODING 7894 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 10 28 44 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED7 ENCODING 7895 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 76 DC 10 38 44 7C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1ED8 ENCODING 7896 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 38 44 7C C6 C6 C6 C6 C6 C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1ED9 ENCODING 7897 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 38 6C 00 7C C6 C6 C6 C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1EDA ENCODING 7898 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 33 03 7A CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EDB ENCODING 7899 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1B 33 06 78 CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EDC ENCODING 7900 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 33 03 7A CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EDD ENCODING 7901 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 63 33 06 78 CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EDE ENCODING 7902 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 70 1B 33 7A CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EDF ENCODING 7903 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 1B 33 06 78 CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EE0 ENCODING 7904 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 68 B3 03 7A CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EE1 ENCODING 7905 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 68 B3 03 06 78 CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EE2 ENCODING 7906 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 03 7A CC CC CC CC CC CC CC CC 78 00 30 30 00 ENDCHAR STARTCHAR uni1EE3 ENCODING 7907 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 06 78 CC CC CC CC CC 78 00 30 30 00 ENDCHAR STARTCHAR uni1EE4 ENCODING 7908 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 30 30 00 ENDCHAR STARTCHAR uni1EE5 ENCODING 7909 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC CC CC CC CC CC 76 00 30 30 00 ENDCHAR STARTCHAR uni1EE6 ENCODING 7910 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 0C 18 C6 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni1EE7 ENCODING 7911 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 18 30 00 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EE8 ENCODING 7912 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 33 03 CE CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EE9 ENCODING 7913 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1B 33 06 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EEA ENCODING 7914 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 33 03 CE CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EEB ENCODING 7915 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 63 33 06 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EEC ENCODING 7916 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 70 1B 33 CE CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EED ENCODING 7917 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 1B 33 06 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EEE ENCODING 7918 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 68 B3 03 CE CC CC CC CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni1EEF ENCODING 7919 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 68 B3 03 06 CC CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1EF0 ENCODING 7920 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 03 CE CC CC CC CC CC CC CC CC 78 00 30 30 00 ENDCHAR STARTCHAR uni1EF1 ENCODING 7921 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 06 CC CC CC CC CC CC 76 00 30 30 00 ENDCHAR STARTCHAR Ygrave ENCODING 7922 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 18 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR ygrave ENCODING 7923 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 30 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni1EF4 ENCODING 7924 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 3C 18 18 18 18 3C 00 18 18 00 ENDCHAR STARTCHAR uni1EF5 ENCODING 7925 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 C6 C6 C6 C6 7E 0C 18 F6 06 00 ENDCHAR STARTCHAR uni1EF6 ENCODING 7926 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 0C 18 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1EF7 ENCODING 7927 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 0C 18 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni1EF8 ENCODING 7928 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 3A 5C 00 66 66 66 3C 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni1EF9 ENCODING 7929 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 76 DC 00 C6 C6 C6 C6 C6 C6 7E 06 0C F8 00 ENDCHAR STARTCHAR uni1F00 ENCODING 7936 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 30 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F01 ENCODING 7937 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 30 18 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F02 ENCODING 7938 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 6C C6 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F03 ENCODING 7939 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 CC 66 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F04 ENCODING 7940 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 66 CC 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F05 ENCODING 7941 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C6 6C 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F06 ENCODING 7942 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 34 58 0C 18 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni1F07 ENCODING 7943 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 34 58 30 18 00 76 CC CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni2409 ENCODING 8192 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 A4 AA EA EA A6 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8193 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 A4 EA AA AA A6 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8194 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 EA 8A CE 8E EA 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8195 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 EA 8E CA 8A EA 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8196 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 CA 2E 4A 2A CA 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8197 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 AA AE EA 2A 2A 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8198 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 6A 8E CA AA 4A 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8199 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 38 20 30 20 20 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8200 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 30 28 30 20 20 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8201 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 EA 4A 4E 4A 4A 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8202 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 28 28 38 28 28 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8203 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 EA 2A 4E 8E EE 00 6C 8A 4C 28 C8 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8204 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 EA 2A 4E 8E EE 00 A2 A2 E2 EA A4 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8205 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 EA 2A 4E 8E EE 00 08 08 08 28 10 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8206 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 80 80 80 F0 28 30 28 0A 0E 0E 0A 00 FE 00 ENDCHAR STARTCHAR uni2409 ENCODING 8207 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE 00 C0 A0 C0 A0 20 20 38 0A 0E 0E 0A 00 FE 00 ENDCHAR STARTCHAR uni2010 ENCODING 8208 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7C 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2011 ENCODING 8209 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 9C D2 BC 92 9C 00 3C 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR figuredash ENCODING 8210 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7E 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR endash ENCODING 8211 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7E 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR emdash ENCODING 8212 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR afii00208 ENCODING 8213 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2016 ENCODING 8214 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 6C 6C 6C 6C 6C 6C 6C 6C 00 00 00 00 ENDCHAR STARTCHAR underscoredbl ENCODING 8215 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 FE 00 FE 00 ENDCHAR STARTCHAR quoteleft ENCODING 8216 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 30 30 30 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR quoteright ENCODING 8217 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 18 18 30 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR quotesinglbase ENCODING 8218 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 18 18 18 30 00 00 ENDCHAR STARTCHAR quotereversed ENCODING 8219 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 30 30 18 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR quotedblleft ENCODING 8220 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 66 CC CC CC 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR quotedblright ENCODING 8221 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 66 66 66 CC 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR quotedblbase ENCODING 8222 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 66 66 66 CC 00 00 ENDCHAR STARTCHAR uni201F ENCODING 8223 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 CC CC CC 66 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR dagger ENCODING 8224 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 7E 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR daggerdbl ENCODING 8225 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 7E 18 18 7E 18 18 18 00 00 00 00 ENDCHAR STARTCHAR bullet ENCODING 8226 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 18 3C 3C 18 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2023 ENCODING 8227 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 20 30 38 3C 38 30 20 00 00 00 00 00 ENDCHAR STARTCHAR onedotenleader ENCODING 8228 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR twodotenleader ENCODING 8229 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 66 66 00 00 00 00 ENDCHAR STARTCHAR ellipsis ENCODING 8230 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 DB DB 00 00 00 00 ENDCHAR STARTCHAR uni2027 ENCODING 8231 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 18 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR perthousand ENCODING 8240 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C6 0C 18 30 60 C0 36 36 00 00 00 00 ENDCHAR STARTCHAR uni2031 ENCODING 8241 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C6 0C 18 30 60 C0 6B 6B 00 00 00 00 ENDCHAR STARTCHAR minute ENCODING 8242 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 10 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR second ENCODING 8243 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 48 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2034 ENCODING 8244 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB 92 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2035 ENCODING 8245 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 08 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2036 ENCODING 8246 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 24 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2037 ENCODING 8247 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB 49 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2038 ENCODING 8248 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 10 38 6C C6 00 ENDCHAR STARTCHAR guilsinglleft ENCODING 8249 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0C 18 30 60 30 18 0C 00 00 00 00 00 ENDCHAR STARTCHAR guilsinglright ENCODING 8250 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 60 30 18 0C 18 30 60 00 00 00 00 00 ENDCHAR STARTCHAR uni203B ENCODING 8251 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 92 44 28 92 28 44 92 00 00 00 00 00 ENDCHAR STARTCHAR exclamdbl ENCODING 8252 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 66 66 66 66 66 00 66 66 00 00 00 00 ENDCHAR STARTCHAR uni203D ENCODING 8253 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E C3 DB 1B 1E 1C 18 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni203E ENCODING 8254 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 FE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni203F ENCODING 8255 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 82 7C 00 00 ENDCHAR STARTCHAR uni2040 ENCODING 8256 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 7C 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2041 ENCODING 8257 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 06 0C 18 38 6C 00 ENDCHAR STARTCHAR uni2042 ENCODING 8258 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 38 28 00 00 44 EE AA 00 00 00 00 00 ENDCHAR STARTCHAR uni2043 ENCODING 8259 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 3C 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR fraction ENCODING 8260 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 06 0C 0C 18 18 30 30 60 60 00 00 00 00 ENDCHAR STARTCHAR uni2045 ENCODING 8261 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 30 30 30 3C 30 30 30 30 3C 00 00 00 00 ENDCHAR STARTCHAR uni2046 ENCODING 8262 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 0C 0C 0C 3C 0C 0C 0C 0C 3C 00 00 00 00 ENDCHAR STARTCHAR uni2048 ENCODING 8264 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7B CF CF 1B 33 33 33 00 33 33 00 00 00 00 ENDCHAR STARTCHAR uni2049 ENCODING 8265 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DE F3 F3 C6 CC CC CC 00 CC CC 00 00 00 00 ENDCHAR STARTCHAR uni204A ENCODING 8266 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7E 7E 06 06 0C 0C 00 00 00 ENDCHAR STARTCHAR uni204B ENCODING 8267 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE DB DB DB DE D8 D8 D8 D8 D8 00 00 00 00 ENDCHAR STARTCHAR uni204C ENCODING 8268 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 3E 72 F2 F2 F2 72 3E 00 00 00 00 00 ENDCHAR STARTCHAR uni204D ENCODING 8269 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 F8 9C 9E 9E 9E 9C F8 00 00 00 00 00 ENDCHAR STARTCHAR zerosuperior ENCODING 8304 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D8 D8 D8 D8 70 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR foursuperior ENCODING 8308 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 18 38 78 D8 FC 18 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR fivesuperior ENCODING 8309 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 F8 C0 F0 18 D8 70 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR sixsuperior ENCODING 8310 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 78 C0 F0 D8 D8 70 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR sevensuperior ENCODING 8311 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 F8 D8 30 30 60 60 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR eightsuperior ENCODING 8312 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D8 70 D8 D8 70 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR ninesuperior ENCODING 8313 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D8 D8 78 18 F0 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni207A ENCODING 8314 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 30 FC 30 30 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni207B ENCODING 8315 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FC 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni207C ENCODING 8316 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 00 FC 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR parenleftsuperior ENCODING 8317 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 60 60 60 60 30 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR parenrightsuperior ENCODING 8318 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 60 30 30 30 30 60 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR nsuperior ENCODING 8319 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 B0 D8 D8 D8 D8 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR zeroinferior ENCODING 8320 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 70 D8 D8 D8 D8 70 00 00 00 ENDCHAR STARTCHAR oneinferior ENCODING 8321 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 30 70 30 30 30 78 00 00 00 ENDCHAR STARTCHAR twoinferior ENCODING 8322 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 70 D8 30 60 C8 F8 00 00 00 ENDCHAR STARTCHAR threeinferior ENCODING 8323 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 70 D8 30 18 D8 70 00 00 00 ENDCHAR STARTCHAR fourinferior ENCODING 8324 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 18 38 78 D8 FC 18 00 00 00 ENDCHAR STARTCHAR fiveinferior ENCODING 8325 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 F8 C0 F0 18 D8 70 00 00 00 ENDCHAR STARTCHAR sixinferior ENCODING 8326 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 78 C0 F0 D8 D8 70 00 00 00 ENDCHAR STARTCHAR seveninferior ENCODING 8327 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 F8 D8 30 30 60 60 00 00 00 ENDCHAR STARTCHAR eightinferior ENCODING 8328 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 70 D8 70 D8 D8 70 00 00 00 ENDCHAR STARTCHAR nineinferior ENCODING 8329 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 70 D8 D8 78 18 F0 00 00 00 ENDCHAR STARTCHAR uni208A ENCODING 8330 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 30 30 FC 30 30 00 00 00 00 ENDCHAR STARTCHAR uni208B ENCODING 8331 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 FC 00 00 00 00 00 00 ENDCHAR STARTCHAR uni208C ENCODING 8332 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 FC 00 FC 00 00 00 00 00 ENDCHAR STARTCHAR parenleftinferior ENCODING 8333 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 30 60 60 60 60 30 00 00 00 ENDCHAR STARTCHAR parenrightinferior ENCODING 8334 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 60 30 30 30 30 60 00 00 00 ENDCHAR STARTCHAR uni208F ENCODING 8335 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 B0 D8 D8 D8 D8 00 00 00 ENDCHAR STARTCHAR uni20A0 ENCODING 8352 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC C0 CF CC CC 7F 0C 0C 0F 00 00 00 00 ENDCHAR STARTCHAR colonmonetary ENCODING 8353 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 04 7C CE C8 C8 D0 D0 D0 E0 E6 7C 40 40 00 00 ENDCHAR STARTCHAR uni20A2 ENCODING 8354 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C0 C0 D6 D8 D8 D8 DE 7C 00 00 00 00 ENDCHAR STARTCHAR franc ENCODING 8355 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 C0 C0 C0 F0 CD CE CC CC CC 00 00 00 00 ENDCHAR STARTCHAR lira ENCODING 8356 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 60 F8 60 F8 60 60 E6 FC 00 00 00 00 ENDCHAR STARTCHAR uni20A5 ENCODING 8357 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 02 EC D6 DE D6 D6 F6 D6 40 00 00 00 ENDCHAR STARTCHAR uni20A6 ENCODING 8358 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 66 76 FF 76 6E FF 6E 66 66 00 00 00 00 ENDCHAR STARTCHAR peseta ENCODING 8359 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 7C 62 66 6F 66 66 F3 00 00 00 00 ENDCHAR STARTCHAR uni20A8 ENCODING 8360 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 CC CC CC F8 E0 F3 D6 DB CE 00 00 00 00 ENDCHAR STARTCHAR uni20A9 ENCODING 8361 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 81 81 81 5A FF 5A FF 24 24 24 00 00 00 00 ENDCHAR STARTCHAR afii57636 ENCODING 8362 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 F2 8A AA AA AA AA A2 BC 00 00 00 00 ENDCHAR STARTCHAR dong ENCODING 8363 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 3E 0C 3C 6C CC CC CC CC 76 00 7C 00 00 ENDCHAR STARTCHAR Euro ENCODING 8364 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 36 60 FC 60 F8 60 60 36 1C 00 00 00 00 ENDCHAR STARTCHAR uni20AD ENCODING 8365 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 6C 78 FE 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni20AE ENCODING 8366 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 7E 5A 18 1E 78 1E 78 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni20AF ENCODING 8367 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 7C B6 36 33 33 33 63 66 F6 DC 00 00 00 00 ENDCHAR STARTCHAR uni2100 ENCODING 8448 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D0 D2 D6 7C 18 30 6E D8 98 18 0E 00 00 00 ENDCHAR STARTCHAR uni2101 ENCODING 8449 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 D0 D2 D6 7C 18 30 6E D8 8C 06 1C 00 00 00 ENDCHAR STARTCHAR uni2102 ENCODING 8450 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 62 A0 A0 A0 A0 A0 A0 62 3C 00 00 00 00 ENDCHAR STARTCHAR uni2103 ENCODING 8451 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 4E B9 58 18 18 18 18 18 19 0E 00 00 00 00 ENDCHAR STARTCHAR uni2104 ENCODING 8452 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 7C DA D8 D8 DA 7C 19 3F 00 00 00 00 ENDCHAR STARTCHAR afii61248 ENCODING 8453 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 C0 C2 C6 7C 18 30 6E DB 9B 1B 0E 00 00 00 ENDCHAR STARTCHAR uni2106 ENCODING 8454 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 70 C0 C2 C6 7C 18 30 7B DB 9B 1B 0D 00 00 00 ENDCHAR STARTCHAR uni2107 ENCODING 8455 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C2 C0 78 C0 C0 C2 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni2108 ENCODING 8456 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC 86 26 3E 26 06 86 CC 78 00 00 00 00 ENDCHAR STARTCHAR uni2109 ENCODING 8457 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7F B9 58 1A 1E 1A 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni210A ENCODING 8458 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 1A 66 46 87 8C 8C 7C 98 98 70 00 ENDCHAR STARTCHAR uni210B ENCODING 8459 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 52 B5 15 16 2C 34 68 A9 AA 4C 00 00 00 00 ENDCHAR STARTCHAR uni210C ENCODING 8460 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 48 B0 80 48 7C 66 26 26 A6 46 06 34 48 00 ENDCHAR STARTCHAR uni210D ENCODING 8461 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E2 A2 A2 A2 BE A2 A2 A2 A2 E2 00 00 00 00 ENDCHAR STARTCHAR uni210E ENCODING 8462 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 36 3B 3B 33 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni210F ENCODING 8463 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 1E 18 76 3B 3B 33 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni2110 ENCODING 8464 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 33 4E 06 06 0C 0C 1F 6C 88 70 00 00 00 00 ENDCHAR STARTCHAR Ifraktur ENCODING 8465 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 71 8E 04 0C 06 03 63 C3 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni2112 ENCODING 8466 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 46 49 39 1E 18 30 70 B1 BA 6C 00 00 00 00 ENDCHAR STARTCHAR afii61289 ENCODING 8467 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 19 31 32 64 68 70 E1 66 38 00 00 00 00 ENDCHAR STARTCHAR uni2114 ENCODING 8468 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D8 FF D8 DE DB DB DB DB DB DE 00 00 00 00 ENDCHAR STARTCHAR uni2115 ENCODING 8469 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E2 A2 B2 B2 AA AA A6 A6 A2 E2 00 00 00 00 ENDCHAR STARTCHAR afii61352 ENCODING 8470 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 CC CF ED FF FC DF CC CC CC CC 00 00 00 00 ENDCHAR STARTCHAR uni2117 ENCODING 8471 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 B9 A5 A5 B9 A1 A1 42 3C 00 00 00 00 ENDCHAR STARTCHAR weierstrass ENCODING 8472 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 40 8E 93 A3 63 4B 6A A4 B0 B0 60 00 ENDCHAR STARTCHAR uni2119 ENCODING 8473 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC A2 A2 A2 A2 BC A0 A0 A0 E0 00 00 00 00 ENDCHAR STARTCHAR uni211A ENCODING 8474 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C A2 A2 A2 A2 A2 A2 AA A6 7E 01 00 00 00 ENDCHAR STARTCHAR uni211B ENCODING 8475 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 4D 4D 19 1E 1C 34 34 B5 62 00 00 00 00 ENDCHAR STARTCHAR Rfraktur ENCODING 8476 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 58 A6 A3 6C B8 26 26 26 A7 C2 00 00 00 00 ENDCHAR STARTCHAR uni211D ENCODING 8477 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC A2 A2 A2 A2 BC B0 A8 A4 E2 00 00 00 00 ENDCHAR STARTCHAR prescription ENCODING 8478 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FC 66 66 66 7C 6C 6D 67 66 EE 08 00 00 00 ENDCHAR STARTCHAR uni211F ENCODING 8479 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 0C FC C6 C6 C6 FC D8 DC DC E6 E6 20 00 00 00 ENDCHAR STARTCHAR uni2120 ENCODING 8480 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 71 DB 35 D1 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2121 ENCODING 8481 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FE 52 5A 52 5F 00 00 00 00 ENDCHAR STARTCHAR trademark ENCODING 8482 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F1 5B 55 51 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2123 ENCODING 8483 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 18 CE D6 D6 D6 D6 D6 E6 6C 38 50 40 00 00 00 ENDCHAR STARTCHAR uni2124 ENCODING 8484 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 0A 14 14 28 28 50 50 A0 FE 00 00 00 00 ENDCHAR STARTCHAR uni2125 ENCODING 8485 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 9C 30 FE 0C 18 38 0C 06 06 C6 C6 7C 00 ENDCHAR STARTCHAR Omega ENCODING 8486 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C C6 C6 C6 C6 C6 6C 6C 6C EE 00 00 00 00 ENDCHAR STARTCHAR uni2127 ENCODING 8487 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 EE 6C 6C 6C C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni2128 ENCODING 8488 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 26 03 13 0C 13 03 03 66 98 00 00 00 00 ENDCHAR STARTCHAR uni2129 ENCODING 8489 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 18 18 18 18 1C 18 00 00 00 00 ENDCHAR STARTCHAR uni212A ENCODING 8490 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E6 66 66 6C 78 78 6C 66 66 E6 00 00 00 00 ENDCHAR STARTCHAR uni212B ENCODING 8491 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 6C 38 10 38 38 6C 6C C6 FE C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni212C ENCODING 8492 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 2D 2D 1A 1E 1B 31 31 B2 6C 00 00 00 00 ENDCHAR STARTCHAR uni212D ENCODING 8493 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 14 6B C8 CC C6 C6 CC C0 63 1C 00 00 00 00 ENDCHAR STARTCHAR estimated ENCODING 8494 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 E7 FF E0 67 3E 00 00 00 00 ENDCHAR STARTCHAR uni212F ENCODING 8495 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 1C 26 44 F8 C0 C8 70 00 00 00 00 ENDCHAR STARTCHAR uni2130 ENCODING 8496 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 4C 52 3C 10 3C 60 C0 C3 CC 78 00 00 00 00 ENDCHAR STARTCHAR uni2131 ENCODING 8497 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 73 CE 18 3A 5C 18 30 30 B0 60 00 00 00 00 ENDCHAR STARTCHAR uni2132 ENCODING 8498 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 0C 0C 0C 2C 3C 2C 8C CC FE 00 00 00 00 ENDCHAR STARTCHAR uni2133 ENCODING 8499 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 12 12 12 16 36 3E 3A 5A 52 91 00 00 00 00 ENDCHAR STARTCHAR uni2134 ENCODING 8500 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 1C 26 46 C6 C4 C8 70 00 00 00 00 ENDCHAR STARTCHAR aleph ENCODING 8501 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 42 C6 E7 7A 38 5C CE E7 63 E2 00 00 00 00 ENDCHAR STARTCHAR uni2136 ENCODING 8502 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 FC 7E 06 06 06 06 0C 7E FE 00 00 00 00 ENDCHAR STARTCHAR uni2137 ENCODING 8503 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 40 78 3C 0C 0C 0C 0C 1E 7E F2 00 00 00 00 ENDCHAR STARTCHAR uni2138 ENCODING 8504 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 FE 7E 0C 0C 0C 0C 0C 1C 18 00 00 00 00 ENDCHAR STARTCHAR uni2139 ENCODING 8505 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 38 00 78 38 38 38 38 38 7C 00 00 00 00 ENDCHAR STARTCHAR uni213A ENCODING 8506 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7D FF 83 86 82 FE 7C 00 00 00 00 ENDCHAR STARTCHAR onethird ENCODING 8531 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 60 DC 86 1C 06 1C 00 00 ENDCHAR STARTCHAR twothirds ENCODING 8532 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 30 62 C6 FC 18 30 60 DC 86 1C 06 1C 00 00 ENDCHAR STARTCHAR uni2155 ENCODING 8533 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 60 DE 98 1C 06 1C 00 00 ENDCHAR STARTCHAR uni2156 ENCODING 8534 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 30 62 C6 FC 18 30 60 DE 98 1C 06 1C 00 00 ENDCHAR STARTCHAR uni2157 ENCODING 8535 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 30 62 36 EC 18 30 60 DE 98 1C 06 1C 00 00 ENDCHAR STARTCHAR uni2158 ENCODING 8536 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 70 B2 F6 3C 18 30 60 DE 98 1C 06 1C 00 00 ENDCHAR STARTCHAR uni2159 ENCODING 8537 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 60 DC B0 3C 36 1C 00 00 ENDCHAR STARTCHAR uni215A ENCODING 8538 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 F0 C0 E2 36 EC 18 30 60 DC B0 3C 36 1C 00 00 ENDCHAR STARTCHAR oneeighth ENCODING 8539 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 60 DC B6 1C 36 1C 00 00 ENDCHAR STARTCHAR threeeighths ENCODING 8540 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 30 62 36 EC 18 30 60 DC B6 1C 36 1C 00 00 ENDCHAR STARTCHAR fiveeighths ENCODING 8541 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 F0 80 E2 36 EC 18 30 60 DC B6 1C 36 1C 00 00 ENDCHAR STARTCHAR seveneighths ENCODING 8542 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 F0 30 62 66 6C 18 30 60 DC B6 1C 36 1C 00 00 ENDCHAR STARTCHAR uni215F ENCODING 8543 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 C2 C6 CC 18 30 60 C0 80 00 00 00 00 00 ENDCHAR STARTCHAR uni2160 ENCODING 8544 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni2161 ENCODING 8545 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 6C 6C 6C 6C 6C 6C 6C 6C FE 00 00 00 00 ENDCHAR STARTCHAR uni2162 ENCODING 8546 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF DB DB DB DB DB DB DB DB FF 00 00 00 00 ENDCHAR STARTCHAR uni2163 ENCODING 8547 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB DB DB DB DB DB CE CE C4 00 00 00 00 ENDCHAR STARTCHAR uni2164 ENCODING 8548 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 C6 C6 C6 C6 C6 6C 38 10 00 00 00 00 ENDCHAR STARTCHAR uni2165 ENCODING 8549 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB DB DB DB DB DB 73 73 23 00 00 00 00 ENDCHAR STARTCHAR uni2166 ENCODING 8550 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 95 95 95 95 95 95 95 65 65 65 00 00 00 00 ENDCHAR STARTCHAR uni2167 ENCODING 8551 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 B5 B5 B5 B5 B5 B5 55 55 55 55 00 00 00 00 ENDCHAR STARTCHAR uni2168 ENCODING 8552 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB DB CE CE CE DB DB DB DB 00 00 00 00 ENDCHAR STARTCHAR uni2169 ENCODING 8553 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 6C 7C 38 38 7C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni216A ENCODING 8554 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB DB 73 73 73 DB DB DB DB 00 00 00 00 ENDCHAR STARTCHAR uni216B ENCODING 8555 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 95 95 95 65 65 65 95 95 95 95 00 00 00 00 ENDCHAR STARTCHAR uni216C ENCODING 8556 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 60 60 60 60 60 60 62 66 FE 00 00 00 00 ENDCHAR STARTCHAR uni216D ENCODING 8557 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 C2 C0 C0 C0 C0 C2 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni216E ENCODING 8558 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 6C 66 66 66 66 66 66 6C F8 00 00 00 00 ENDCHAR STARTCHAR uni216F ENCODING 8559 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 EE FE FE D6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni2170 ENCODING 8560 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2171 ENCODING 8561 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 00 6C 6C 6C 6C 6C 6C 6C 00 00 00 00 ENDCHAR STARTCHAR uni2172 ENCODING 8562 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 DB DB 00 DB DB DB DB DB DB DB 00 00 00 00 ENDCHAR STARTCHAR uni2173 ENCODING 8563 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 00 DB DB DB DB DB CE C4 00 00 00 00 ENDCHAR STARTCHAR uni2174 ENCODING 8564 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 66 66 66 3C 18 00 00 00 00 ENDCHAR STARTCHAR uni2175 ENCODING 8565 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 00 DB DB DB DB DB 73 23 00 00 00 00 ENDCHAR STARTCHAR uni2176 ENCODING 8566 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 05 05 00 95 95 95 95 95 65 65 00 00 00 00 ENDCHAR STARTCHAR uni2177 ENCODING 8567 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 15 15 00 B5 B5 B5 B5 55 55 55 00 00 00 00 ENDCHAR STARTCHAR uni2178 ENCODING 8568 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 00 DB DB CE CE CE DB DB 00 00 00 00 ENDCHAR STARTCHAR uni2179 ENCODING 8569 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 6C 38 38 38 6C C6 00 00 00 00 ENDCHAR STARTCHAR uni217A ENCODING 8570 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 00 DB DB 73 73 73 DB DB 00 00 00 00 ENDCHAR STARTCHAR uni217B ENCODING 8571 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 05 05 00 95 95 65 65 95 95 95 00 00 00 00 ENDCHAR STARTCHAR uni217C ENCODING 8572 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 18 18 18 18 18 18 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni217D ENCODING 8573 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 7C C6 C0 C0 C0 C6 7C 00 00 00 00 ENDCHAR STARTCHAR uni217E ENCODING 8574 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 0C 0C 3C 6C CC CC CC CC 76 00 00 00 00 ENDCHAR STARTCHAR uni217F ENCODING 8575 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 EC FE D6 D6 D6 D6 C6 00 00 00 00 ENDCHAR STARTCHAR uni2180 ENCODING 8576 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 5A DB DB DB DB DB DB 5A 3C 00 00 00 00 ENDCHAR STARTCHAR uni2181 ENCODING 8577 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 CC E6 D6 D6 D6 D6 E6 CC F8 00 00 00 00 ENDCHAR STARTCHAR uni2182 ENCODING 8578 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 5A 99 BD DB DB BD 99 5A 3C 00 00 00 00 ENDCHAR STARTCHAR uni2183 ENCODING 8579 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 CC 86 06 06 06 06 86 CC 78 00 00 00 00 ENDCHAR STARTCHAR arrowleft ENCODING 8592 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 30 60 FF 60 30 00 00 00 00 00 00 ENDCHAR STARTCHAR arrowup ENCODING 8593 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 7E 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR arrowright ENCODING 8594 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 06 FF 06 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR arrowdown ENCODING 8595 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 7E 3C 18 00 00 00 00 ENDCHAR STARTCHAR arrowboth ENCODING 8596 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 24 66 FF 66 24 00 00 00 00 00 00 ENDCHAR STARTCHAR arrowupdn ENCODING 8597 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 7E 18 18 18 7E 3C 18 00 00 00 00 00 ENDCHAR STARTCHAR uni2196 ENCODING 8598 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 F0 E0 B0 18 0C 06 03 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2197 ENCODING 8599 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 0F 07 0D 18 30 60 C0 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2198 ENCODING 8600 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C0 60 30 18 0D 07 0F 00 00 00 00 00 ENDCHAR STARTCHAR uni2199 ENCODING 8601 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 03 06 0C 18 B0 E0 F0 00 00 00 00 00 ENDCHAR STARTCHAR uni219A ENCODING 8602 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 32 62 FF 64 34 00 00 00 00 00 00 ENDCHAR STARTCHAR uni219B ENCODING 8603 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 2C 26 FF 46 4C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni219C ENCODING 8604 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 E0 CE BB 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni219D ENCODING 8605 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 07 73 DD 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni219E ENCODING 8606 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 36 6C FF 6C 36 00 00 00 00 00 00 ENDCHAR STARTCHAR uni219F ENCODING 8607 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 7E 18 3C 7E 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni21A0 ENCODING 8608 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 6C 36 FF 36 6C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21A1 ENCODING 8609 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 7E 3C 18 7E 3C 18 00 00 00 00 ENDCHAR STARTCHAR uni21A2 ENCODING 8610 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 33 66 FC 66 33 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21A3 ENCODING 8611 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC 66 3F 66 CC 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21A4 ENCODING 8612 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 33 63 FF 63 33 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21A5 ENCODING 8613 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 7E 18 18 18 18 18 18 7E 00 00 00 00 ENDCHAR STARTCHAR uni21A6 ENCODING 8614 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 CC C6 FF C6 CC 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21A7 ENCODING 8615 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 18 18 18 18 18 18 7E 3C 18 00 00 00 00 ENDCHAR STARTCHAR arrowupdnbse ENCODING 8616 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 7E 18 18 18 7E 3C 18 7E 00 00 00 00 ENDCHAR STARTCHAR uni21A9 ENCODING 8617 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 33 63 FE 60 30 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21AA ENCODING 8618 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 60 CC C6 7F 06 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21AB ENCODING 8619 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 3B 6B FE 68 30 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21AC ENCODING 8620 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 60 DC D6 7F 16 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21AD ENCODING 8621 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 24 5A FF 66 24 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21AE ENCODING 8622 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 2C 6E FF 76 34 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21AF ENCODING 8623 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 30 60 63 FF C6 16 1C 1C 1E 00 00 00 00 ENDCHAR STARTCHAR uni21B0 ENCODING 8624 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 30 60 FE 66 36 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni21B1 ENCODING 8625 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 0C FE CC D8 C0 C0 C0 C0 00 00 00 00 ENDCHAR STARTCHAR uni21B2 ENCODING 8626 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 06 06 06 06 36 66 FE 60 30 00 00 00 00 ENDCHAR STARTCHAR uni21B3 ENCODING 8627 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C0 C0 C0 D8 CC FE 0C 18 00 00 00 00 ENDCHAR STARTCHAR uni21B4 ENCODING 8628 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FC 0C 0C 3F 1E 0C 00 00 00 ENDCHAR STARTCHAR carriagereturn ENCODING 8629 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 06 36 66 FE 60 30 00 00 00 00 ENDCHAR STARTCHAR uni21B6 ENCODING 8630 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 1E 33 33 33 30 FC 78 30 00 00 00 00 ENDCHAR STARTCHAR uni21B7 ENCODING 8631 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 78 CC CC CC 0C 3F 1E 0C 00 00 00 00 ENDCHAR STARTCHAR uni21B8 ENCODING 8632 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 00 F0 E0 B0 18 0C 06 03 00 00 00 00 00 ENDCHAR STARTCHAR uni21B9 ENCODING 8633 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 98 B0 FF B0 98 19 0D FF 0D 19 00 00 00 00 ENDCHAR STARTCHAR uni21BA ENCODING 8634 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 1E 1C 16 03 C3 C3 C3 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni21BB ENCODING 8635 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 78 38 68 C0 C3 C3 C3 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni21BC ENCODING 8636 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 30 60 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21BD ENCODING 8637 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 60 30 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21BE ENCODING 8638 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 1C 1E 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni21BF ENCODING 8639 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 38 78 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni21C0 ENCODING 8640 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 06 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21C1 ENCODING 8641 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 06 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21C2 ENCODING 8642 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 1E 1C 18 00 00 00 00 ENDCHAR STARTCHAR uni21C3 ENCODING 8643 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 78 38 18 00 00 00 00 ENDCHAR STARTCHAR uni21C4 ENCODING 8644 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 06 FF 06 0C 30 60 FF 60 30 00 00 00 00 ENDCHAR STARTCHAR uni21C5 ENCODING 8645 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 2E 3F 24 24 24 24 FC 74 24 00 00 00 00 ENDCHAR STARTCHAR uni21C6 ENCODING 8646 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 60 FF 60 30 0C 06 FF 06 0C 00 00 00 00 ENDCHAR STARTCHAR uni21C7 ENCODING 8647 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 60 FE 60 30 00 30 60 FE 60 30 00 00 00 ENDCHAR STARTCHAR uni21C8 ENCODING 8648 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 7E FF 24 24 24 24 24 24 24 00 00 00 00 ENDCHAR STARTCHAR uni21C9 ENCODING 8649 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 0C FE 0C 18 00 18 0C FE 0C 18 00 00 00 ENDCHAR STARTCHAR uni21CA ENCODING 8650 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 24 24 24 24 24 24 FF 7E 24 00 00 00 00 ENDCHAR STARTCHAR uni21CB ENCODING 8651 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 30 60 FF 00 FF 06 0C 00 00 00 00 00 ENDCHAR STARTCHAR uni21CC ENCODING 8652 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0C 06 FF 00 FF 60 30 00 00 00 00 00 ENDCHAR STARTCHAR uni21CD ENCODING 8653 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 22 7F C4 7F 24 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21CE ENCODING 8654 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 2C 7E CB 7E 34 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21CF ENCODING 8655 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 24 FE 23 FE 44 00 00 00 00 00 00 ENDCHAR STARTCHAR arrowdblleft ENCODING 8656 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 20 7F C0 7F 20 00 00 00 00 00 00 ENDCHAR STARTCHAR arrowdblup ENCODING 8657 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 7C EE 6C 6C 6C 6C 6C 6C 6C 00 00 00 00 ENDCHAR STARTCHAR arrowdblright ENCODING 8658 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 FE 03 FE 04 00 00 00 00 00 00 ENDCHAR STARTCHAR arrowdbldown ENCODING 8659 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 6C 6C 6C 6C 6C EE 7C 38 00 00 00 00 ENDCHAR STARTCHAR arrowdblboth ENCODING 8660 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 24 7E C3 7E 24 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21D5 ENCODING 8661 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 7C EE 6C 6C 6C 6C EE 7C 38 00 00 00 00 ENDCHAR STARTCHAR uni21D6 ENCODING 8662 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 F0 E0 B0 D8 EC B6 1B 0C 04 00 00 00 00 ENDCHAR STARTCHAR uni21D7 ENCODING 8663 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 0F 07 0D 1B 37 6D D8 30 20 00 00 00 00 ENDCHAR STARTCHAR uni21D8 ENCODING 8664 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 20 30 D8 6D 37 1B 0D 07 0F 00 00 00 00 ENDCHAR STARTCHAR uni21D9 ENCODING 8665 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 0C 1B B6 EC D8 B0 E0 F0 00 00 00 00 ENDCHAR STARTCHAR uni21DA ENCODING 8666 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 3F 60 FF 60 3F 10 00 00 00 00 00 ENDCHAR STARTCHAR uni21DB ENCODING 8667 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 FC 06 FF 06 FC 08 00 00 00 00 00 ENDCHAR STARTCHAR uni21DC ENCODING 8668 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 30 6A FF 65 30 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21DD ENCODING 8669 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C A6 FF 56 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21DE ENCODING 8670 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 7E 18 18 3C 18 3C 18 18 00 00 00 00 ENDCHAR STARTCHAR uni21DF ENCODING 8671 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 3C 18 3C 18 18 7E 3C 18 00 00 00 00 ENDCHAR STARTCHAR uni21E0 ENCODING 8672 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 30 60 D5 60 30 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21E1 ENCODING 8673 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C 66 18 00 18 00 18 00 18 00 00 00 00 ENDCHAR STARTCHAR uni21E2 ENCODING 8674 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 06 AB 06 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21E3 ENCODING 8675 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 00 18 00 18 00 18 66 3C 18 00 00 00 00 ENDCHAR STARTCHAR uni21E4 ENCODING 8676 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 98 B0 FF B0 98 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21E5 ENCODING 8677 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 19 0D FF 0D 19 00 00 00 00 00 00 ENDCHAR STARTCHAR uni21E6 ENCODING 8678 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 3F 41 81 41 3F 10 00 00 00 00 00 ENDCHAR STARTCHAR uni21E7 ENCODING 8679 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 C6 44 44 44 44 44 7C 00 00 00 00 ENDCHAR STARTCHAR uni21E8 ENCODING 8680 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 FC 82 81 82 FC 08 00 00 00 00 00 ENDCHAR STARTCHAR uni21E9 ENCODING 8681 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C 44 44 44 44 44 C6 44 28 10 00 00 00 00 ENDCHAR STARTCHAR uni21EA ENCODING 8682 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 C6 44 44 7C 00 7C 44 7C 00 00 00 ENDCHAR STARTCHAR uni21EB ENCODING 8683 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 C6 44 44 44 C6 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni21EC ENCODING 8684 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 7C C6 44 44 44 C6 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni21ED ENCODING 8685 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 54 D6 54 54 54 D6 92 FE 00 00 00 00 ENDCHAR STARTCHAR uni21EE ENCODING 8686 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 28 54 EE 44 C6 44 44 44 44 7C 00 00 00 00 ENDCHAR STARTCHAR uni21EF ENCODING 8687 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 28 54 EE 44 C6 44 44 C6 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni21F0 ENCODING 8688 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 E8 BC 82 81 82 BC E8 00 00 00 00 00 ENDCHAR STARTCHAR uni21F1 ENCODING 8689 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 80 BC B8 AC 86 83 81 80 00 00 00 00 00 ENDCHAR STARTCHAR uni21F2 ENCODING 8690 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 01 81 C1 61 35 1D 3D 01 FF 00 00 00 00 ENDCHAR STARTCHAR uni21F3 ENCODING 8691 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 C6 44 44 44 C6 44 28 10 00 00 00 ENDCHAR STARTCHAR universal ENCODING 8704 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 FE C6 6C 6C 38 38 10 10 00 00 00 00 ENDCHAR STARTCHAR uni2201 ENCODING 8705 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 60 60 60 60 60 66 3C 00 00 ENDCHAR STARTCHAR partialdiff ENCODING 8706 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 06 06 3E 66 C6 C6 CC 78 00 00 00 00 ENDCHAR STARTCHAR existential ENCODING 8707 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 06 06 06 7E 06 06 06 06 FE 00 00 00 00 ENDCHAR STARTCHAR uni2204 ENCODING 8708 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 FE 16 16 16 7E 16 26 26 26 FE 40 00 00 00 ENDCHAR STARTCHAR emptyset ENCODING 8709 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 3E 66 CF DB DB F3 66 7C C0 00 00 00 00 ENDCHAR STARTCHAR Delta ENCODING 8710 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 38 38 6C 6C C6 C6 C6 FE 00 00 00 00 ENDCHAR STARTCHAR gradient ENCODING 8711 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 C6 C6 6C 6C 38 38 10 10 00 00 00 00 ENDCHAR STARTCHAR element ENCODING 8712 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 3E 60 C0 C0 FE C0 C0 60 3E 00 00 00 00 ENDCHAR STARTCHAR notelement ENCODING 8713 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 3E 64 C8 C8 FE C8 D0 70 3E 20 00 00 00 ENDCHAR STARTCHAR uni220A ENCODING 8714 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 3E 60 C0 FE C0 60 3E 00 00 00 00 00 ENDCHAR STARTCHAR suchthat ENCODING 8715 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 F8 0C 06 06 FE 06 06 0C F8 00 00 00 00 ENDCHAR STARTCHAR uni220C ENCODING 8716 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 F8 1C 16 26 FE 26 26 4C F8 40 00 00 00 ENDCHAR STARTCHAR uni220D ENCODING 8717 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 F8 0C 06 FE 06 0C F8 00 00 00 00 00 ENDCHAR STARTCHAR uni220E ENCODING 8718 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 7E 7E 7E 7E 7E 7E 7E 00 00 00 00 00 ENDCHAR STARTCHAR product ENCODING 8719 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 66 66 66 66 66 66 66 66 66 66 E7 00 00 ENDCHAR STARTCHAR uni2210 ENCODING 8720 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E7 66 66 66 66 66 66 66 66 66 66 FF 00 00 ENDCHAR STARTCHAR summation ENCODING 8721 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF C1 60 30 18 0C 0C 18 30 60 C1 FF 00 00 ENDCHAR STARTCHAR minus ENCODING 8722 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7E 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2213 ENCODING 8723 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 7E 00 18 18 7E 18 18 00 00 00 00 00 ENDCHAR STARTCHAR uni2214 ENCODING 8724 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 18 00 18 18 7E 18 18 00 00 00 00 00 ENDCHAR STARTCHAR fraction ENCODING 8725 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 06 06 0C 0C 18 18 30 30 60 60 C0 C0 00 00 00 ENDCHAR STARTCHAR uni2216 ENCODING 8726 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 C0 60 60 30 30 18 18 0C 0C 06 06 00 00 00 ENDCHAR STARTCHAR asteriskmath ENCODING 8727 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 24 18 7E 18 24 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2218 ENCODING 8728 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 24 24 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR periodcentered ENCODING 8729 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 3C 3C 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR radical ENCODING 8730 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 06 06 06 0C CC 6C 38 18 00 00 00 00 ENDCHAR STARTCHAR uni221B ENCODING 8731 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E3 33 66 36 E6 0C CC 6C 38 18 00 00 00 00 ENDCHAR STARTCHAR uni221C ENCODING 8732 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 33 73 B6 F6 36 0C CC 6C 38 18 00 00 00 00 ENDCHAR STARTCHAR proportional ENCODING 8733 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 D8 D8 6E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR infinity ENCODING 8734 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 DB DB 6E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR orthogonal ENCODING 8735 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 C0 C0 C0 C0 C0 FE 00 00 00 00 ENDCHAR STARTCHAR angle ENCODING 8736 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 02 06 0C 18 30 60 FF 00 00 00 00 ENDCHAR STARTCHAR uni2221 ENCODING 8737 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 02 16 0C 1C 34 62 FF 02 00 00 00 ENDCHAR STARTCHAR uni2222 ENCODING 8738 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 0E 38 E8 38 0E 10 00 00 00 00 00 ENDCHAR STARTCHAR uni2223 ENCODING 8739 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2224 ENCODING 8740 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 1A 1C 38 58 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2225 ENCODING 8741 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 6C 6C 6C 6C 6C 6C 6C 6C 00 00 00 00 ENDCHAR STARTCHAR uni2226 ENCODING 8742 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6C 6C 6C 6E 7C EC 6C 6C 6C 6C 00 00 00 00 ENDCHAR STARTCHAR logicaland ENCODING 8743 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 10 38 38 6C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR logicalor ENCODING 8744 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C6 C6 6C 6C 38 38 10 10 00 00 00 00 ENDCHAR STARTCHAR intersection ENCODING 8745 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 7C C6 C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR union ENCODING 8746 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C6 C6 C6 C6 C6 C6 C6 7C 00 00 00 00 ENDCHAR STARTCHAR integral ENCODING 8747 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 1A 18 18 18 18 18 18 18 18 18 18 58 30 00 00 ENDCHAR STARTCHAR uni222C ENCODING 8748 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 33 66 66 66 66 66 66 66 66 66 66 66 66 CC 00 00 ENDCHAR STARTCHAR uni222D ENCODING 8749 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 2A 54 54 54 54 54 54 54 54 54 54 54 54 A8 00 00 ENDCHAR STARTCHAR uni222E ENCODING 8750 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 1A 18 18 3C 5A 99 99 5A 3C 18 18 58 30 00 00 ENDCHAR STARTCHAR uni222F ENCODING 8751 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 33 66 66 66 7E E7 E7 E7 E7 7E 66 66 66 CC 00 00 ENDCHAR STARTCHAR uni2230 ENCODING 8752 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 2A 54 54 54 7C D6 D6 D6 D6 7C 54 54 54 A8 00 00 ENDCHAR STARTCHAR uni2231 ENCODING 8753 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 34 30 30 38 35 33 37 30 30 30 30 B0 60 00 00 ENDCHAR STARTCHAR uni2232 ENCODING 8754 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 1A 18 18 3C 5A FA 5A 5A 3C 18 18 58 30 00 00 ENDCHAR STARTCHAR uni2233 ENCODING 8755 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 1A 18 18 3C 5A 5F 5A 5A 3C 18 18 58 30 00 00 ENDCHAR STARTCHAR therefore ENCODING 8756 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 18 00 00 00 66 66 00 00 00 00 ENDCHAR STARTCHAR uni2235 ENCODING 8757 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 00 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2236 ENCODING 8758 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 18 00 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2237 ENCODING 8759 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 66 66 00 00 00 66 66 00 00 00 00 ENDCHAR STARTCHAR uni2238 ENCODING 8760 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 18 00 7E 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2239 ENCODING 8761 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 03 03 00 FC 00 03 03 00 00 00 00 00 ENDCHAR STARTCHAR uni223A ENCODING 8762 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 66 66 00 7E 00 66 66 00 00 00 00 00 ENDCHAR STARTCHAR uni223B ENCODING 8763 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 18 00 76 DC 00 30 30 00 00 00 00 00 ENDCHAR STARTCHAR similar ENCODING 8764 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 76 DC 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni223D ENCODING 8765 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 DC 76 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni223E ENCODING 8766 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 72 DB DB 4E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni223F ENCODING 8767 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 D8 DB DB 1B 0E 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2240 ENCODING 8768 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 1C 30 30 30 18 0C 0C 0C 38 00 00 00 00 ENDCHAR STARTCHAR uni2241 ENCODING 8769 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 10 76 DC 10 20 20 00 00 00 00 00 ENDCHAR STARTCHAR uni2242 ENCODING 8770 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FE 00 76 DC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2243 ENCODING 8771 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 DC 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2244 ENCODING 8772 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 76 DC 10 FE 20 20 00 00 00 00 00 ENDCHAR STARTCHAR congruent ENCODING 8773 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 76 DC 00 FE 00 FE 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2246 ENCODING 8774 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 76 DC 08 FE 10 FE 20 00 00 00 00 00 ENDCHAR STARTCHAR uni2247 ENCODING 8775 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 08 76 DC 10 FE 20 FE 40 40 00 00 00 00 ENDCHAR STARTCHAR approxequal ENCODING 8776 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 76 DC 00 76 DC 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2249 ENCODING 8777 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 76 DC 10 76 DC 20 20 00 00 00 00 ENDCHAR STARTCHAR uni224A ENCODING 8778 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 76 DC 00 76 DC 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni224B ENCODING 8779 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 76 DC 00 76 DC 00 76 DC 00 00 00 00 00 ENDCHAR STARTCHAR uni224C ENCODING 8780 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 DC 76 00 FE 00 FE 00 00 00 00 00 00 ENDCHAR STARTCHAR uni224D ENCODING 8781 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C6 7C 00 7C C6 00 00 00 00 00 00 ENDCHAR STARTCHAR uni224E ENCODING 8782 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 66 00 00 66 18 00 00 00 00 00 00 ENDCHAR STARTCHAR uni224F ENCODING 8783 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 66 00 00 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2250 ENCODING 8784 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 7E 00 00 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2251 ENCODING 8785 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 7E 00 00 7E 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2252 ENCODING 8786 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 60 00 7E 00 00 7E 00 06 06 00 00 00 00 ENDCHAR STARTCHAR uni2253 ENCODING 8787 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 06 00 7E 00 00 7E 00 60 60 00 00 00 00 ENDCHAR STARTCHAR uni2254 ENCODING 8788 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C0 DF 00 00 DF C0 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2255 ENCODING 8789 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 03 FB 00 00 FB 03 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2256 ENCODING 8790 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FE 28 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2257 ENCODING 8791 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 10 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2258 ENCODING 8792 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 44 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2259 ENCODING 8793 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni225A ENCODING 8794 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 44 28 10 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni225B ENCODING 8795 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 10 7C 28 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni225C ENCODING 8796 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 10 28 44 7C 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni225D ENCODING 8797 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 26 7C B4 6C 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni225E ENCODING 8798 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 68 54 54 00 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni225F ENCODING 8799 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 08 10 00 10 FE 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR notequal ENCODING 8800 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 08 7E 08 10 7E 10 20 00 00 00 00 00 ENDCHAR STARTCHAR equivalence ENCODING 8801 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 00 00 FE 00 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni2262 ENCODING 8802 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 08 FE 08 10 FE 10 20 FE 20 40 00 00 00 ENDCHAR STARTCHAR uni2263 ENCODING 8803 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 00 00 FE 00 00 FE 00 00 FE 00 00 00 00 ENDCHAR STARTCHAR lessequal ENCODING 8804 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0E 38 E0 38 0E 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR greaterequal ENCODING 8805 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 E0 38 0E 38 E0 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni2266 ENCODING 8806 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 0E 38 E0 38 0E 00 FE 00 FE 00 00 00 00 ENDCHAR STARTCHAR uni2267 ENCODING 8807 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 E0 38 0E 38 E0 00 FE 00 FE 00 00 00 00 ENDCHAR STARTCHAR uni2268 ENCODING 8808 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 0E 38 E0 38 0E 08 FE 10 FE 20 00 00 00 ENDCHAR STARTCHAR uni2269 ENCODING 8809 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 E0 38 0E 38 E0 08 FE 10 FE 20 00 00 00 ENDCHAR STARTCHAR uni226A ENCODING 8810 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 1B 36 6C D8 6C 36 1B 00 00 00 00 00 ENDCHAR STARTCHAR uni226B ENCODING 8811 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 D8 6C 36 1B 36 6C D8 00 00 00 00 00 ENDCHAR STARTCHAR uni226C ENCODING 8812 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 66 18 3C 66 66 66 66 3C 18 66 00 00 00 00 ENDCHAR STARTCHAR uni226D ENCODING 8813 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 CE 7C 10 7C E6 20 00 00 00 00 00 ENDCHAR STARTCHAR uni226E ENCODING 8814 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 04 0E 38 E8 38 0E 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni226F ENCODING 8815 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 E0 38 2E 38 E0 40 40 00 00 00 00 00 ENDCHAR STARTCHAR uni2270 ENCODING 8816 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 04 0E 38 E8 38 0E 10 FE 10 00 00 00 00 ENDCHAR STARTCHAR uni2271 ENCODING 8817 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 E0 38 2E 38 E0 40 FE 40 00 00 00 00 ENDCHAR STARTCHAR uni2272 ENCODING 8818 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0E 38 E0 38 0E 00 76 DC 00 00 00 00 ENDCHAR STARTCHAR uni2273 ENCODING 8819 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 E0 38 0E 38 E0 00 76 DC 00 00 00 00 ENDCHAR STARTCHAR uni2274 ENCODING 8820 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 04 0E 38 E8 38 0E 10 76 DC 20 20 00 00 ENDCHAR STARTCHAR uni2275 ENCODING 8821 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 E0 38 2E 38 E0 40 76 DC 80 00 00 00 ENDCHAR STARTCHAR uni2276 ENCODING 8822 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 38 E0 38 0E E0 38 0E 38 E0 00 00 00 00 ENDCHAR STARTCHAR uni2277 ENCODING 8823 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 E0 38 0E 38 E0 0E 38 E0 38 0E 00 00 00 00 ENDCHAR STARTCHAR uni2278 ENCODING 8824 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 0E 38 E8 38 1E F0 38 2E 38 E0 20 00 00 00 ENDCHAR STARTCHAR uni2279 ENCODING 8825 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 E8 38 0E 38 F0 1E 38 E0 38 2E 20 00 00 00 ENDCHAR STARTCHAR uni227A ENCODING 8826 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 02 06 1C F0 1C 06 02 00 00 00 00 00 00 ENDCHAR STARTCHAR uni227B ENCODING 8827 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 80 C0 70 1E 70 C0 80 00 00 00 00 00 00 ENDCHAR STARTCHAR uni227C ENCODING 8828 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 02 06 1C F0 1C 06 F2 1C 06 02 00 00 00 00 ENDCHAR STARTCHAR uni227D ENCODING 8829 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 C0 70 1E 70 C0 9E 70 C0 80 00 00 00 00 ENDCHAR STARTCHAR uni227E ENCODING 8830 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 02 06 1C F0 1C 06 02 00 76 DC 00 00 00 00 ENDCHAR STARTCHAR uni227F ENCODING 8831 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 C0 70 1E 70 C0 80 00 76 DC 00 00 00 00 ENDCHAR STARTCHAR uni2280 ENCODING 8832 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 06 0C 38 E8 38 1C 16 10 00 00 00 00 00 ENDCHAR STARTCHAR uni2281 ENCODING 8833 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 D0 70 38 2E 38 60 C0 40 00 00 00 00 00 ENDCHAR STARTCHAR propersubset ENCODING 8834 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 7E C0 C0 C0 C0 7E 00 00 00 00 00 00 ENDCHAR STARTCHAR propersuperset ENCODING 8835 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FC 06 06 06 06 FC 00 00 00 00 00 00 ENDCHAR STARTCHAR notsubset ENCODING 8836 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 7E C8 C8 D0 D0 7E 20 00 00 00 00 00 ENDCHAR STARTCHAR uni2285 ENCODING 8837 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 FC 16 16 26 26 FC 40 00 00 00 00 00 ENDCHAR STARTCHAR reflexsubset ENCODING 8838 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7E C0 C0 C0 C0 7E 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR reflexsuperset ENCODING 8839 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FC 06 06 06 06 FC 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni2288 ENCODING 8840 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 7E C8 C8 D0 D0 7E 20 FE 40 00 00 00 00 ENDCHAR STARTCHAR uni2289 ENCODING 8841 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 FC 16 16 26 26 FC 40 FE 80 00 00 00 00 ENDCHAR STARTCHAR uni228A ENCODING 8842 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7E C0 C0 C0 C0 7E 08 FE 10 00 00 00 00 ENDCHAR STARTCHAR uni228B ENCODING 8843 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FC 06 06 06 06 FC 10 FE 20 00 00 00 00 ENDCHAR STARTCHAR uni228C ENCODING 8844 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 82 92 A2 FA A2 92 44 38 00 00 00 00 ENDCHAR STARTCHAR uni228D ENCODING 8845 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 82 82 92 BA BA 92 44 38 00 00 00 00 ENDCHAR STARTCHAR uni228E ENCODING 8846 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 82 82 92 BA 92 82 44 38 00 00 00 00 ENDCHAR STARTCHAR uni228F ENCODING 8847 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE C0 C0 C0 C0 FE 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2290 ENCODING 8848 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 06 06 06 06 FE 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2291 ENCODING 8849 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE C0 C0 C0 C0 FE 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni2292 ENCODING 8850 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 06 06 06 06 FE 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni2293 ENCODING 8851 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE C6 C6 C6 C6 C6 C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni2294 ENCODING 8852 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C6 C6 C6 C6 C6 C6 C6 FE 00 00 00 00 ENDCHAR STARTCHAR circleplus ENCODING 8853 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 54 92 FE 92 54 38 00 00 00 00 00 ENDCHAR STARTCHAR uni2296 ENCODING 8854 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 82 FE 82 44 38 00 00 00 00 00 ENDCHAR STARTCHAR circlemultiply ENCODING 8855 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 AA 92 AA 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni2298 ENCODING 8856 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 8A 92 A2 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni2299 ENCODING 8857 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 92 BA 92 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni229A ENCODING 8858 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 92 AA 92 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni229B ENCODING 8859 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 54 D6 BA D6 54 38 00 00 00 00 00 ENDCHAR STARTCHAR uni229C ENCODING 8860 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 BA 82 BA 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni229D ENCODING 8861 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 82 BA 82 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni229E ENCODING 8862 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 92 92 FE 92 92 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni229F ENCODING 8863 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 82 82 FE 82 82 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni22A0 ENCODING 8864 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE C6 AA 92 AA C6 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni22A1 ENCODING 8865 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 82 92 BA 92 82 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni22A2 ENCODING 8866 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C0 C0 C0 FF C0 C0 C0 C0 00 00 00 00 ENDCHAR STARTCHAR uni22A3 ENCODING 8867 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 03 03 03 03 FF 03 03 03 03 00 00 00 00 ENDCHAR STARTCHAR uni22A4 ENCODING 8868 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 18 18 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR perpendicular ENCODING 8869 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 18 18 FF 00 00 00 00 ENDCHAR STARTCHAR uni22A6 ENCODING 8870 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 60 60 60 60 7E 60 60 60 60 00 00 00 00 ENDCHAR STARTCHAR uni22A7 ENCODING 8871 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 60 60 60 7E 60 7E 60 60 60 00 00 00 00 ENDCHAR STARTCHAR uni22A8 ENCODING 8872 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C0 C0 FF C0 FF C0 C0 C0 00 00 00 00 ENDCHAR STARTCHAR uni22A9 ENCODING 8873 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 D8 D8 D8 D8 DF D8 D8 D8 D8 00 00 00 00 ENDCHAR STARTCHAR uni22AA ENCODING 8874 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 A8 A8 A8 A8 AF A8 A8 A8 A8 00 00 00 00 ENDCHAR STARTCHAR uni22AB ENCODING 8875 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 D8 D8 D8 DF D8 DF D8 D8 D8 00 00 00 00 ENDCHAR STARTCHAR uni22AC ENCODING 8876 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C2 C4 C4 FF C8 C8 D0 C0 00 00 00 00 ENDCHAR STARTCHAR uni22AD ENCODING 8877 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 C4 C4 FF C8 FF D0 D0 C0 00 00 00 00 ENDCHAR STARTCHAR uni22AE ENCODING 8878 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 D8 D9 DA DA DF DA DA DC D8 00 00 00 00 ENDCHAR STARTCHAR uni22AF ENCODING 8879 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 D8 D9 DA DF DA DF DA DC D8 00 00 00 00 ENDCHAR STARTCHAR uni22B0 ENCODING 8880 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 0C 06 1C F0 1C 06 0C 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B1 ENCODING 8881 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 60 C0 70 1E 70 C0 60 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B2 ENCODING 8882 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 06 1E 76 C6 76 1E 06 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B3 ENCODING 8883 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C0 F0 DC C6 DC F0 C0 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B4 ENCODING 8884 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 1E 76 C6 76 1E 06 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni22B5 ENCODING 8885 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 F0 DC C6 DC F0 C0 00 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni22B6 ENCODING 8886 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 42 BF 42 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B7 ENCODING 8887 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 42 FD 42 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B8 ENCODING 8888 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 02 7D 02 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22B9 ENCODING 8889 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 10 00 C6 00 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni22BA ENCODING 8890 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 18 18 18 18 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni22BB ENCODING 8891 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C6 C6 6C 6C 38 38 10 10 00 FE 00 00 00 00 ENDCHAR STARTCHAR uni22BC ENCODING 8892 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 00 10 10 38 38 6C 6C C6 C6 00 00 00 00 ENDCHAR STARTCHAR uni22BD ENCODING 8893 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 00 C6 C6 6C 6C 38 38 10 10 00 00 00 00 ENDCHAR STARTCHAR uni22BE ENCODING 8894 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 C0 C0 C0 F0 C8 C4 C4 FF 00 00 00 00 ENDCHAR STARTCHAR uni22BF ENCODING 8895 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 03 07 0B 13 23 43 83 FF 00 00 00 00 ENDCHAR STARTCHAR uni22C0 ENCODING 8896 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 38 38 6C 6C C6 C6 00 00 00 00 00 ENDCHAR STARTCHAR uni22C1 ENCODING 8897 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C6 C6 6C 6C 38 38 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni22C2 ENCODING 8898 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 6C C6 C6 C6 C6 C6 C6 00 00 00 00 00 ENDCHAR STARTCHAR uni22C3 ENCODING 8899 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C6 C6 C6 C6 C6 C6 6C 38 00 00 00 00 00 ENDCHAR STARTCHAR uni22C4 ENCODING 8900 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 38 6C 38 10 00 00 00 00 00 00 ENDCHAR STARTCHAR dotmath ENCODING 8901 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 18 18 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22C6 ENCODING 8902 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 10 7C 38 28 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22C7 ENCODING 8903 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 92 44 28 92 28 44 92 00 00 00 00 00 ENDCHAR STARTCHAR uni22C8 ENCODING 8904 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 82 C6 AA 92 AA C6 82 00 00 00 00 00 ENDCHAR STARTCHAR uni22C9 ENCODING 8905 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 82 C4 A8 90 A8 C4 82 00 00 00 00 00 ENDCHAR STARTCHAR uni22CA ENCODING 8906 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 82 46 2A 12 2A 46 82 00 00 00 00 00 ENDCHAR STARTCHAR uni22CB ENCODING 8907 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 80 40 20 10 28 44 82 00 00 00 00 00 ENDCHAR STARTCHAR uni22CC ENCODING 8908 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 02 04 08 10 28 44 82 00 00 00 00 00 ENDCHAR STARTCHAR uni22CD ENCODING 8909 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 DC 76 00 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22CE ENCODING 8910 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 10 38 38 6C 6C C6 00 00 00 00 00 ENDCHAR STARTCHAR uni22CF ENCODING 8911 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C6 6C 6C 38 38 10 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uni22D0 ENCODING 8912 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 3E 60 CE D8 D8 CE 60 3E 00 00 00 00 00 ENDCHAR STARTCHAR uni22D1 ENCODING 8913 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 F8 0C E6 36 36 E6 0C F8 00 00 00 00 00 ENDCHAR STARTCHAR uni22D2 ENCODING 8914 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 44 92 AA AA AA AA AA 00 00 00 00 00 ENDCHAR STARTCHAR uni22D3 ENCODING 8915 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 AA AA AA AA AA 92 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni22D4 ENCODING 8916 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 10 38 54 92 92 92 92 92 92 00 00 00 00 ENDCHAR STARTCHAR uni22D5 ENCODING 8917 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 7E 18 18 7E 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni22D6 ENCODING 8918 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 30 64 CE 64 30 18 00 00 00 00 00 ENDCHAR STARTCHAR uni22D7 ENCODING 8919 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 30 18 4C E6 4C 18 30 00 00 00 00 00 ENDCHAR STARTCHAR uni22D8 ENCODING 8920 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 15 2A 54 A8 54 2A 15 00 00 00 00 00 ENDCHAR STARTCHAR uni22D9 ENCODING 8921 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 A8 54 2A 15 2A 54 A8 00 00 00 00 00 ENDCHAR STARTCHAR uni22DA ENCODING 8922 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 0E 38 E0 38 0E 00 FE 00 E0 38 0E 38 E0 00 00 ENDCHAR STARTCHAR uni22DB ENCODING 8923 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 38 0E 38 E0 00 FE 00 0E 38 E0 38 0E 00 00 ENDCHAR STARTCHAR uni22DC ENCODING 8924 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 00 0E 38 E0 38 0E 00 00 00 00 00 ENDCHAR STARTCHAR uni22DD ENCODING 8925 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 00 E0 38 0E 38 E0 00 00 00 00 00 ENDCHAR STARTCHAR uni22DE ENCODING 8926 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 02 06 1C F2 06 1C F0 1C 06 02 00 00 00 00 ENDCHAR STARTCHAR uni22DF ENCODING 8927 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 C0 70 9E C0 70 1E 70 C0 80 00 00 00 00 ENDCHAR STARTCHAR uni22E0 ENCODING 8928 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0A 0E 1C F0 1C 16 F2 1C 26 22 00 00 00 00 ENDCHAR STARTCHAR uni22E1 ENCODING 8929 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 88 C8 70 1E 70 D0 9E 70 E0 A0 00 00 00 00 ENDCHAR STARTCHAR uni22E2 ENCODING 8930 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 FE C8 C8 D0 D0 FE 20 FE 40 00 00 00 00 ENDCHAR STARTCHAR uni22E3 ENCODING 8931 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 FE 16 16 26 26 FE 40 FE 80 00 00 00 00 ENDCHAR STARTCHAR uni22E4 ENCODING 8932 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE C0 C0 C0 C0 FE 08 FE 10 00 00 00 00 ENDCHAR STARTCHAR uni22E5 ENCODING 8933 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 06 06 06 06 FE 10 FE 20 00 00 00 00 ENDCHAR STARTCHAR uni22E6 ENCODING 8934 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0E 38 E0 38 0E 10 76 DC 10 00 00 00 ENDCHAR STARTCHAR uni22E7 ENCODING 8935 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 E0 38 0E 38 E0 10 76 DC 10 00 00 00 ENDCHAR STARTCHAR uni22E8 ENCODING 8936 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 02 06 1C F0 1C 06 02 10 76 DC 10 00 00 00 ENDCHAR STARTCHAR uni22E9 ENCODING 8937 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 80 C0 70 1E 70 C0 80 10 76 DC 10 00 00 00 ENDCHAR STARTCHAR uni22EA ENCODING 8938 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 0E 1E 76 D6 76 1E 26 20 00 00 00 00 00 ENDCHAR STARTCHAR uni22EB ENCODING 8939 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 C8 F0 DC D6 DC F0 E0 20 00 00 00 00 00 ENDCHAR STARTCHAR uni22EC ENCODING 8940 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 0E 1E 76 D6 76 1E 26 20 FE 40 00 00 00 00 ENDCHAR STARTCHAR uni22ED ENCODING 8941 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 C8 F0 DC D6 DC F0 E0 20 FE 40 00 00 00 00 ENDCHAR STARTCHAR uni22EE ENCODING 8942 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 00 00 18 18 00 00 18 18 00 00 00 00 ENDCHAR STARTCHAR uni22EF ENCODING 8943 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 DB DB 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni22F0 ENCODING 8944 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 03 03 00 00 18 18 00 00 C0 C0 00 00 00 00 ENDCHAR STARTCHAR uni22F1 ENCODING 8945 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 00 00 18 18 00 00 03 03 00 00 00 00 ENDCHAR STARTCHAR emptyset ENCODING 8960 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 3D 66 C7 CB D3 E3 66 BC 00 00 00 00 ENDCHAR STARTCHAR house ENCODING 8962 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 38 6C C6 C6 C6 FE 00 00 00 00 00 ENDCHAR STARTCHAR uni2308 ENCODING 8968 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2309 ENCODING 8969 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni230A ENCODING 8970 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 1E 00 00 00 00 ENDCHAR STARTCHAR uni230B ENCODING 8971 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 78 00 00 00 00 ENDCHAR STARTCHAR revlogicalnot ENCODING 8976 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FE C0 C0 C0 C0 00 00 00 00 00 ENDCHAR STARTCHAR uni2318 ENCODING 8984 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 42 A5 7E 24 24 7E A5 42 00 00 00 00 00 ENDCHAR STARTCHAR circleplus ENCODING 8986 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 38 54 8A F6 82 54 38 38 00 00 00 00 ENDCHAR STARTCHAR H ENCODING 8987 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 FE FE 44 44 28 10 28 44 44 FE FE 00 00 00 00 ENDCHAR STARTCHAR integraltp ENCODING 8992 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0E 1B 1B 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR integralbt ENCODING 8993 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 D8 D8 D8 70 00 00 00 00 ENDCHAR STARTCHAR angleleft ENCODING 9001 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 18 18 30 30 60 60 30 30 18 18 0C 0C 00 00 ENDCHAR STARTCHAR angleright ENCODING 9002 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 60 30 30 18 18 0C 0C 18 18 30 30 60 60 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9115 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 03 06 0C 0C 18 18 18 30 30 30 30 30 30 30 30 ENDCHAR STARTCHAR SF110000 ENCODING 9116 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 ENDCHAR STARTCHAR SF110000 ENCODING 9117 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 30 30 30 30 30 18 18 18 0C 0C 06 03 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9118 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 C0 60 30 30 18 18 18 0C 0C 0C 0C 0C 0C 0C 0C ENDCHAR STARTCHAR SF110000 ENCODING 9119 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C ENDCHAR STARTCHAR SF110000 ENCODING 9120 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 0C 0C 0C 0C 0C 18 18 18 30 30 60 C0 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9121 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 3F 30 30 30 30 30 30 30 30 30 30 30 30 30 30 ENDCHAR STARTCHAR SF110000 ENCODING 9122 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 ENDCHAR STARTCHAR SF110000 ENCODING 9123 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 30 30 30 30 30 30 30 30 30 30 30 30 3F 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9124 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 FC 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C ENDCHAR STARTCHAR SF110000 ENCODING 9125 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C ENDCHAR STARTCHAR SF110000 ENCODING 9126 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C FC 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9127 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 07 0C 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF110000 ENCODING 9128 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 30 E0 30 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF110000 ENCODING 9129 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 18 0C 07 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9130 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF110000 ENCODING 9131 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 E0 30 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF110000 ENCODING 9132 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 0C 07 0C 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF110000 ENCODING 9133 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 18 30 E0 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9134 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF100000 ENCODING 9135 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9136 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 07 0C 18 18 18 18 18 18 18 18 18 18 18 18 30 E0 ENDCHAR STARTCHAR SF110000 ENCODING 9137 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP E0 30 18 18 18 18 18 18 18 18 18 18 18 18 0C 07 ENDCHAR STARTCHAR summation ENCODING 9138 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF C1 C0 60 60 60 60 30 30 30 30 18 18 18 ENDCHAR STARTCHAR summation ENCODING 9139 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 30 30 30 30 60 60 60 60 C0 C1 FF 00 00 ENDCHAR STARTCHAR uni2423 ENCODING 9140 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF C3 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2423 ENCODING 9141 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 C3 FF 00 00 00 00 ENDCHAR STARTCHAR uni2423 ENCODING 9142 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 C3 FF 00 FF C3 00 00 00 00 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9143 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 D8 D8 78 78 38 38 18 18 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9144 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR SF110000 ENCODING 9145 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 ENDCHAR STARTCHAR SF100000 ENCODING 9146 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF100000 ENCODING 9147 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF100000 ENCODING 9148 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 ENDCHAR STARTCHAR SF100000 ENCODING 9149 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 ENDCHAR STARTCHAR carriagereturn ENCODING 9166 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 07 05 05 05 05 25 79 C2 7C 20 00 00 00 00 ENDCHAR STARTCHAR uni2409 ENCODING 9225 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D8 D8 F8 D8 D8 0F 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni240A ENCODING 9226 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 C0 F0 0F 0C 0E 0C 0C 00 00 00 00 ENDCHAR STARTCHAR uni240B ENCODING 9227 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D8 D8 F8 70 20 0F 06 06 06 06 00 00 00 00 ENDCHAR STARTCHAR uni240C ENCODING 9228 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F0 C0 E0 C0 C0 0F 0C 0E 0C 0C 00 00 00 00 ENDCHAR STARTCHAR uni240D ENCODING 9229 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 C0 C0 C0 70 1E 1B 1E 1B 1B 00 00 00 00 ENDCHAR STARTCHAR uni2423 ENCODING 9251 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni2424 ENCODING 9252 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 98 D8 F8 D8 D8 0C 0C 0C 0C 0F 00 00 00 00 ENDCHAR STARTCHAR question ENCODING 9254 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7C FE C6 C6 60 30 30 00 30 30 00 00 00 00 ENDCHAR STARTCHAR SF100000 ENCODING 9472 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2501 ENCODING 9473 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF110000 ENCODING 9474 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2503 ENCODING 9475 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2504 ENCODING 9476 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 6D 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2505 ENCODING 9477 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 6D 6D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2506 ENCODING 9478 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 00 18 18 18 18 18 00 18 18 18 18 00 ENDCHAR STARTCHAR uni2507 ENCODING 9479 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 00 1C 1C 1C 1C 1C 00 1C 1C 1C 1C 00 ENDCHAR STARTCHAR uni2508 ENCODING 9480 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 AA 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2509 ENCODING 9481 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 AA AA 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni250A ENCODING 9482 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 00 18 18 18 00 18 18 18 00 18 18 18 00 ENDCHAR STARTCHAR uni250B ENCODING 9483 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 00 1C 1C 1C 00 1C 1C 1C 00 1C 1C 1C 00 ENDCHAR STARTCHAR SF010000 ENCODING 9484 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1F 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni250D ENCODING 9485 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1F 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni250E ENCODING 9486 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1F 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni250F ENCODING 9487 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1F 1F 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR SF030000 ENCODING 9488 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 F8 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2511 ENCODING 9489 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 F8 F8 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2512 ENCODING 9490 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FC 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2513 ENCODING 9491 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FC FC 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR SF020000 ENCODING 9492 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1F 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2515 ENCODING 9493 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1F 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2516 ENCODING 9494 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1F 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2517 ENCODING 9495 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1F 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF040000 ENCODING 9496 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 F8 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2519 ENCODING 9497 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 F8 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni251A ENCODING 9498 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FC 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni251B ENCODING 9499 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FC FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF080000 ENCODING 9500 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1F 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni251D ENCODING 9501 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1F 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni251E ENCODING 9502 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1F 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni251F ENCODING 9503 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1F 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2520 ENCODING 9504 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1F 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2521 ENCODING 9505 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1F 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2522 ENCODING 9506 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1F 1F 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2523 ENCODING 9507 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1F 1F 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR SF090000 ENCODING 9508 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 F8 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2525 ENCODING 9509 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 F8 F8 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2526 ENCODING 9510 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FC 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2527 ENCODING 9511 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FC 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2528 ENCODING 9512 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FC 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2529 ENCODING 9513 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FC FC 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni252A ENCODING 9514 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FC FC 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni252B ENCODING 9515 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FC FC 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR SF060000 ENCODING 9516 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni252D ENCODING 9517 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF F8 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni252E ENCODING 9518 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni252F ENCODING 9519 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF FF 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2530 ENCODING 9520 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2531 ENCODING 9521 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF FC 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2532 ENCODING 9522 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 1F 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2533 ENCODING 9523 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF FF 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR SF070000 ENCODING 9524 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2535 ENCODING 9525 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2536 ENCODING 9526 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2537 ENCODING 9527 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2538 ENCODING 9528 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2539 ENCODING 9529 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni253A ENCODING 9530 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni253B ENCODING 9531 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF050000 ENCODING 9532 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni253D ENCODING 9533 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF F8 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni253E ENCODING 9534 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni253F ENCODING 9535 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF FF 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2540 ENCODING 9536 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2541 ENCODING 9537 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2542 ENCODING 9538 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2543 ENCODING 9539 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF FC 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2544 ENCODING 9540 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2545 ENCODING 9541 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF FC 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2546 ENCODING 9542 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF 1F 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2547 ENCODING 9543 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF FF 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2548 ENCODING 9544 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 FF FF 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni2549 ENCODING 9545 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF FC 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni254A ENCODING 9546 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF 1F 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni254B ENCODING 9547 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C FF FF 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni254C ENCODING 9548 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 EE 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni254D ENCODING 9549 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 EE EE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni254E ENCODING 9550 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 00 18 18 18 18 18 18 18 00 ENDCHAR STARTCHAR uni254F ENCODING 9551 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 00 1C 1C 1C 1C 1C 1C 1C 00 ENDCHAR STARTCHAR SF430000 ENCODING 9552 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FF 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF240000 ENCODING 9553 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF510000 ENCODING 9554 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 1F 18 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF520000 ENCODING 9555 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 3F 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF390000 ENCODING 9556 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 3F 30 37 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF220000 ENCODING 9557 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 F8 18 F8 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF210000 ENCODING 9558 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FE 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF250000 ENCODING 9559 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FE 06 F6 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF500000 ENCODING 9560 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 1F 18 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF490000 ENCODING 9561 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 3F 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF380000 ENCODING 9562 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 37 30 3F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF280000 ENCODING 9563 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 F8 18 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF270000 ENCODING 9564 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 FE 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF260000 ENCODING 9565 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 F6 06 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF360000 ENCODING 9566 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 1F 18 1F 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF370000 ENCODING 9567 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 37 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF420000 ENCODING 9568 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 37 30 37 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF190000 ENCODING 9569 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 F8 18 F8 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF200000 ENCODING 9570 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 F6 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF230000 ENCODING 9571 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 F6 06 F6 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF470000 ENCODING 9572 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FF 00 FF 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF480000 ENCODING 9573 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF410000 ENCODING 9574 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FF 00 F7 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF450000 ENCODING 9575 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 FF 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF460000 ENCODING 9576 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF400000 ENCODING 9577 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 F7 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR SF540000 ENCODING 9578 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 FF 18 FF 18 18 18 18 18 18 18 ENDCHAR STARTCHAR SF530000 ENCODING 9579 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 36 FF 36 36 36 36 36 36 36 36 ENDCHAR STARTCHAR SF440000 ENCODING 9580 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 36 36 36 36 36 36 F7 00 F7 36 36 36 36 36 36 36 ENDCHAR STARTCHAR uni256D ENCODING 9581 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 03 0E 0C 18 18 18 18 18 18 ENDCHAR STARTCHAR uni256E ENCODING 9582 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 C0 70 30 18 18 18 18 18 18 ENDCHAR STARTCHAR uni256F ENCODING 9583 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 30 70 C0 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2570 ENCODING 9584 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 0C 0E 03 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2571 ENCODING 9585 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 01 01 02 02 04 04 08 08 10 10 20 20 40 40 80 80 ENDCHAR STARTCHAR uni2572 ENCODING 9586 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 80 80 40 40 20 20 10 10 08 08 04 04 02 02 01 01 ENDCHAR STARTCHAR uni2573 ENCODING 9587 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 81 81 42 42 24 24 18 18 18 18 24 24 42 42 81 81 ENDCHAR STARTCHAR uni2574 ENCODING 9588 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 F8 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2575 ENCODING 9589 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 18 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2576 ENCODING 9590 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1F 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2577 ENCODING 9591 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 18 18 18 18 18 18 18 18 18 ENDCHAR STARTCHAR uni2578 ENCODING 9592 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FC FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2579 ENCODING 9593 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1C 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni257A ENCODING 9594 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1F 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni257B ENCODING 9595 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 1C 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni257C ENCODING 9596 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF 1F 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni257D ENCODING 9597 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 18 18 18 18 18 18 1C 1C 1C 1C 1C 1C 1C 1C 1C ENDCHAR STARTCHAR uni257E ENCODING 9598 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FF FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni257F ENCODING 9599 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 1C 1C 1C 1C 1C 1C 1C 1C 1C 18 18 18 18 18 18 18 ENDCHAR STARTCHAR upblock ENCODING 9600 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2581 ENCODING 9601 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF ENDCHAR STARTCHAR uni2582 ENCODING 9602 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF ENDCHAR STARTCHAR uni2583 ENCODING 9603 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF ENDCHAR STARTCHAR dnblock ENCODING 9604 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF ENDCHAR STARTCHAR uni2585 ENCODING 9605 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF ENDCHAR STARTCHAR uni2586 ENCODING 9606 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF ENDCHAR STARTCHAR uni2587 ENCODING 9607 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF ENDCHAR STARTCHAR block ENCODING 9608 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ENDCHAR STARTCHAR uni2589 ENCODING 9609 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE ENDCHAR STARTCHAR uni258A ENCODING 9610 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC FC ENDCHAR STARTCHAR uni258B ENCODING 9611 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 F8 ENDCHAR STARTCHAR lfblock ENCODING 9612 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 ENDCHAR STARTCHAR uni258D ENCODING 9613 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 ENDCHAR STARTCHAR uni258E ENCODING 9614 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR uni258F ENCODING 9615 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ENDCHAR STARTCHAR rtblock ENCODING 9616 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F ENDCHAR STARTCHAR ltshade ENCODING 9617 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 11 44 11 44 11 44 11 44 11 44 11 44 11 44 11 44 ENDCHAR STARTCHAR shade ENCODING 9618 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 55 AA 55 AA 55 AA 55 AA 55 AA 55 AA 55 AA 55 AA ENDCHAR STARTCHAR dkshade ENCODING 9619 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP DD 77 DD 77 DD 77 DD 77 DD 77 DD 77 DD 77 DD 77 ENDCHAR STARTCHAR uni2594 ENCODING 9620 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2595 ENCODING 9621 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ENDCHAR STARTCHAR filledbox ENCODING 9632 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE FE FE FE FE FE FE FE FE 00 00 00 00 ENDCHAR STARTCHAR H22073 ENCODING 9633 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 82 82 82 82 82 82 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25A2 ENCODING 9634 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 7C 82 82 82 82 82 82 82 7C 00 00 00 00 ENDCHAR STARTCHAR uni25A3 ENCODING 9635 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 82 BA BA BA BA BA 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25A4 ENCODING 9636 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 82 FE 82 FE 82 FE 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25A5 ENCODING 9637 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE AA AA AA AA AA AA AA FE 00 00 00 00 ENDCHAR STARTCHAR uni25A6 ENCODING 9638 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE AA FE AA FE AA FE AA FE 00 00 00 00 ENDCHAR STARTCHAR uni25A7 ENCODING 9639 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 8A C6 A2 92 8A C6 A2 FE 00 00 00 00 ENDCHAR STARTCHAR uni25A8 ENCODING 9640 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE A2 C6 8A 92 A2 C6 8A FE 00 00 00 00 ENDCHAR STARTCHAR uni25A9 ENCODING 9641 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE AA C6 AA 92 AA C6 AA FE 00 00 00 00 ENDCHAR STARTCHAR H18543 ENCODING 9642 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7C 7C 7C 7C 7C 00 00 00 00 ENDCHAR STARTCHAR H18551 ENCODING 9643 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7C 44 44 44 7C 00 00 00 00 ENDCHAR STARTCHAR filledrect ENCODING 9644 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FE FE FE FE FE 00 00 00 00 ENDCHAR STARTCHAR uni25AD ENCODING 9645 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 FE 82 82 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25AE ENCODING 9646 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE FE FE FE FE FE FE FE FE FE FE FE 00 00 ENDCHAR STARTCHAR uni25AF ENCODING 9647 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 82 82 82 82 82 82 82 82 82 82 FE 00 00 ENDCHAR STARTCHAR uni25B0 ENCODING 9648 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 7E 7E 7E FC FC FC 00 00 00 00 ENDCHAR STARTCHAR uni25B1 ENCODING 9649 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 7E 42 42 84 84 FC 00 00 00 00 ENDCHAR STARTCHAR triagup ENCODING 9650 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 38 38 7C 7C FE FE 00 00 00 00 ENDCHAR STARTCHAR uni25B3 ENCODING 9651 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 28 28 44 44 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25B4 ENCODING 9652 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 10 38 38 7C 00 00 00 00 ENDCHAR STARTCHAR uni25B5 ENCODING 9653 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 10 28 28 7C 00 00 00 00 ENDCHAR STARTCHAR uni25B6 ENCODING 9654 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 80 C0 E0 F0 F8 FC F8 F0 E0 C0 80 00 00 00 00 ENDCHAR STARTCHAR uni25B7 ENCODING 9655 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 80 C0 A0 90 88 84 88 90 A0 C0 80 00 00 00 00 ENDCHAR STARTCHAR uni25B8 ENCODING 9656 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 40 70 78 70 40 00 00 00 00 ENDCHAR STARTCHAR uni25B9 ENCODING 9657 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 40 70 48 70 40 00 00 00 00 ENDCHAR STARTCHAR triagrt ENCODING 9658 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 80 E0 F8 FE F8 E0 80 00 00 00 00 00 ENDCHAR STARTCHAR uni25BB ENCODING 9659 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 80 E0 98 86 98 E0 80 00 00 00 00 00 ENDCHAR STARTCHAR triagdn ENCODING 9660 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE FE 7C 7C 38 38 10 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni25BD ENCODING 9661 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE 82 44 44 28 28 10 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni25BE ENCODING 9662 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 7C 38 38 10 00 00 00 00 ENDCHAR STARTCHAR uni25BF ENCODING 9663 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 7C 28 28 10 00 00 00 00 ENDCHAR STARTCHAR uni25C0 ENCODING 9664 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 02 06 0E 1E 3E 7E 3E 1E 0E 06 02 00 00 00 00 ENDCHAR STARTCHAR uni25C1 ENCODING 9665 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 02 06 0A 12 22 42 22 12 0A 06 02 00 00 00 00 ENDCHAR STARTCHAR uni25C2 ENCODING 9666 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 08 38 78 38 08 00 00 00 00 ENDCHAR STARTCHAR uni25C3 ENCODING 9667 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 08 38 48 38 08 00 00 00 00 ENDCHAR STARTCHAR triaglf ENCODING 9668 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 02 0E 3E FE 3E 0E 02 00 00 00 00 00 ENDCHAR STARTCHAR uni25C5 ENCODING 9669 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 02 0E 32 C2 32 0E 02 00 00 00 00 00 ENDCHAR STARTCHAR uni25C6 ENCODING 9670 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 38 7C 7C FE FE 7C 7C 38 10 00 00 00 00 ENDCHAR STARTCHAR uni25C7 ENCODING 9671 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 44 82 82 44 44 28 10 00 00 00 00 ENDCHAR STARTCHAR uni25C8 ENCODING 9672 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 44 54 BA BA 54 44 28 10 00 00 00 00 ENDCHAR STARTCHAR uni25C9 ENCODING 9673 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 99 BD BD BD BD 99 42 3C 00 00 00 00 ENDCHAR STARTCHAR lozenge ENCODING 9674 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 28 28 44 82 82 44 28 28 10 00 00 00 00 ENDCHAR STARTCHAR circle ENCODING 9675 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 81 81 81 81 81 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni25CC ENCODING 9676 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 14 40 01 80 01 80 01 80 02 28 00 00 00 00 ENDCHAR STARTCHAR uni25CD ENCODING 9677 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 A5 A5 A5 A5 A5 A5 66 3C 00 00 00 00 ENDCHAR STARTCHAR uni25CE ENCODING 9678 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 99 A5 A5 A5 A5 99 42 3C 00 00 00 00 ENDCHAR STARTCHAR H18533 ENCODING 9679 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 7E FF FF FF FF FF FF 7E 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D0 ENCODING 9680 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 72 F1 F1 F1 F1 F1 F1 72 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D1 ENCODING 9681 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 4E 8F 8F 8F 8F 8F 8F 4E 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D2 ENCODING 9682 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 81 81 FF FF FF 7E 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D3 ENCODING 9683 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 7E FF FF FF 81 81 81 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D4 ENCODING 9684 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 4E 8F 8F 8F 81 81 81 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D5 ENCODING 9685 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 4E 8F 8F 8F FF FF FF 7E 3C 00 00 00 00 ENDCHAR STARTCHAR uni25D6 ENCODING 9686 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 70 F0 F0 F0 F0 F0 F0 70 30 00 00 00 00 ENDCHAR STARTCHAR uni25D7 ENCODING 9687 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 0E 0F 0F 0F 0F 0F 0F 0E 0C 00 00 00 00 ENDCHAR STARTCHAR invbullet ENCODING 9688 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF FF FF FF FF E7 C3 C3 E7 FF FF FF FF FF FF ENDCHAR STARTCHAR invcircle ENCODING 9689 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF C3 BD 7E 7E 7E 7E 7E 7E BD C3 FF FF FF FF ENDCHAR STARTCHAR uni25DA ENCODING 9690 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF C3 BD 7E 7E 7E 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni25DB ENCODING 9691 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 7E 7E 7E BD C3 FF FF FF FF ENDCHAR STARTCHAR uni25DC ENCODING 9692 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 40 80 80 80 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni25DD ENCODING 9693 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0C 02 01 01 01 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni25DE ENCODING 9694 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 01 01 01 02 0C 00 00 00 00 ENDCHAR STARTCHAR uni25DF ENCODING 9695 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 80 80 80 40 30 00 00 00 00 ENDCHAR STARTCHAR uni25E0 ENCODING 9696 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 81 81 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni25E1 ENCODING 9697 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 81 81 81 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni25E2 ENCODING 9698 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 01 01 03 03 07 07 0F 0F 1F 1F 3F 3F 7F 7F FF FF ENDCHAR STARTCHAR uni25E3 ENCODING 9699 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 80 80 C0 C0 E0 E0 F0 F0 F8 F8 FC FC FE FE FF FF ENDCHAR STARTCHAR uni25E4 ENCODING 9700 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF FE FE FC FC F8 F8 F0 F0 E0 E0 C0 C0 80 80 ENDCHAR STARTCHAR uni25E5 ENCODING 9701 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP FF FF 7F 7F 3F 3F 1F 1F 0F 0F 07 07 03 03 01 01 ENDCHAR STARTCHAR openbullet ENCODING 9702 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 3C 66 42 42 66 3C 00 00 00 00 00 ENDCHAR STARTCHAR uni25E7 ENCODING 9703 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF F1 F1 F1 F1 F1 F1 F1 F1 FF 00 00 00 00 ENDCHAR STARTCHAR uni25E8 ENCODING 9704 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 8F 8F 8F 8F 8F 8F 8F 8F FF 00 00 00 00 ENDCHAR STARTCHAR uni25E9 ENCODING 9705 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF FF FD F9 F1 F1 E1 C1 81 FF 00 00 00 00 ENDCHAR STARTCHAR uni25EA ENCODING 9706 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 81 83 87 8F 8F 9F BF FF FF 00 00 00 00 ENDCHAR STARTCHAR uni25EB ENCODING 9707 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FF 99 99 99 99 99 99 99 99 FF 00 00 00 00 ENDCHAR STARTCHAR uni25EC ENCODING 9708 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 28 28 44 44 92 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25ED ENCODING 9709 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 38 38 74 74 F2 F2 FE 00 00 00 00 ENDCHAR STARTCHAR uni25EE ENCODING 9710 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 38 38 5C 5C 9E 9E FE 00 00 00 00 ENDCHAR STARTCHAR uni25EF ENCODING 9711 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 81 81 81 81 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uni25F0 ENCODING 9712 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 92 92 92 F2 82 82 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25F1 ENCODING 9713 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 82 82 82 F2 92 92 92 FE 00 00 00 00 ENDCHAR STARTCHAR uni25F2 ENCODING 9714 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 82 82 82 9E 92 92 92 FE 00 00 00 00 ENDCHAR STARTCHAR uni25F3 ENCODING 9715 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 FE 92 92 92 9E 82 82 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni25F4 ENCODING 9716 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 4A 89 89 89 F9 81 81 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni25F5 ENCODING 9717 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 81 F9 89 89 89 4A 3C 00 00 00 00 ENDCHAR STARTCHAR uni25F6 ENCODING 9718 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 81 9F 91 91 91 52 3C 00 00 00 00 ENDCHAR STARTCHAR uni25F7 ENCODING 9719 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 52 91 91 91 9F 81 81 42 3C 00 00 00 00 ENDCHAR STARTCHAR uni2600 ENCODING 9728 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 54 38 FE 38 54 10 10 00 00 00 00 ENDCHAR STARTCHAR uni2602 ENCODING 9729 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 30 7C FE FF 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2601 ENCODING 9730 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 7C FE 10 10 10 10 14 08 00 00 00 00 ENDCHAR STARTCHAR uni2605 ENCODING 9733 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 38 FE 7C 38 6C 44 00 00 00 00 00 ENDCHAR STARTCHAR uni2606 ENCODING 9734 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 28 EE 44 54 6C 44 00 00 00 00 00 ENDCHAR STARTCHAR uni2607 ENCODING 9735 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 18 30 60 C0 60 34 1C 3C 00 00 00 00 00 ENDCHAR STARTCHAR uni2608 ENCODING 9736 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE C6 CC D8 F0 D8 CD C7 CF 00 00 00 00 00 ENDCHAR STARTCHAR uni2609 ENCODING 9737 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 38 44 82 92 82 44 38 00 00 00 00 00 ENDCHAR STARTCHAR uni260A ENCODING 9738 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 42 42 42 A5 A5 42 00 00 00 00 ENDCHAR STARTCHAR uni260B ENCODING 9739 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 42 A5 A5 42 42 42 24 18 00 00 00 00 ENDCHAR STARTCHAR uni260C ENCODING 9740 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 06 0C 78 CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni260D ENCODING 9741 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 36 36 1C 18 30 70 D8 D8 70 00 00 00 00 ENDCHAR STARTCHAR uni2610 ENCODING 9744 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 82 82 82 82 82 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni2611 ENCODING 9745 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 82 86 8A BA 92 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni2612 ENCODING 9746 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 FE 82 EE BA BA EE 82 FE 00 00 00 00 ENDCHAR STARTCHAR uni2613 ENCODING 9747 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 82 C6 6C 7C 38 7C 6C C6 82 00 00 00 00 ENDCHAR STARTCHAR uni2620 ENCODING 9760 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 7C 82 AA 82 44 7C 44 38 00 44 C6 38 C6 44 00 ENDCHAR STARTCHAR uni2622 ENCODING 9762 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 44 EE FE 92 BA 7C 38 00 00 00 00 00 ENDCHAR STARTCHAR uni2626 ENCODING 9766 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 7E 18 18 FF 18 1E 78 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2628 ENCODING 9768 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 7E 18 18 FF 18 18 18 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2629 ENCODING 9769 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 38 10 10 92 FE 92 10 10 38 00 00 00 00 ENDCHAR STARTCHAR uni262A ENCODING 9770 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 72 E0 C4 DF CE CA E0 72 3C 00 00 00 00 ENDCHAR STARTCHAR uni262B ENCODING 9771 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 54 28 54 AA AA AA AA 54 38 00 00 00 00 00 ENDCHAR STARTCHAR uni262E ENCODING 9774 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 5A 99 99 99 BD FF DB 5A 3C 00 00 00 00 ENDCHAR STARTCHAR uni262F ENCODING 9775 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 42 81 85 B1 F9 FF DF 7E 3C 00 00 00 00 ENDCHAR STARTCHAR uni2630 ENCODING 9776 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE FE 00 00 FE FE 00 00 FE FE 00 00 00 00 ENDCHAR STARTCHAR uni2631 ENCODING 9777 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 EE EE 00 00 FE FE 00 00 FE FE 00 00 00 00 ENDCHAR STARTCHAR uni2632 ENCODING 9778 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE FE 00 00 EE EE 00 00 FE FE 00 00 00 00 ENDCHAR STARTCHAR uni2633 ENCODING 9779 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 EE EE 00 00 EE EE 00 00 FE FE 00 00 00 00 ENDCHAR STARTCHAR uni2634 ENCODING 9780 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE FE 00 00 FE FE 00 00 EE EE 00 00 00 00 ENDCHAR STARTCHAR uni2635 ENCODING 9781 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 EE EE 00 00 FE FE 00 00 EE EE 00 00 00 00 ENDCHAR STARTCHAR uni2636 ENCODING 9782 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 FE FE 00 00 EE EE 00 00 EE EE 00 00 00 00 ENDCHAR STARTCHAR uni2637 ENCODING 9783 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 EE EE 00 00 EE EE 00 00 EE EE 00 00 00 00 ENDCHAR STARTCHAR uni2639 ENCODING 9785 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 81 A5 81 81 81 99 A5 81 7E 00 00 00 00 ENDCHAR STARTCHAR smileface ENCODING 9786 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E 81 A5 81 81 A5 99 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR invsmileface ENCODING 9787 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E FF DB FF FF DB E7 FF FF 7E 00 00 00 00 ENDCHAR STARTCHAR sun ENCODING 9788 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 54 28 C6 28 54 10 10 00 00 00 00 ENDCHAR STARTCHAR uni263D ENCODING 9789 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 78 14 0A 0A 0A 0A 0A 0A 14 78 00 00 00 00 ENDCHAR STARTCHAR uni263E ENCODING 9790 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 28 50 50 50 50 50 50 28 1E 00 00 00 00 ENDCHAR STARTCHAR uni263F ENCODING 9791 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 66 66 3C 66 66 66 66 3C 18 7E 18 18 00 00 00 ENDCHAR STARTCHAR female ENCODING 9792 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 3C 18 7E 18 18 00 00 00 00 ENDCHAR STARTCHAR uni2641 ENCODING 9793 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 7E 18 3C 66 66 66 66 3C 00 00 00 00 ENDCHAR STARTCHAR male ENCODING 9794 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 06 0E 1A 78 CC CC CC CC 78 00 00 00 00 ENDCHAR STARTCHAR uni2643 ENCODING 9795 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 03 03 7B CF CF CF 0F 1B 33 FF 03 03 03 00 00 ENDCHAR STARTCHAR uni2644 ENCODING 9796 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 60 F0 60 6E 73 63 63 66 66 63 00 00 00 00 ENDCHAR STARTCHAR uni2645 ENCODING 9797 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 D6 54 54 7C 54 54 D6 38 44 44 38 00 00 00 ENDCHAR STARTCHAR uni2646 ENCODING 9798 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 3C DB DB DB DB 7E 3C 18 3C 18 18 00 00 ENDCHAR STARTCHAR uni2647 ENCODING 9799 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 F8 CC CC CC CC F8 C0 C0 C0 C0 FE 00 00 00 ENDCHAR STARTCHAR uni2648 ENCODING 9800 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 42 A5 A5 3C 3C 18 18 18 18 18 18 00 00 00 ENDCHAR STARTCHAR uni2649 ENCODING 9801 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 C3 66 66 66 66 3C 66 66 66 66 3C 00 00 ENDCHAR STARTCHAR uni264A ENCODING 9802 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C3 7E 66 66 66 66 66 66 7E C3 00 00 00 00 ENDCHAR STARTCHAR uni264B ENCODING 9803 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7E DB D8 70 00 00 0E 1B DB 7E 00 00 00 00 ENDCHAR STARTCHAR uni264C ENCODING 9804 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1E 33 33 33 33 1B 7B DB DB 73 03 01 00 00 ENDCHAR STARTCHAR uni264D ENCODING 9805 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 94 7C 55 57 55 55 55 55 55 55 06 0B 00 00 ENDCHAR STARTCHAR uni264E ENCODING 9806 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 66 66 66 66 24 E7 00 FF 00 00 00 00 00 ENDCHAR STARTCHAR uni264F ENCODING 9807 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 94 7C 54 54 54 54 54 54 54 54 04 03 00 00 ENDCHAR STARTCHAR uni2650 ENCODING 9808 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1F 07 8F DB 73 70 D8 88 00 00 00 00 00 00 ENDCHAR STARTCHAR uni2651 ENCODING 9809 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 90 50 70 68 48 48 4E 49 09 0E 10 20 00 00 ENDCHAR STARTCHAR uni2652 ENCODING 9810 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 2A 7E AA 00 00 2A 7E AA 00 00 00 00 00 ENDCHAR STARTCHAR uni2653 ENCODING 9811 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C3 66 66 66 66 FF 66 66 66 66 C3 00 00 00 ENDCHAR STARTCHAR spade ENCODING 9824 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 3C 7E FF FF 7E 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni2661 ENCODING 9825 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 6C 92 82 82 82 44 28 10 00 00 00 00 ENDCHAR STARTCHAR uni2662 ENCODING 9826 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 28 44 82 44 28 10 00 00 00 00 00 ENDCHAR STARTCHAR club ENCODING 9827 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 3C 3C E7 E7 E7 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni2664 ENCODING 9828 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 24 42 81 81 66 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR heart ENCODING 9829 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 6C FE FE FE FE 7C 38 10 00 00 00 00 ENDCHAR STARTCHAR diamond ENCODING 9830 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 38 7C FE 7C 38 10 00 00 00 00 00 ENDCHAR STARTCHAR uni2667 ENCODING 9831 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 18 24 3C E7 A5 E7 18 18 3C 00 00 00 00 ENDCHAR STARTCHAR uni2669 ENCODING 9833 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 18 18 18 18 18 18 18 38 78 70 00 00 00 00 ENDCHAR STARTCHAR musicalnote ENCODING 9834 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 30 3C 3E 32 30 30 30 70 F0 E0 00 00 00 00 ENDCHAR STARTCHAR musicalnotedbl ENCODING 9835 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 7F 6F 63 63 63 63 E3 E7 C7 06 00 00 00 ENDCHAR STARTCHAR uni266C ENCODING 9836 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 7F 63 7F 63 63 63 63 63 E7 E7 C6 00 00 00 ENDCHAR STARTCHAR uni266D ENCODING 9837 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 C0 C0 C0 C0 CC DE E6 C4 D8 E0 00 00 00 00 ENDCHAR STARTCHAR uni266E ENCODING 9838 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 40 40 44 5C 74 44 44 5C 74 44 04 04 00 00 ENDCHAR STARTCHAR uni266F ENCODING 9839 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 04 46 5C 74 C4 46 5C 74 C4 40 40 00 00 ENDCHAR STARTCHAR ff ENCODING 64256 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3B 66 66 66 FF 66 66 66 66 FF 00 00 00 00 ENDCHAR STARTCHAR fi ENCODING 64257 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3C 6E 66 60 FE 66 66 66 66 FF 00 00 00 00 ENDCHAR STARTCHAR fl ENCODING 64258 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 3E 6E 66 66 FE 66 66 66 66 FF 00 00 00 00 ENDCHAR STARTCHAR ffi ENCODING 64259 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6E DB DB D8 FF DB DB DB DB FF 00 00 00 00 ENDCHAR STARTCHAR ffl ENCODING 64260 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 6F DB DB DB FF DB DB DB DB FF 00 00 00 00 ENDCHAR STARTCHAR uniFB05 ENCODING 64261 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 38 6C 6C 6F 6C 6C 6C 6C 6D F6 00 00 00 00 ENDCHAR STARTCHAR uniFB50 ENCODING 64336 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 06 29 5E 00 04 04 04 04 04 04 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB51 ENCODING 64337 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 06 29 5E 00 04 04 04 04 04 03 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB52 ENCODING 64338 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFB53 ENCODING 64339 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 80 81 7E 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFB54 ENCODING 64340 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFB55 ENCODING 64341 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFB56 ENCODING 64342 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 14 00 08 00 00 00 ENDCHAR STARTCHAR uniFB57 ENCODING 64343 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 80 81 7E 00 14 00 08 00 00 00 ENDCHAR STARTCHAR uniFB58 ENCODING 64344 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 14 00 08 00 00 00 ENDCHAR STARTCHAR uniFB59 ENCODING 64345 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 14 00 08 00 00 00 ENDCHAR STARTCHAR uniFB5A ENCODING 64346 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 14 00 14 00 00 00 ENDCHAR STARTCHAR uniFB5B ENCODING 64347 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 80 81 7E 00 14 00 14 00 00 00 ENDCHAR STARTCHAR uniFB5C ENCODING 64348 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 14 00 14 00 00 00 ENDCHAR STARTCHAR uniFB5D ENCODING 64349 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 14 00 14 00 00 00 ENDCHAR STARTCHAR uniFB5E ENCODING 64350 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 08 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB5F ENCODING 64351 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 08 00 40 80 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB60 ENCODING 64352 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 08 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB61 ENCODING 64353 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 08 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB62 ENCODING 64354 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 14 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB63 ENCODING 64355 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 14 00 40 80 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB64 ENCODING 64356 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 14 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB65 ENCODING 64357 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 14 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB66 ENCODING 64358 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB67 ENCODING 64359 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 40 80 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB68 ENCODING 64360 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB69 ENCODING 64361 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB6A ENCODING 64362 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 0A 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB6B ENCODING 64363 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 00 0A 00 06 49 89 86 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB6C ENCODING 64364 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 0C 12 0A 06 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB6D ENCODING 64365 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 0C 12 12 0C F3 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB6E ENCODING 64366 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0A 00 0A 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB6F ENCODING 64367 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0A 00 0A 00 06 49 89 86 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB70 ENCODING 64368 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 00 14 00 0C 12 0A 06 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB71 ENCODING 64369 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 14 00 14 00 0C 12 12 0C F3 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB72 ENCODING 64370 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 88 80 88 41 3E 00 00 00 ENDCHAR STARTCHAR uniFB73 ENCODING 64371 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 41 88 80 88 40 3E 00 00 ENDCHAR STARTCHAR uniFB74 ENCODING 64372 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 47 18 E0 00 04 00 04 00 00 00 ENDCHAR STARTCHAR uniFB75 ENCODING 64373 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 C1 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFB76 ENCODING 64374 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 80 94 80 41 3E 00 00 00 ENDCHAR STARTCHAR uniFB77 ENCODING 64375 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 41 80 94 80 40 3E 00 00 ENDCHAR STARTCHAR uniFB78 ENCODING 64376 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 47 18 E0 00 00 0A 00 00 00 00 ENDCHAR STARTCHAR uniFB79 ENCODING 64377 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 C1 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFB7A ENCODING 64378 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 94 80 88 41 3E 00 00 00 ENDCHAR STARTCHAR uniFB7B ENCODING 64379 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 41 94 80 88 40 3E 00 00 ENDCHAR STARTCHAR uniFB7C ENCODING 64380 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 47 18 E0 00 0A 00 04 00 00 00 ENDCHAR STARTCHAR uniFB7D ENCODING 64381 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 C1 00 14 00 08 00 00 00 ENDCHAR STARTCHAR uniFB7E ENCODING 64382 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 94 80 94 41 3E 00 00 00 ENDCHAR STARTCHAR uniFB7F ENCODING 64383 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 41 94 80 94 40 3E 00 00 ENDCHAR STARTCHAR uniFB80 ENCODING 64384 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 47 18 E0 00 0A 00 0A 00 00 00 ENDCHAR STARTCHAR uniFB81 ENCODING 64385 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 C1 00 14 00 14 00 00 00 ENDCHAR STARTCHAR uniFB82 ENCODING 64386 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 04 02 42 3C 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFB83 ENCODING 64387 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 08 04 46 39 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFB84 ENCODING 64388 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 28 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB85 ENCODING 64389 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 28 00 08 08 04 46 39 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB86 ENCODING 64390 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 00 28 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB87 ENCODING 64391 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 00 28 00 08 08 04 46 39 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB88 ENCODING 64392 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 38 28 70 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB89 ENCODING 64393 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 38 28 70 08 08 04 46 39 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB8A ENCODING 64394 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 00 14 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uniFB8B ENCODING 64395 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 14 00 00 04 07 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFB8C ENCODING 64396 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uniFB8D ENCODING 64397 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 00 00 04 07 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFB8E ENCODING 64398 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 01 02 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB8F ENCODING 64399 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 01 02 04 08 48 84 82 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB90 ENCODING 64400 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 18 20 10 08 08 F0 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB91 ENCODING 64401 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 18 20 20 10 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB92 ENCODING 64402 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB93 ENCODING 64403 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 48 84 82 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB94 ENCODING 64404 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 46 18 20 10 08 08 F0 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB95 ENCODING 64405 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 46 18 20 20 10 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB96 ENCODING 64406 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 44 82 82 7C 00 10 00 10 00 00 00 ENDCHAR STARTCHAR uniFB97 ENCODING 64407 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 09 12 04 08 48 84 82 7D 00 10 00 10 00 00 00 ENDCHAR STARTCHAR uniFB98 ENCODING 64408 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 46 18 20 10 08 08 F0 00 10 00 10 00 00 00 ENDCHAR STARTCHAR uniFB99 ENCODING 64409 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 46 18 20 20 10 08 F7 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFB9A ENCODING 64410 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP A4 09 12 04 08 44 82 82 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB9B ENCODING 64411 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP A4 09 12 04 08 48 84 82 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB9C ENCODING 64412 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP A2 0C 13 0C 10 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB9D ENCODING 64413 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP A2 0C 13 0C 10 10 08 04 FB 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFB9E ENCODING 64414 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR uniFB9F ENCODING 64415 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 01 41 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uniFBA0 ENCODING 64416 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA1 ENCODING 64417 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 00 00 01 41 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uniFBA2 ENCODING 64418 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA3 ENCODING 64419 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 1C 14 38 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA4 ENCODING 64420 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 38 40 38 40 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA5 ENCODING 64421 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 70 80 70 80 10 68 88 74 03 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA6 ENCODING 64422 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA7 ENCODING 64423 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 0C 13 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBA8 ENCODING 64424 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 10 F0 10 14 08 00 00 00 00 ENDCHAR STARTCHAR uniFBA9 ENCODING 64425 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 10 F7 08 08 08 00 00 00 00 ENDCHAR STARTCHAR uniFBAA ENCODING 64426 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 38 4C 52 32 3D 40 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBAB ENCODING 64427 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 38 4C 52 32 3D 40 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBAC ENCODING 64428 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 38 4C 52 32 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBAD ENCODING 64429 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 38 4C 52 32 FD 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBAE ENCODING 64430 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 14 60 80 FE 00 00 00 00 00 ENDCHAR STARTCHAR uniFBAF ENCODING 64431 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 07 18 20 3F 00 00 00 00 ENDCHAR STARTCHAR uniFBB0 ENCODING 64432 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 70 80 70 80 08 14 60 80 FE 00 00 00 00 00 ENDCHAR STARTCHAR uniFBB1 ENCODING 64433 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 1C 20 1C 20 00 00 07 18 20 3F 00 00 00 00 ENDCHAR STARTCHAR uniFBD3 ENCODING 64467 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 00 29 01 19 21 19 A1 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBD4 ENCODING 64468 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 00 2A 02 32 42 32 C6 79 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBD5 ENCODING 64469 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 40 00 A3 0C 10 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBD6 ENCODING 64470 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 40 00 A3 0C 10 10 08 04 FB 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBD7 ENCODING 64471 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 28 18 10 20 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBD8 ENCODING 64472 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 28 18 10 20 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFBD9 ENCODING 64473 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 08 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBDA ENCODING 64474 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 08 00 00 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFBDB ENCODING 64475 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 08 08 08 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBDC ENCODING 64476 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 08 08 08 00 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFBDD ENCODING 64477 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 23 54 33 24 40 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBDE ENCODING 64478 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBDF ENCODING 64479 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 14 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFBE0 ENCODING 64480 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 0E 02 3C 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBE1 ENCODING 64481 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 08 00 00 00 0C 12 0F 02 3C 18 60 00 00 00 ENDCHAR STARTCHAR uniFBE2 ENCODING 64482 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 14 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFBE3 ENCODING 64483 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 14 00 00 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFBE4 ENCODING 64484 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 81 7E 00 10 00 10 ENDCHAR STARTCHAR uniFBE5 ENCODING 64485 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 07 88 87 81 7E 10 00 10 ENDCHAR STARTCHAR uniFBE6 ENCODING 64486 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFBE7 ENCODING 64487 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 08 00 08 00 00 00 ENDCHAR STARTCHAR uniFBE8 ENCODING 64488 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBE9 ENCODING 64489 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFBFC ENCODING 64508 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 82 7C 00 00 00 00 ENDCHAR STARTCHAR uniFBFD ENCODING 64509 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 07 88 87 81 7E 00 00 00 ENDCHAR STARTCHAR uniFBFE ENCODING 64510 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFBFF ENCODING 64511 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFC5B ENCODING 64603 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 20 20 20 20 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC5C ENCODING 64604 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 10 10 10 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uniFC5D ENCODING 64605 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 10 10 10 00 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR uniFC5E ENCODING 64606 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 24 98 60 C2 12 92 9C 60 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC5F ENCODING 64607 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 02 92 9C 60 0E 70 0E 70 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC60 ENCODING 64608 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 60 04 54 58 20 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC61 ENCODING 64609 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 28 10 60 04 54 58 20 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC62 ENCODING 64610 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 04 54 58 20 0C 30 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC63 ENCODING 64611 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 10 04 54 58 20 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFC90 ENCODING 64656 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 10 10 10 00 00 00 00 07 88 87 81 7E 00 00 00 ENDCHAR STARTCHAR uniFCF2 ENCODING 64754 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0E F0 02 92 9C 60 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFCF3 ENCODING 64755 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 24 18 60 02 92 9C 60 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFCF4 ENCODING 64756 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 02 12 9C 60 0E 70 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFD3C ENCODING 64828 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 10 28 50 28 08 08 08 08 07 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFD3D ENCODING 64829 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 14 28 14 04 04 04 04 04 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFD3E ENCODING 64830 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 08 10 54 38 54 10 08 04 00 00 00 00 00 ENDCHAR STARTCHAR uniFD3F ENCODING 64831 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 10 08 2A 1C 2A 08 10 20 00 00 00 00 00 ENDCHAR STARTCHAR uniFDF2 ENCODING 65010 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 2A 14 00 21 69 A9 69 16 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE50 ENCODING 65104 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 08 10 00 00 00 00 00 ENDCHAR STARTCHAR uniFE51 ENCODING 65105 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 10 08 00 00 00 00 00 ENDCHAR STARTCHAR uniFE52 ENCODING 65106 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE54 ENCODING 65108 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 00 00 08 10 00 00 00 00 00 ENDCHAR STARTCHAR uniFE55 ENCODING 65109 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 10 00 00 10 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE56 ENCODING 65110 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 24 08 10 00 10 00 00 00 00 00 ENDCHAR STARTCHAR uniFE57 ENCODING 65111 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 10 10 10 00 10 00 00 00 00 00 ENDCHAR STARTCHAR uniFE58 ENCODING 65112 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE59 ENCODING 65113 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 10 10 10 10 10 08 00 00 00 00 ENDCHAR STARTCHAR uniFE5A ENCODING 65114 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 08 08 08 08 08 10 00 00 00 00 ENDCHAR STARTCHAR uniFE5B ENCODING 65115 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 10 10 20 10 10 18 00 00 00 00 ENDCHAR STARTCHAR uniFE5C ENCODING 65116 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 08 08 04 08 08 18 00 00 00 00 ENDCHAR STARTCHAR uniFE5D ENCODING 65117 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 10 10 10 10 10 18 00 00 00 00 ENDCHAR STARTCHAR uniFE5E ENCODING 65118 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 18 08 08 08 08 08 18 00 00 00 00 ENDCHAR STARTCHAR uniFE5F ENCODING 65119 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 28 7C 28 7C 28 00 00 00 00 00 ENDCHAR STARTCHAR uniFE60 ENCODING 65120 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 28 28 10 2A 24 1A 00 00 00 00 ENDCHAR STARTCHAR uniFE61 ENCODING 65121 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 10 10 7C 38 38 44 00 00 00 00 00 ENDCHAR STARTCHAR uniFE62 ENCODING 65122 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 10 10 7C 10 10 00 00 00 00 00 ENDCHAR STARTCHAR uniFE63 ENCODING 65123 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE64 ENCODING 65124 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 10 20 10 08 00 00 00 00 00 ENDCHAR STARTCHAR uniFE65 ENCODING 65125 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 20 10 08 10 20 00 00 00 00 00 ENDCHAR STARTCHAR uniFE66 ENCODING 65126 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 3C 00 3C 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE68 ENCODING 65128 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 20 10 10 08 08 04 00 00 00 00 00 ENDCHAR STARTCHAR uniFE69 ENCODING 65129 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 10 38 54 30 18 54 38 10 00 00 00 00 ENDCHAR STARTCHAR uniFE6A ENCODING 65130 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 24 08 08 10 10 24 00 00 00 00 00 ENDCHAR STARTCHAR uniFE6B ENCODING 65131 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 44 54 58 40 38 00 00 00 00 00 ENDCHAR STARTCHAR uniFE70 ENCODING 65136 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 0C 30 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE71 ENCODING 65137 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 06 18 60 06 18 60 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE72 ENCODING 65138 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 12 CA 2C 70 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE74 ENCODING 65140 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 0C 30 0C 30 00 00 ENDCHAR STARTCHAR uniFE76 ENCODING 65142 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE77 ENCODING 65143 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 06 18 60 00 00 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE78 ENCODING 65144 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 08 14 0C 08 10 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE79 ENCODING 65145 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 24 14 18 60 00 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE7A ENCODING 65146 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 00 00 00 00 0C 30 00 00 ENDCHAR STARTCHAR uniFE7B ENCODING 65147 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 FF 00 00 06 18 60 00 00 ENDCHAR STARTCHAR uniFE7C ENCODING 65148 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0A 2A 2C 10 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE7D ENCODING 65149 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 02 12 92 9C 60 00 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE7E ENCODING 65150 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 24 18 00 00 00 00 00 00 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE7F ENCODING 65151 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 24 24 18 00 00 00 00 FF 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE80 ENCODING 65152 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 20 1E 20 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE81 ENCODING 65153 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 02 3C 40 10 10 10 10 10 10 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE82 ENCODING 65154 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 01 3E 40 08 08 08 08 08 07 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE83 ENCODING 65155 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 18 20 1C 20 08 08 08 08 08 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE84 ENCODING 65156 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 0C 10 0E 10 04 04 04 04 03 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE85 ENCODING 65157 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1C 20 1C 20 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFE86 ENCODING 65158 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1C 20 1C 20 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFE87 ENCODING 65159 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 04 04 04 04 04 00 0C 10 0E 10 00 00 ENDCHAR STARTCHAR uniFE88 ENCODING 65160 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 04 04 04 04 03 00 0C 10 0E 10 00 00 ENDCHAR STARTCHAR uniFE89 ENCODING 65161 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 40 38 40 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR uniFE8A ENCODING 65162 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 30 40 38 40 00 00 00 07 88 87 81 7E 00 00 00 ENDCHAR STARTCHAR uniFE8B ENCODING 65163 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1C 20 1C 20 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE8C ENCODING 65164 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 1C 20 1C 20 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE8D ENCODING 65165 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 08 08 08 08 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE8E ENCODING 65166 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 08 08 08 08 07 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE8F ENCODING 65167 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 81 81 7E 00 00 08 00 00 00 00 ENDCHAR STARTCHAR uniFE90 ENCODING 65168 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 40 80 81 7E 00 00 08 00 00 00 00 ENDCHAR STARTCHAR uniFE91 ENCODING 65169 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 00 10 00 00 00 00 ENDCHAR STARTCHAR uniFE92 ENCODING 65170 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 00 08 00 00 00 00 ENDCHAR STARTCHAR uniFE93 ENCODING 65171 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 28 00 00 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE94 ENCODING 65172 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 50 00 10 10 68 88 74 03 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE95 ENCODING 65173 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 14 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE96 ENCODING 65174 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 14 00 40 80 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE97 ENCODING 65175 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 14 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE98 ENCODING 65176 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 14 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE99 ENCODING 65177 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 40 81 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE9A ENCODING 65178 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 40 80 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE9B ENCODING 65179 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE9C ENCODING 65180 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFE9D ENCODING 65181 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 80 88 80 41 3E 00 00 00 ENDCHAR STARTCHAR uniFE9E ENCODING 65182 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 41 80 88 80 40 3E 00 00 ENDCHAR STARTCHAR uniFE9F ENCODING 65183 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 47 18 E0 00 00 10 00 00 00 00 ENDCHAR STARTCHAR uniFEA0 ENCODING 65184 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 C1 00 00 08 00 00 00 00 ENDCHAR STARTCHAR uniFEA1 ENCODING 65185 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR uniFEA2 ENCODING 65186 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 41 80 80 80 40 3E 00 00 ENDCHAR STARTCHAR uniFEA3 ENCODING 65187 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 38 47 18 E0 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEA4 ENCODING 65188 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 70 8F 32 C1 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEA5 ENCODING 65189 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 20 00 00 70 8F 30 40 80 80 80 41 3E 00 00 00 ENDCHAR STARTCHAR uniFEA6 ENCODING 65190 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 00 00 70 8F 32 41 80 80 80 40 3E 00 00 ENDCHAR STARTCHAR uniFEA7 ENCODING 65191 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 00 38 47 18 E0 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEA8 ENCODING 65192 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 00 00 70 8F 32 C1 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEA9 ENCODING 65193 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEAA ENCODING 65194 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 08 04 46 39 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEAB ENCODING 65195 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 00 08 04 02 42 3C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEAC ENCODING 65196 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 00 08 08 04 46 39 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEAD ENCODING 65197 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uniFEAE ENCODING 65198 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 04 07 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFEAF ENCODING 65199 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 04 02 02 04 18 60 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB0 ENCODING 65200 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 00 00 04 07 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFEB1 ENCODING 65201 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 01 15 88 84 84 78 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB2 ENCODING 65202 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 01 15 88 84 84 78 00 00 00 00 ENDCHAR STARTCHAR uniFEB3 ENCODING 65203 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 01 15 EA 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB4 ENCODING 65204 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 2A D5 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB5 ENCODING 65205 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 01 15 88 84 84 78 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB6 ENCODING 65206 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 14 00 01 15 88 84 84 78 00 00 00 00 ENDCHAR STARTCHAR uniFEB7 ENCODING 65207 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 04 00 0A 00 00 01 15 EA 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB8 ENCODING 65208 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 14 00 00 00 2A D5 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEB9 ENCODING 65209 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 06 09 31 9E 88 88 70 00 00 00 00 00 ENDCHAR STARTCHAR uniFEBA ENCODING 65210 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 06 09 31 9E 88 88 70 00 00 00 00 ENDCHAR STARTCHAR uniFEBB ENCODING 65211 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 06 29 31 DE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEBC ENCODING 65212 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 06 29 31 DE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEBD ENCODING 65213 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 09 31 9E 88 88 70 00 00 00 00 00 ENDCHAR STARTCHAR uniFEBE ENCODING 65214 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 04 00 06 09 31 9E 88 88 70 00 00 00 00 ENDCHAR STARTCHAR uniFEBF ENCODING 65215 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 00 06 29 31 DE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC0 ENCODING 65216 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 00 06 29 31 DE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC1 ENCODING 65217 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 20 20 2C 32 A2 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC2 ENCODING 65218 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 20 20 2C 32 A2 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC3 ENCODING 65219 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 20 20 2C 32 22 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC4 ENCODING 65220 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 20 20 20 2C 32 22 FD 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC5 ENCODING 65221 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 20 20 2C 32 A2 7C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC6 ENCODING 65222 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 20 20 2C 32 A2 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC7 ENCODING 65223 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 20 20 2C 32 22 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC8 ENCODING 65224 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 24 20 20 2C 32 22 FD 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEC9 ENCODING 65225 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 70 80 8C 70 40 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR uniFECA ENCODING 65226 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 1E 22 1C 22 41 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR uniFECB ENCODING 65227 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0E 10 10 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFECC ENCODING 65228 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 1E 22 1C E3 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFECD ENCODING 65229 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 40 00 00 70 80 8C 70 40 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR uniFECE ENCODING 65230 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 08 00 00 1E 22 1C 22 41 80 80 80 41 3E 00 00 ENDCHAR STARTCHAR uniFECF ENCODING 65231 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 10 00 00 0E 10 10 FE 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED0 ENCODING 65232 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 1E 22 1C E3 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED1 ENCODING 65233 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 49 85 83 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED2 ENCODING 65234 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 04 00 06 49 89 86 7D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED3 ENCODING 65235 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 0C 12 0A 06 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED4 ENCODING 65236 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 0C 12 12 0C F3 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED5 ENCODING 65237 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0A 00 06 09 09 47 81 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uniFED6 ENCODING 65238 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 0A 00 00 06 09 49 87 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uniFED7 ENCODING 65239 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 00 0C 12 0A 06 FC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED8 ENCODING 65240 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 14 00 00 0C 12 12 0C F3 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFED9 ENCODING 65241 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 19 21 19 21 01 81 7E 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEDA ENCODING 65242 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 32 42 32 42 02 86 79 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEDB ENCODING 65243 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 18 20 10 08 08 F0 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEDC ENCODING 65244 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 06 18 20 20 10 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEDD ENCODING 65245 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 02 02 02 02 02 42 82 82 84 78 00 00 00 00 00 ENDCHAR STARTCHAR uniFEDE ENCODING 65246 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 02 02 02 02 02 03 42 82 82 84 78 00 00 ENDCHAR STARTCHAR uniFEDF ENCODING 65247 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 08 08 08 08 08 F0 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE0 ENCODING 65248 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 08 08 08 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE1 ENCODING 65249 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 0C 12 12 3C 40 40 40 40 40 40 00 00 ENDCHAR STARTCHAR uniFEE2 ENCODING 65250 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 3C 4B 4A 44 40 40 40 00 00 ENDCHAR STARTCHAR uniFEE3 ENCODING 65251 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 32 CC 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE4 ENCODING 65252 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 32 CD 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE5 ENCODING 65253 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 08 00 00 41 81 81 81 42 3C 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE6 ENCODING 65254 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 01 41 81 81 42 3C 00 00 00 ENDCHAR STARTCHAR uniFEE7 ENCODING 65255 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 00 08 04 04 F8 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE8 ENCODING 65256 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 08 00 00 08 08 F7 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEE9 ENCODING 65257 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 18 24 22 22 1C 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEEA ENCODING 65258 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 10 10 68 88 74 03 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEEB ENCODING 65259 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 40 30 4E 49 39 E6 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEEC ENCODING 65260 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 08 14 24 28 F3 24 18 0C 00 00 00 00 ENDCHAR STARTCHAR uniFEED ENCODING 65261 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 0C 12 0E 02 04 18 60 00 00 00 00 ENDCHAR STARTCHAR uniFEEE ENCODING 65262 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 0C 12 0F 02 04 18 60 00 00 00 ENDCHAR STARTCHAR uniFEEF ENCODING 65263 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 81 7E 00 00 00 00 ENDCHAR STARTCHAR uniFEF0 ENCODING 65264 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 07 88 87 81 7E 00 00 00 ENDCHAR STARTCHAR uniFEF1 ENCODING 65265 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 07 08 88 86 81 81 7E 00 00 24 00 ENDCHAR STARTCHAR uniFEF2 ENCODING 65266 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 00 00 07 88 87 81 7E 00 24 00 ENDCHAR STARTCHAR uniFEF3 ENCODING 65267 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 08 04 04 F8 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFEF4 ENCODING 65268 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 00 00 00 00 08 08 F7 00 00 14 00 00 00 00 ENDCHAR STARTCHAR uniFEF5 ENCODING 65269 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 68 90 02 22 12 0A 04 0C 12 3C 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEF6 ENCODING 65270 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 68 90 02 32 12 0A 0A 0E 3D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEF7 ENCODING 65271 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 60 80 72 A2 12 0A 04 0C 12 3C 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEF8 ENCODING 65272 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 30 40 3A 52 12 0A 0A 0E 3D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEF9 ENCODING 65273 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 42 22 12 0A 04 0C 12 3C 00 18 20 1C 20 00 ENDCHAR STARTCHAR uniFEFA ENCODING 65274 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 22 12 12 0A 0A 0E 3D 00 00 18 20 1C 20 00 ENDCHAR STARTCHAR uniFEFB ENCODING 65275 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 42 22 12 0A 04 0C 12 3C 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEFC ENCODING 65276 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 00 22 12 12 0A 0A 0E 3D 00 00 00 00 00 00 00 ENDCHAR STARTCHAR uniFEFF ENCODING 65279 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP F1 35 55 8A E0 06 95 D6 B5 97 00 EE 8A EE 28 E8 ENDCHAR STARTCHAR uniFFFD ENCODING 65533 SWIDTH 480 0 DWIDTH 8 0 BBX 8 16 0 -4 BITMAP 00 38 7C 7C C6 92 F2 E6 FE E6 7C 7C 38 00 00 00 ENDCHAR ENDFONT tboot-1.10.5/tboot/include/vga/u_vga16.sfn0000644000000000000000000016347314210363175016402 0ustar 00000000000000SFN2;ç }AUVga UnicodeVGAMediumBolkhovCopyright (c) 2000 Dmitry Bolkhovityanov, bolkhov@inp.nsk.su€€€€(€>€ €0€66€n;€0>333n€>ccccc>€€~€ÿ€ €>cc>€6€333333n€P€ € €<€ff€~€ï€ cccccc~`0€€6€ €6€3f€ @B<€ @@ €0Hp@ €8(€ww€6ccccc€fFFf€6Q2€€<<€>ccccccc>€;ffffff€;nf€>c0c>€6€n33333n€`’¡Á~€ n33333>03€cccccccc>€6€~€>cc>€cckkk6€<€6€f3€‚B<€àa~€?€ <<€ gff66ffg€3 c€ €fff<<€ÀÀ€€`Œy€â€ñLƒ€0Hð@ € ~~Z<€``€ccccccc>€€ñ ‚|€€¨!!€(€pp€p€ 6cccccc€ ?fff>ffff?€ fFFf€ ccccccccc€ Ff€ cwkccccc€ cgo{scccc€ 800<63333n€ p``````ff<€ <€7kkkkc€c66c€ €?fff>6ffg€p€3ccccc>€cs{ogc€€$DD8€ 1‚|€€€ H "AA>€0€ bœ€àá~€~€ 6ffffff6€ >cccccccc>€ ?fff>6fffg€ >cc0`cc>€ ccccccccc>€ cc6>>6cc€ ffff<<€ ca0 Cc€ € 6nffffg€ f66fg€ ;fffff>€  ? l8€fffff<€€cgo{sccc€3nl~v€ccccccc>€3€>c``c>€>cccccc>€>cccc>€cccc~``c>€€`âB<€˜„˜„€~€0 0 €0 €0È€ccckkkw6€pÈ\6€cc66€888€0HP`?€0HH0Ï€ à €`”Œ{€ € € ccccccc6€ 6ffff>€€ 6ffofff6€ >cc>0€33€ €cccccccc€>cc0cc>€ ;ffffff```€ 6666666666€ € `0<```c>€>cc>€>c`<`c>€6ckkkk6€ccs{ogcc€kkk>kkk€6ckkk6€f€f€€$x€€8€ @@@@@BAA!€$€`”z€ €ñ )‚|€ @B<€@€€(€àaA>€<<€FF€WTrqw€ÛÛ€€66cc€;n€€ÿÿ€`’‘a¾€88€<<<€ ccccccc>€^#skgb=€c```ccc>€ >cCCc>€ ÀÀ^33333333€ ÀÀ`33333€ cF  Fc€ ÀÀs33333333€ ÀÀ`333333n€ w666ccccc>€ €|633333s€ >ccccc> € þ›[[[;ö€cc>0€ N9>cccccc>€ cb644€ >kkkkk>€?ff>ff?€cccccc€ccc€ €0€ € fF€ 66ccc€ ccccccccc€ >kkkkk>€ >ccccc666w€gff66ffg€fF€ccc~```€ÃÃÃÏÛÛÏ€>c`|`c>€Cc&6€ >€>*€f€ ccccccccãÀ€€cccccãÀ€€00<€ €€@<€8€ 880Hp@ €(~€ñ ‚|€4LE>€$4LE>€ 0HH<€ r’œg€0HS4€(0€PT4€$€00€€"? €R/ €Acc6€6ccA€0p`€>6"€ €`z€À À € Ä*Ì$0Hp@ €ñ )‚|€ñ ‚|€ñ ))‚|€€¨ ¦€ €€@ "AA>€”€˜„˜…~€%H "AA>€$DD8€0Hp@<€ 0Hp@ €(€¨Q €00€ |€(D(€cwkcccc€0n;€?fff>€cc6>>6cc€Àd€&pØ€fff3€ ~~€I"I"I€€?€€€ €€€ ? €  € € €  € 0`À€ ÿ€ÿ €0`ÿ€ÿ`0€  €00€$$€@`88`@€x€~~€?````?€€````€`xncnx`€;c;€€ €0000000000000000€ÿÀÃÿ€€8888€8888888€ïlllllll€llllllï€888888888€T~U€ À€`€`ï€ H !A¾€0 b€0 b‚B<€2JL¼€àü€€`€0p€.À€ñL‚|€€¨W€T«€ xD8D‚‚|€p€xD8Ç€BDHP 0H<€DHHPPp¼€ [@A@A@m€fff$€6666666€ >cC>``ac>€Cc0 ca€ 66n;333n€ € 0 0€ 000000 €f<ÿc`0 c€ >c``<```c>€ 08<63000x€ ?```c>€ ?cccc>€ c``0 € >ccc>cccc>€ >ccc~```0€`0  0`€ 0`0 €>cc0€>cc{{{;>€ fF€ >cccccck{>0p€ < <€8p`@€ <00000000<€ 6&€ n33333>00x€ pp€ p€<<<€ c6cc60c>€ € 66ccccc€ € >ffff>€ € >fffff>€ 6cccccc0p€ 0>333n0p€ "cc> € 6fFFf€ "6ffg€ ">cc0cc>€ >cc0cc>0€ >c0c>0€ 6>cc0cc>€ ~~Z<0€  ? l80€ 6~~Z<€ 6 ? l8€ ~~Z<<€  ? ? l8€3€ 6cccccccc>€ cccccccc> € 333333n € "ccckkkw6€ "fff<<€ 6c1 Cc€ 6&€ 6ffff>€ ~ÍÍÌ|ÌÌÌÌ~€ ?&>ffff?€ ~F6ffff>€ >ggf>ffff?€ 6ffff>€ À|fCCf<€À~cc>€ >mÍÌÌÌÌÌl>€ ~200>3333~€ >20<63333n€ >cccc> 3€ 314<4013€ fF€ 8lL  € À|fC{ccf\€ ccc6666€ ÏÛÛÛÛÛs€  l8€ <<<€ g¶66ffg€ 6f66fg€ <<€  6&cC€ kkkkkkkk7€ ffn~~vffff€ ÎûÛÛÛÛÛÛÛÎÀÀÀ€ ÎûÛÛÛÛÎÀÀÀ€ ~ÍÍÌ| € 6>fffff>€ >ff>66g`€ >cc0cc>€>c0c>€ Øp€  ? l806€ ~Y<€ 8l ? l8€ ~~Zp€ 3ccccccc3€ ÆÍÍÌx0000x€ `°333333>0€ ca0~ Cc€3?c€ `0 >````c>€  >c>€  c>€ `0<`>c>€ >c`0~ c€ 0```f<€0`f<€  ? 26€ ;fff6€ ~~€ Øp ï››[[[;;ï€ ¯[û›[[[;ï€ ¼Xþ›[[[;ö€ ãÃÃÃÃÃÃÃÓo€ ÏÆæÆÆÆæöÿÀØp€ ÇÆæÆÆÆÆÆÏÀÌx€ ÛÛßßßÛÛÛÛ{€ ÛÛÿßßÛÛÛÛÀÌx€ íÛÛÛÛÛÛÀÌx€ 66ccccc€ 6<<€ 6>ccccccc>€ 6cccccccc>€6€6€ €6€ 66ccccc€ > 6ccccc€ 0|3€ 6cccccccc> € >ccccccc> € 60 >````c>€Øp € ï››[[[[;;ï€ û›[[[;ï€ ÛßÛÛÛÛs€ ?ffff6€ 066cccc€ 060>333n€^#sskggb=€3€ >ca`8.````8€>c`p<``8€ 6cccccccc€ 66nffffg€ 6ccc>cccc>€ $fff<€.33333n€;fffff:€ 66ffff>€>c```c>€>c;g>€ 800<63333>0°`€ `°0<63333n€>c``c>€Ü6qhd6€^³°03€>cc;cc>€ p``ø```ff<€ `°>33333>03€>cscc^€C&6€ s3333;600p€ 66nffffg€ 66nffffg``8€<<€<<€ Þ{<€ |<€ Øp€ þÆf6~ÆÏÀÌx€ckkkkv€ ckkkkv```€ 7kkkkc``8€ ;ffffff€ ;ffffff``À€cgo{sc€v{v€x0003;n€ x0000003;n€ x0003;60°`€ ;nf€ ;nf6€6fg€gf6>ff?€ >c0c?€ pؘ€ pؘ<€Øp€ pØ~€ ~€  ? l8€fffÿffÜ€w66ccc>€€ >cc`8<€ >cc € <8`cc>€ >cc>€ ccncc>€À~cscc^€00€ 8000000~3€ s36<<6300p€Ff€ `°>33333>00x€ >cc`8~<€ >cc ? € þÛÛ{{ÛÖÀØp€ þ›[[Û»ö € o¶6fÆÖl€ d¶6?66666<04€ o¶66v¶l€ ÛÛÛÛÛÛÀÀp€ f¶6fÆÖo€ öÖÆf6¶ÿ€ ck>6ck>6€€€€ €€0€€ck>6€€l6€  € €€€€€€0€ € 8€666€,€€À`€ €€ ,€€ 6cccccc€ |L ,<, L|€ ÌÌÌÌüÌÌÌÌÌ€ <<€ "€Ac€ Ikkkkk>€ cccc>€ b> >``8€ ``8€66666f€ €>c>``8€~33333€~p€ 6kkkkk>€ ab44 #C€ Ikkkkk>€ ffff<€ ``8€ fF€ ~L <, €  Æÿc`00`€ 00€ 5ddÐÐØØØØÀ@ €  2($`@@€ ÛÛÛÛÛÛÛÛÛ¶À|€ÛÛÛÛÛÛ¶À~€ nkccc~````€ lffff|````€ ?ccccc`n9€>kf``f=€ >cc`<ccc>€ € c 22a€&] 2>€ ~3kccccc>€~;ccc>€ <~™<€ 8~€be4S#€ >cccc?<`€ M |ÌÌÌÌÌÌÀ`€fF€ ffff?€ <66666666cA€ kkk>>kkkk€ >ca`<``ac>€ cccs{ogcc€ 6cccs{ogcc€ |ffffffffc€ ccccc~``c>€ 333333333`@€ ccccc~````€ ckkkkkkkk€ ckkkkkkkkÿÀ€€  € ÃÃÃÃÏÛÛÛÛÏ€ >ffff?€ 3a`|``a3€ 9mmmommmm9€ ~333>6666s€ `>?cccc>€<66666cA€|fffffc€cwkcc€cccccc€~Z<€ >kkkkk>€333333`@€ckkkkk€ckkkkkÿÀ€€ €>ff?€9mmomm9€~33>66s€ 6nffffg``8€>cc>€{ÛÛ{€ÛÛ{€ cccccc€ 6cckkkkk6€ ?- € ?- € sÛ››Ûs€sÛÛs€ 666kkk€6>kk€ 19iomýÕ××€19o}Õ×€ c66>kkkk€c6>kkk€ ÿÅMi?9}UÕ×€ýÅiÕÕ×€ 6>c``>```>>€>a`>``>>€ ikkkkk>€ ikkkkk>€ Ccc#36 €Cc##6 € ÛÛÛÛÛÛöÀ`8€ ÎÛÛÛÛÛöÀ`8€ >kcccccck>€>kccck>€ >6cckkkk6€6cckkkk6€ c€ ``<ð<€$"€>€ > €Ã€ b€A‚€FP€ 6cccs{ogcãÀ€€cs{ogãÀ€€ >ffff?€>ff?€ ?fv&^€ ;fffv&^€ @`€@`€ fF€fF€ fF>ffffo`h0€ fF6fo`h0€ kkk>>kkkëÀ€€kkk>kkëÀ€€ >ca`<``ac> € >c`<`c> € gff66ffçÀ€€g66fçÀ€€ ckk;;kkcc€ck;;kc€ gfo66ffg€ f66fg€ ÏÍÍl<C3kkkkk3^€>C3kk3^€ ~~Z<0 €~Z<0 € fffff<<€ ffff<~<€ fffff<~<€ cc6>>6cãÀ€€c66ãÀ€€ offffffffþÀ€€offfffþÀ€€ ccccc~```àÀ€€ccc~``àÀ€€ ccckk~hh``€ckk~hh`€ ?ccccc€?ccc€ xÌÍÍþ Ìx€yÍþ Ìx€ xÌÍÍþ Ìx0p€ yÍþ Ìx0p€ 6kkk>>kkkk€ gff66ffg`h0€ g66fg`h0€ |ffffffffãÀ€€|fffffãÀ€€ ccccccccc`h0€ cccccc`h0€ ccccc~```p0€ccc~``p0€ cwkccccãÀ€€cwkcãÀ€€>c``ccc>€kkk>>kkk€>ca`<`ac>€ `0<``ac>€>cccccc>€3a`|`a3€cccc~````€ÃÃÃÏÛÛÛÛÏ€ x000>3333~€ x000>³³³³n€ 800<63³³³n€ 310°°°°`€30œ°°`€ >ca`<````àÀ€€>c`<``àÀ€€ <6666¶¶¶¶c€<66¶¶¶c€ 3333?³³³³c€333¿³³c€ cscc>€ ~~ZØØØØp€~ZØØØp€&)]J2 € 33333333óÞ€ `€ cókkkk3€ 0000þ3333€ >fffff€ >`€ okkkk3€ þ$ffffff<€ fffff|``€  0 

``ff<€ fffff<€ <`|fff<€ kkkkkhh``€ 00ð€ >cc 0cc>€ ffffÆ€ >kkkkkk>€ € hhhk>€ €  €`<€ 0€8l6€|€kkkkkkV€ >fff~€ >33333þ000€ 33333ó000€ ~ffff|€ >33333>00ð€ >0€ >ffffff~€ ?ccókk3€ 000þ33333>€ >ffffff€ |€ okkkkkS€ 0þ33333€ ffffff|```€ >ffffff€ 80<&fFƼ€ 33333300ð€ p 6ffff|€ ð00333333>€ 000000006€ ffffff|€ ffffff€ 00`0 |€ kkkkkk~```€ 00ð€;kkkkkn€ >ffffff€ |fffff|`f<€ |€ ;kkkkkn€ >ffff>€hhhhk>€ 3333î€c>€6€€66€0€€.k:€€À`À€ €0€À` €Øl$€"U6€ P0€ € €$6€  € €€6€ `À€ €Û€Ì€o€`€of€~€À€~?€ccfn;3cc€000000€00008lg€0000000€?```cccc€€~00 €?fcccccc€3kkcccc>€ € ?```000000p€?``````?€ ?````0€?fccccc€;nfcccc{€ 008€000000>€?fcccc3€wfffff4€ 233700000p€?bccg``€ wff6€wff,0`€ ?``f&6v€?```````€kkkkkoc>€?fffffgg€3fffffff€3fffc```€3fff3€€0€8D€ àaA>€€~€  € B>€4"BAA>€0p`€ ‰I&d’‘`€ €€àà€À À(€(~(€ ``ñ ‚|€ @B<(€ @@ 8V € @@ F€ @H F€€¨Q€`Œy ¦€T4LE>€|€~€€@ Ð!A>€ H Ð!A>€"E "AA>€ (@@@@BAA!€ @@@@@BAA!€ @T@@@BAA!€‚B<(€2JL<€€0HpH4€âa~€ àa~€(€ª~>€TdT>>€0p8€(((€4D8€ Z¥fÚZf¥Z€ fBB™™BBf€8€d€L4€(0  €DD8€ *UI*******A€""€r> € 4"BAI6€<~< €€¨N€`ŒyN€ 1‚|€((((€ 0HH<****€ 6IIIII2 2@€6IIIII&€ *UUUAA 2@€6IIIAA"€ 6IIIAA 2@€?fff>fff?€ 076ffff>€ cc>6€ fFFf0€fF€6&€ 006nffffg€6nffffg€ ccccccccc € 6nffffg €0f€<<€0ff€ 07f66fg€ Ff6€ <6€ cgo{scccc6€ ;ffffff6€ 0N9>cccccc>€ >€0>€6€>cc8cc>€0€ ">cc8cc>€ ">c0c>€~~Z<€ `h ? l8€ ~~Z<6€  ? l88l€ ccccccccc>6€ 333333n6€0N9€cccccc>€cccccc6€ "c1 Cc€ ? l8€6&€ 06ccccc€ Àh66cccc€Àh6€ 8l6cccc€8l€ pÈ\66cccc€ n;*6cccc€ n;"0>333n€ 0"6cccc€0"€  "6cccc€ "€ *6cccc€ *€ N9"6cccc€N9"€ 0fFFf€ ÄnfFFf€ #vˆfFFf€ n;"FF€ n;">cc>€ 0<<€ 0>ccccccc>€ Än>ccccccc>€ #vˆ>ccccccc>€ pÈ\">cccccc>€ n;">ccccc>€ n;">ccccc>€ ÌÀ^3333333€ ØÌ`33333€ ÌÀ^3333333€ ÆÌ`33333€ ØÌ^3333333€ ØÌ`33333€ ÍÀ^3333333€ ÍÀ`33333€ 0cccccccc>€ ÌÀs3333333€ ØÌ`333333n€ ÌÀs3333333€ ÆÌ`333333n€ ØÌs3333333€ ØÌ`333333n€ ÍÀs3333333€ ÍÀ`333333n€ ccccc~0o`€ 0fff<<€\:€6c€3f€f3€c6€,0€, €%UWWe€%WUUe€WQsqW€WqSQW€StRTS€UuWTT€VqSUR€ €  €WRrRR€€EEGW%€€  PppP€ PppP€9K=I9€ € €f333€333f€ ~€ < €c0 ll€c0 ÖÖ€€66€ÛÛI€€66$€ÛÛ’€0  0€ 0 €fffffff€~ÃÛØx8€A>€>A€`06€€"wU€<<€ ``00 € < < <€ <000<0000<€ÞóóØÌÌÌ€ÌÌ€{ÏÏc333€~~``00€ ÛÛÛ{€|NOOON|€9yyy9€ 3ó33þ00ð€ >s g>€ >ck{>€ ³s333€ 6g?€@7k{kkok€ ffnÿnvÿvff€ ?ff>FföffÏ€ 333ÏkÛs€ ZÿZÿ$$$€OQUUUUE=€ 8l?l8€ gf66ffg€ ~~Zxx<€ >mlÌÌÌÆfo;€  Kk> vp€  Kk> v1`8€ [[>˜ü€ Cc> vÛÙØp€ Cc> ÞÛÙØ°€ 3ad|d`a3€ þXxX<€ Xfbá11>€ J­¨h4,•U2€  >fddeb`,€ GEEE}EEEEG€ lÜÜÌffg€ xnÜÜÌffg€ Ìr``00ø6€ Žq 0`ÀÆÃB<€ b’œx ]6€ p˜ŒL&‡f€ ÿ{ÛÛÛÛÛ{€ GEMMUUeeEG€ 3ó·ÿ?û3333€ EEEEEEUe~€€ |²²˜x8,,­F€ eÅ6dddåC€ ?EEEE= %G€ ?fff>6¶æfw€ 0?ccc?;;gg€ŽÛ¬‹€JZJú€ÚªŠ€ skkkkkg6 € P(( € 9 00``cc>€ dÀÈ0ÈÀÀf€8€ 666ccc€ x´´XxØŒŒM6€ (Ö3cc3Æ8€€¾ÿÁaA>€ Cc3 ;a8`8€  Fc? ;a8`8€ Cc3 {8`8€  Fc? {8`8€  Fl7 {8`8€ Mo< {8`8€ Cc3 ; w6666666€ À € 6666666w>€$~Ã~$€ >w6666w>€ 7mØ0 €ðà°Øì¶ € ¶ìذàð€ 0Øm7 €üÿü€?`ÿ`?€ Vÿ¦ €0eÿj0€ <~<<€ <<~<€ « €€?AA?€ >"""""c"€"c"">€>">€ "c"""cA€ >c"""cA€ *k***kI€ *w"c"""">€ *w"c""cA€=AA=€ÿ=5aÁ€€ƒ†¬¸¼€ÿ€ "c"""c"€ ccc66€€ ccc66€||€ |& |€||€0````0€ 8hddd2€0``0€~~~~~~~€ ÿffffffffffç€ çffffffffffÿ€ ÿƒ 00 ƒÿ€ ``00 €  00``€$~$€ ÀÀ```036€ ÇÌflg036€ ÌÎmol036€nv€nÛÛv€€@`0 ÿ€@h08,Fÿ@€pp€ X8€ 666v>76666€>ccccccc€ 0X € Ìffffffffffff3€ T************€ 0Xkkkk>***€ , ¬Ìì € 0X€>c€û€û€À߀ßÀ€€€"€"€"€>€">€d>-6€**€ €€ ~~€ € pp€ p€Øl66lØ€6lØl6€ f>g€ pp€t€ pp€ t€ ppn;€ tn;€ ppp€ ppp€ pxt€ pxt€ @`88`O8`@€ xy€ `08h€ t€ ~ ~€?hhdd?€ ~ ~€ ?hhdd?€~~€?````?€AIE_EI"€AAI]]I"€AAI]IA"€ccccccc€ccccccc€*II*€"AA"€"UIU"€"QIE"€"I]I"€"IUI"€*k]k*€"]A]"€"A]A"€IIII€AAAA€cUIUc€AI]IA€ÿ€ÀÀÀÀÿÀÀÀÀ€ ÿ€ ÿ€~€~~€ÿÿ€û€õ€ûû€C##ÿ €##ÿÿ €›[[û[[;€›[û[û[;€0`88`0€x€BýB€B¿B€@¾@€c€ ~€##ÿ€ÀàÐÈÄÂÁÿ€6cccccc€cccccc6€6€>€AcUIUcA€A# #A€AbTHTbA€"A€@ "A€66c€c66€|ss|€0gllg0€"IUUUUU€UUUUUI"€ *IIIIII€ &s& € 2g2 €¨T**T¨€*T¨T*€ @`8O`88`@€ yx€ Pp88hO8dD€ x y€  € hhdd€€````€ppn;€pn;€ @`88`@n;€ xn;€pxnknxd€;k;€ pxnknxd€ ;k;€¼fãÓËÇf=€ x€ € x€ €€B¥~$$~¥B€*QoA*€ """"€ pØØ€ € 00  00€  00 €À`00 € 00`À€ 00000000€ 0000000 €ü € ü€?00000000000000€ 0000000000000?€à0€  € 0à€ €0à0€  €à0 € 0à€ ÿƒ €  ƒÿ€ €ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ€ à    ¤žC>€ ð````€ ð0p00€ ð````€ ð0p00€ xØxØØ€A€ 0000ð€>cc €8888888888888888€¶€¶¶€88888€U€UU€ø€øø€ø88888888€øø8888888€€€?88888888€??8888888€ø€øø€8888888ø€8888888øø€€€8888888?€8888888??€ø€øø€8888888ø€ø88888888€8888888ø88888888€8888888øø€øø8888888€8888888øø8888888€€€8888888?€?88888888€8888888?88888888€8888888??€??8888888€8888888??8888888€ÿ€ÿ€ÿø€ÿÿ€ÿ88888888€ÿ?8888888€ÿø8888888€ÿÿ8888888€ÿ€ÿ€ÿø€ÿÿ€8888888ÿ€8888888ÿ?€8888888ÿø€8888888ÿÿ€ÿ€ÿ€ÿø€ÿÿ€8888888ÿ€ÿ88888888€8888888ÿ88888888€8888888ÿ?€8888888ÿø€ÿ?8888888€ÿø8888888€8888888ÿÿ€ÿÿ8888888€8888888ÿ?8888888€8888888ÿø8888888€8888888ÿÿ8888888€w€llllllllllllllll€ øø€üllllllll€ ü ìlllllll€ €llllllll€ `olllllll€øø€lllllllü€llllllì ü€€lllllll€llllllo`€øø€lllllllìllllllll€llllllì ìlllllll€€lllllllollllllll€llllllo`olllllll€ÿ€ÿllllllll€ÿ€lllllllÿ€ÿÿ€lllllllÿllllllll€Àp0€ € €0pÀ€€€@@ € @@€€€BB$$$$BB€€ø€€??€øø€ÿø€888888888€ÿ?€888888888€ÿÿÿÿÿÿÿ€ÿÿÿÿ€ÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿ€ ÿÿÿÿÿÿÿÿÿÿ€ ÿÿÿÿÿÿÿÿÿÿÿÿ€ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€????????????????€€€€€ðððððððððððððððð€ˆ"ˆ"ˆ"ˆ"ˆ"ˆ"ˆ"ˆ"€ªUªUªUªUªUªUªUªU€»î»î»î»î»î»î»î»î€€€€€€€€€€€€€€€€€€€AAAAAAA€>AAAAAAA>€A]]]]]A€AAAA€UUUUUUU€UUUU€QcEIQcE€EcQIEcQ€UcUIUcU€>>>>>€>""">€€AAA€ € AAAAAAAAAA€~~~???€~BB!!?€>>€""A€>€>€ ?€  ! €€€€a€>>€A""€>€>€ @`px|~|xp`@€ @`PHDBDHP`@€€€@p||p@€@pLCLp@€ >>>>€ ""AA""€ "*]]*"€ ÿ€>(€w"*6"€ ,8<€c3³ãó€"AIA"€$BBB¥¥B€B¥¥BBB$€`0333€ 8ll8 €AAAAAA€AaQ]IA€Aw]]wA€Ac6>>6cA€>AUA">"€"cc"€"wI]>€ ~ÿx€ ~ÿ€II€ **k""€ <ÛÛÛÛ~<<€ 3333€ B¥¥<<€ Ãffffªêªªªªªª`Ѐ******** À€øàñÛ΀ r’p€ ÃffffÿffffÀ<~ÿÿ~<€6IAAA"€"A"€<<ççç<€$Bf<€6>€>>€$<ç¥ç<€ € <|L € þöÆÆÆÆÇçã`€ þÆþÆÆÆÆÆççc€ 3{g#€ ":."":." € b:.#b:.#€ Üfffÿffffÿ€ >€T$X€>"€>€€€ €* *€$$€"*€``€$(€@HI9€€|à€0p À€ àa~€ €88 €à€ñL‚|€4LE¾€4LD?€4LD¿€$4LE¾€$4LD?€$4LD¿€`’áB<€LBLB@až€ @@@@@ÀBAA!€€ï€<ÒR"€0HL3€0HL³€€‚B<€($Ï$0€  @DHP 0H<€ @LHPPp¼€ NEHP 0H<€ \JHPPp¼€ ¬ªQ`©k­é€wQw€ >>cIOgg>>Ë žu ƒ× Ý è ø     , } æ€ ƒ3 = I U a m y … ‘  © ƒ ƒƒ ص ²²À Ë ƒÔ ‹—ì„£ß ~¯òŠþ»ÇÓøë œ¨I´–ÀÌØù ¢ µäÀß»ŸéƒÝUëõ÷q¦(zƒ ÈÉ õ 4"@™¨ŸƒLUbox"„•’ž²¤«Ò²Š±} ²·¿‘Ç» ÇÓ±ŠÌÓâñÔ:‘:Û™:•: éõE‘E•E[‘[æ[#™(Ôf‘f™f•f%,Ô«‘«8•«‘FRÔ™•Õ3/Ô»‘»»•»Ý‘ÝÝæÝ^™qÔ¦‘¦¦™¦•¦ƒ² ƒ ÔÈÈÈ;È‘õj•õŠ:ŠÄ:Äyˆ‘)‘À”Àƒ)À¢À°¾#4ŠEŠ»ÄEÄ»ƒE»ÌÚæ»ôŸÄ<ÄŸƒ<Ÿ~ Ø?ŸD@™[™Ý²[²ÝL[LÝ ƒ.ƒ[Ý:æFR`ëþ Øõ ØGP‘[» Ø÷ Øes™¥‘(‘qÓ Øq رq¿qÄÓŠfЦÄfĦÚfÚ¦ßë‘‘zœ Øz Øôz‘O‘ƒƒ*ƒ8GVdr~™«™ÈŠ«fÈÄ«ŠÈŽÕÈÚ«ÚÈœª¶ÉÄõæ‘i‘ ƒiƒ Ò àìø(t4A#KWco{€Œ‡–¥²ÀÌØäðü ZP˜¦/>JVer~²‡–¥±½¾ÌØÌØäòþ#/;GS\häftu ƒ€Žš¦²ÁÐÜ"ë÷ݦ!ÈŠŒYf\È/Y\È4Y9\È=YÔ\È_ŠBŠŒNŠrŠðŠ3\htŸ‚žûŠ­Šû»uËëÐÜ‘<ŸèôÔ(q‘ð‘3‘‘ :¶:¶E»¶E¶»[Ý[Ýf¦¶f¶¦z¶¶z«È¶«*Ȩ ؃ ØI Ø  Ø.<GUco{‰:”ŠŒhŠŒ¦Š#Š™¦f¦ŠrhŠr¦ÒŠõ›£¬µ¾ÊÓÝìø_Š (Ÿ6/?HT`ƒo$x™¨·ÀÌØäðrù“; #/;DMV_kz‰“ ¬»Ä-ÍÖßëôu ".:FJR[SeiuŠ˜¤°¿ÌØçó\\&.6=CIPX^be?Øägjov}„‹“&Š‘Ô & Š › Ÿ‡ÄƒÕ £™Ú¨Ô‘€®„l‡?Øä ƒ›²¶±º ¿ƒ Ä‚ƒ ؄ɑŒÍƒÛé÷€€!‘Œ$‹—q}£Ø¯Pòþ/ÇÓ; C‰ø€²IÌ•ÀH¡æ[æ‘‘‘Z‘$‘Œ-T/coZ~$GŠÇ–Ÿ¦®·ÃÎ×-àìø“æ$•-‘¦‘-‘“€(•6;AJUco{‡” ¯¼ÊÕáíü*3?HT`iÀUë‹E•Eu‘ƒŽ¨òæ[Šš¦²‘­œÄ{¾‹Í—qÙ£çóÿ þǯ‰øìI%•À1?KWeq}‰•¡­J¸¹»§Š6Ä6GÄÍS¦ÖÀßõè õÁ ÊÓ&/Ô»•»8‘¸GƒƒÝæÝUëPY@‘GÔ6Äõbn°z†’ž§³¼ÈÑÝæòû  " Pr1 Ü= ÜH W c q | å°êŠ ê°• ¤ ¯ å» À Å €¹Ê îÍ Ò Ö Û Äë ö ! !!%!3!>!J!S!b!n!|!‡!–!¢!°!»!Ç!Ð!Ü!è!ô!ò ý! ""!"-"9"õ/B"P"Ì["g"s"""˜"¦"±"¿"Ê"Ö"ß"ë"ô"# ##ò$#ħ2#A#M#[#f#u#ò ##š#¨#€Ä:Ä•:•é3ÄEÄ»€_•³#•_•¾#•§•É#•ŠÔ#uŠœŠ6•œ•6•f•¦Pr•à#•r•ë#•ÓŠ{Šõ•{•õÚ{Úõ•ö#•Á•$•Ê… $ß$$$0$<$E$S$^$j$s$$ˆ$”$$©$Ÿ²$»$Ç$Ó$ß$ë$÷$%%%)%5%A%N%Z%f%r%%‹%—%£%¯%»%Ç%Ó%ß%ë%÷%&&&(&4&@&L&X&d&p&|&ˆ&Ž&b”&™&ž&£&€¨&±&½&É&Õ&á&í&û&'''.':'I'U'd'p'|'ˆ'”' '¬'¸'Ä'Í'Ù'å'ñ'ú'((('(3(<(K(W(`(o(€ƒ ƒ{(… €(½†(( ’(—(œ(¡( ¦( «(°(µ(º(¿(Å(Ë(€    Ñ( Ö( Û(á(æ( ì(   ò(÷(Õ  ü(ÿ( )) )  ½ ½ ² )À€ )ƒ &)Š U?ƒ ƒƒŠ)%)/)9)C)M)W)a)k)u)|)‰)“)Ÿ)©)³)À)Ê)Ô)Þ)ë)õ)* **#*-*„7*A*K*‘Ú–R*X*ƒ‚]* }€Ä * 5 Ë Óe*Ëê }cCB }‡êI f†f¯}q}‡q+¸+T ] JVJ„µ¸˜Ñ‰”Ùf }Þr 'ææåz  £  £ˆ Ž r*“  “ ‰w*™ ¤ ¯ |*‡*’*º Å Ð *©*±*Û Yèå ì å í ì ¸*¾*ñ '÷ ñ æ0ê}}êê } }É*‡}êê ‡ }‡‡êê ‡ ‡Ó*}}f  }‡fõ â* } }‡ ‡}‡‡}‡‡0yì*õ* yý*‡}‡‡‡¸+& ¸Ñ&  +¸Ñ+¸+†. J˜˜ ¸˜ }¸Ñ˜˜ Ñ ¸Ñј¸‰¸Ñ‰1 +(+¸”¯; ” ‡ }_2+D _ ‡_ } }=+H+U+b+Ù ‡}}Þ ¸Þ0Þ}o+}‡Þz+¯õO §ƒ+§‡§‰+Z y'c ''‡'}‡'æ’+œ+}' }} ‡}q §+ÒC²+»+Ä+Ê+Ñ+}‡x Ù+é+÷+ƒü+~  x ,,… … ,, ‹ ‹ ! ~ $,™ ¤ ¯ *,5,@,º Å Ð }‡K,¸S,V\,Ä h,n,ÉÓz,‚†,,›,‡¤,Í‹ Õ Õƒ°,»,— ƒ ƒ— Š Š‘È,‘/Ö,á,„ ß „ Šß Šï,þ, --ÔŠ'ÔŠ»‘Š'‘Š»+-:-£ ™» ™ÄF-ăT-_-Š<ŠŸDj-¯ é ƒ•D•x-ƒ-’-¯ Äé Äò ™ƒÝ ™¡-¦-°-݃­¶-þ ƒõ ƒþ Šõ Š» ƒ÷ ƒŠP ƒŠ[ ƒ» Š÷ ²Ã-Ò-‘’ ‘’ Ç  (ƒqÓ q ƒÓ Šq Šá-ð-ü- ¦Œ#Œ™¦ .hÔŠ¦.h‘Ц‘£ ‘ƒ£ ƒƒƒzœ ƒz ƒŠ ƒŠz ƒœ Šz ŠOƒ¨ ƒ ..#.ƒ).7.O ƒ ƒE.P.I ƒ  ƒI ²  ²].l.´ •È •´ ™È ™{.Š.–.œ. ÈŒŠY;ïÈ™¥.™  ƒÔ«ÔÉ‘«‘É•«•ɫɖ É ®  •® • ƒõ°. Ø   Ø Š  Šé Š•¾.ÕÉÕõgÉ.ƒ‹  Ô.jâ.ð.ö./ /¶/&/Û  4/B/H/V/\/j/p/~/Ä: Ä £ ƒ» „/j»™E™»’/¹ » /¿ »¶'¶»®/¼/ ƒ» Ê/jÝò ƒƒÝ ƒ ¦ Ø/j¦æ/¹ ¦ô/¿ ¦0¶¦00 ¦ ,0:0F0T0`0n0{0‰0˜ ¦ ´ È –0lȤ0²0¾0Ì0Ø0æ0ó01¾ Ì ÔõÌ ƒ11jõ(1™õ…Øä,11161;1@1F1À÷€L1P€€S1P€€Z1P€€a1P€€h1P€€o1P€€v1P€€}1P€€„1P€€‹1P€€’1P€€0P€€0™1€€0 1€€§1€€´1€ŠÁ1Ò²²µµf €€È1æ æÎ1Ô1Å  Å Ú1à1Ë !ì1 ƒ æ 7ƒ‡õ12 22222$2 ¢)222× ;2 æD2 ƒ€ M2Q2 U2\2a2f2j2v2‚2€Ž2 —2›2 ;¤2¬2¸2Á2¡à ‚è ð ø     ïïï ' / à Ó·¿è ð ø      ïï ï ' / Ê2Ö2æ2ò2þ2 33!3-393E34 ŠO3[3g3s3ÀO€3Ž3œ3¨3´3À3Î3ŒÜ3è3ô34 44'434?4K4W4c4o4{4‡4“4Ÿ4¬4¸4Å4Ñ4Ý4é4ö45 555'535¡ØB5N5þW5e5q5}5†55›5§5³5¿5È5Ô5à5ì5ø5ü56—66,6;6J6Y6h6w6†6•6¤6³6Â6òÎ6Ú6æ6ò6þ6 77À"7.7»ì„ǃ;•:77C7?L7"U76 ^7g7k7?t7 "}76 †7÷Àß7›7§7t‹³7º7Æ7Í7Ù7à7: ë7ô7ý78 8888%81888D8K8R8Y8e8l8x8„8Œ8”8œ8¤8«8²8¾8É8Ô8ß8ê8ò8ú89µ: 99%9C H 09<9M R H9T9`9l9x9W W „9^ ^ 9C R M H œ9£9ª9±9¸9Ä9Ë9×9Þ9ê9õ9: :::(:/:6:B:N:U:  [:b:h:o:v::‹:”: : ©:®:º:Æ:Ò:ß:ì:õ:; ;‹;$;/;;;G;U;}a;m;x;…;Ž;™;¦;¯;¸;Æ;Ô;²²}ƒ}â;ð;þ;e !<<<)</<5<=<F<P<äY<fe<D¼q<Y{<‹<›<«<»<Ë<Û<ë<û<ƒ ææ ƒƒ ƒæ 惲"ï "æ² æƒ™ ™N ===$=€™™€.=™€ €8=A=™™M=™™ €™™ ™N€ €X=\=¹î¹²ƒ²²ƒ²² ƒÀ²² UU²² À`=d=h=l=p=u=€€z=€€~=€€ƒ=€€ˆ=€€Ž=€€”=€€š=€€Ÿ=¤=€¨=€€ €²=€€€ €} €„ €} € €„ € €¿=Ë=×=à=é=õ=þ= >> >} ™„ ™,>:>G>S>_>m>k t {>‡>k ™t ™“>ž>} … ©>³>} €… €½>É>Õ>à>ë>õ>ÿ> •  €• € ???&?/?8?A?J?S?\?e?n?w?€?‰?’??¨?´?À?Ë?Ö?á?ì?÷?@ @@#@.@7@ ¦  €¦ €@@E@J@¯ O@ ¯ R@¼ €€D€¼^@h@D¼r@|@†@ƒ@× ”@@¦@¯@¸@N€Á@Ë@Õ@ß@é@ó@ý@Ë  AAA$A}€ „„€ }€}€„-A9AEAQA]AiAuA€A‹A–A¡A®A»AÆAÑAÞAƒƒ ƒ7"ƒ ??ƒ "ëA€¨„õABB#Bƒ1B†8B€BBMBƒZBjB†xBˆBÀo˜B³ ©B¹BÅ ÊBÚB³ ëBûBÅ  CC-C?CROC`CrCRµ‚C”C¦C¶C×  Û Û × ÆCß ÖCµµ µ µèC¹ôCD DD$D” 0D4D€@D ÀصdRID[D^D" "ñ bD ñ iDlD&&& &ÆÆÆ ÆpD{D†D‘DœD§D²D½DÈDÒDÝDçDòDüDEEE.E@EREdEvEˆEšE¬E¾EÐEâEôEFF*FTvDToðËNTê }º }  ¯ð }cC. „ B ‡º‡ ‡ð}‡ê}‡º}‡ }‡ðI VT4 ¯: }fŒ 4:†f†Œ ¯4¯:o¯¯oÙ}}Ùqq— œ }‡q}‡q¸Ñ— }‡œ ++àà¸+¸+¸à¸àT aTjTsT] |T…TŽTJ  ¬ ² VJ}  ¯¬ }² ¸˜¸h}Ë}ÒщїT‡Ë‡Ò”¡T+ 4 ÙªT·TÀTf ÉTÓTÙT}ÞßT¯ }ðC„ r èT'@ævæåvå  ‡ð ‡òTþT UU¸ Ó Ó¸   U ,UÀü3Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‚2NFStboot-1.10.5/tboot/include/vtd.h0000644000000000000000000000465414210363175014606 0ustar 00000000000000/* * vtd.c: VT-d support functions * * Copyright (c) 2019, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __VTD_H__ #define __VTD_H__ #define VTD_OPERATION_TIMEOUT 0x10000000 #define VTD_GCMD_OFFSET 0x18 #define TE_EN (1 << 31) #define QIE_EN (1 << 26) #define IRE_EN (1 << 25) #define VTD_GSTS_OFFSET 0x1C #define TE_STAT (1 << 31) #define QIE_STAT (1 << 26) #define IRE_STAT (1 << 25) #define VTD_IQH_OFFSET 0x80 #define VTD_IQT_OFFSET 0x88 bool vtd_bios_enabled(void); bool vtd_save_dmar_table(void); bool vtd_restore_dmar_table(void); bool vtd_remove_dmar_table(void); struct dmar_remapping *vtd_get_dmar_remap(uint32_t *remap_length); bool vtd_disable_dma_remap(struct dmar_remapping *rs); bool vtd_disable_qie(struct dmar_remapping *rs); bool vtd_disable_ire(struct dmar_remapping *rs); #endiftboot-1.10.5/tboot/txt/acmod.c0000644000000000000000000010753714210363175014267 0ustar 00000000000000/* * acmod.c: support functions for use of Intel(r) TXT Authenticated * Code (AC) Modules * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef IS_INCLUDED /* defined in utils/acminfo.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* IS_INCLUDED */ static acm_info_table_t *get_acmod_info_table(const acm_hdr_t* hdr) { uint32_t user_area_off; /* overflow? */ if ( plus_overflow_u32(hdr->header_len, hdr->scratch_size) ) { printk(TBOOT_ERR"ACM header length plus scratch size overflows\n"); return NULL; } if ( multiply_overflow_u32((hdr->header_len + hdr->scratch_size), 4) ) { printk(TBOOT_ERR"ACM header length and scratch size in bytes overflows\n"); return NULL; } /* this fn assumes that the ACM has already passed at least the initial */ /* is_acmod() checks */ user_area_off = (hdr->header_len + hdr->scratch_size) * 4; /* overflow? */ if ( plus_overflow_u32(user_area_off, sizeof(acm_info_table_t)) ) { printk(TBOOT_ERR"user_area_off plus acm_info_table_t size overflows\n"); return NULL; } /* check that table is within module */ if ( user_area_off + sizeof(acm_info_table_t) > hdr->size*4 ) { printk(TBOOT_ERR"ACM info table size too large: %x\n", user_area_off + (uint32_t)sizeof(acm_info_table_t)); return NULL; } /* overflow? */ if ( plus_overflow_u32((uint32_t)(uintptr_t)hdr, user_area_off) ) { printk(TBOOT_ERR"hdr plus user_area_off overflows\n"); return NULL; } return (acm_info_table_t *)((unsigned long)hdr + user_area_off); } static acm_chipset_id_list_t *get_acmod_chipset_list(const acm_hdr_t* hdr) { acm_info_table_t* info_table; uint32_t size, id_list_off; acm_chipset_id_list_t *chipset_id_list; /* this fn assumes that the ACM has already passed the is_acmod() checks */ info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) return NULL; id_list_off = info_table->chipset_id_list; size = hdr->size * 4; /* overflow? */ if ( plus_overflow_u32(id_list_off, sizeof(acm_chipset_id_list_t)) ) { printk(TBOOT_ERR"id_list_off plus acm_chipset_id_list_t size overflows\n"); return NULL; } /* check that chipset id table is w/in ACM */ if ( id_list_off + sizeof(acm_chipset_id_list_t) > size ) { printk(TBOOT_ERR"ACM chipset id list is too big: chipset_id_list=%x\n", id_list_off); return NULL; } /* overflow? */ if ( plus_overflow_u32((uint32_t)(uintptr_t)hdr, id_list_off) ) { printk(TBOOT_ERR"hdr plus id_list_off overflows\n"); return NULL; } chipset_id_list = (acm_chipset_id_list_t *) ((unsigned long)hdr + id_list_off); /* overflow? */ if ( multiply_overflow_u32(chipset_id_list->count, sizeof(acm_chipset_id_t)) ) { printk(TBOOT_ERR"size of acm_chipset_id_list overflows\n"); return NULL; } if ( plus_overflow_u32(id_list_off + sizeof(acm_chipset_id_list_t), chipset_id_list->count * sizeof(acm_chipset_id_t)) ) { printk(TBOOT_ERR"size of all entries overflows\n"); return NULL; } /* check that all entries are w/in ACM */ if ( id_list_off + sizeof(acm_chipset_id_list_t) + chipset_id_list->count * sizeof(acm_chipset_id_t) > size ) { printk(TBOOT_ERR"ACM chipset id entries are too big:" " chipset_id_list->count=%x\n", chipset_id_list->count); return NULL; } return chipset_id_list; } static acm_processor_id_list_t *get_acmod_processor_list(const acm_hdr_t* hdr) { acm_info_table_t* info_table; uint32_t size, id_list_off; acm_processor_id_list_t *proc_id_list; /* this fn assumes that the ACM has already passed the is_acmod() checks */ info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) return NULL; id_list_off = info_table->processor_id_list; size = hdr->size * 4; /* overflow? */ if ( plus_overflow_u32(id_list_off, sizeof(acm_processor_id_list_t)) ) { printk(TBOOT_ERR"id_list_off plus acm_processor_id_list_t size overflows\n"); return NULL; } /* check that processor id table is w/in ACM */ if ( id_list_off + sizeof(acm_processor_id_list_t) > size ) { printk(TBOOT_ERR"ACM processor id list is too big: processor_id_list=%x\n", id_list_off); return NULL; } /* overflow? */ if ( plus_overflow_u32((unsigned long)hdr, id_list_off) ) { printk(TBOOT_ERR"hdr plus id_list_off overflows\n"); return NULL; } proc_id_list = (acm_processor_id_list_t *) ((unsigned long)hdr + id_list_off); /* overflow? */ if ( multiply_overflow_u32(proc_id_list->count, sizeof(acm_processor_id_t)) ) { printk(TBOOT_ERR"size of acm_processor_id_list overflows\n"); return NULL; } if ( plus_overflow_u32(id_list_off + sizeof(acm_processor_id_list_t), proc_id_list->count * sizeof(acm_processor_id_t)) ) { printk(TBOOT_ERR"size of all entries overflows\n"); return NULL; } /* check that all entries are w/in ACM */ if ( id_list_off + sizeof(acm_processor_id_list_t) + proc_id_list->count * sizeof(acm_processor_id_t) > size ) { printk(TBOOT_ERR"ACM processor id entries are too big:" " proc_id_list->count=%x\n", proc_id_list->count); return NULL; } return proc_id_list; } tpm_info_list_t *get_tpm_info_list(const acm_hdr_t* hdr) { acm_info_table_t* info_table; uint32_t size, tpm_info_off; tpm_info_list_t *tpm_info; /* this fn assumes that the ACM has already passed the is_acmod() checks */ info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) return NULL; tpm_info_off = info_table->tpm_info_list_off; size = hdr->size * 4; /* overflow? */ if ( plus_overflow_u32(tpm_info_off, sizeof(tpm_info_list_t)) ) { printk("tpm_info_off plus tpm_info_list_t size overflows\n"); return NULL; } /* check that tpm info list is w/in ACM */ if ( tpm_info_off + sizeof(tpm_info_list_t) > size ) { printk("TPM info list is too big: tpm_info_list=%x\n", tpm_info_off); return NULL; } /* overflow? */ if ( plus_overflow_u32((unsigned long)hdr, tpm_info_off) ) { printk("hdr plus tpm_info_off overflows\n"); return NULL; } tpm_info = (tpm_info_list_t *) ((unsigned long)hdr + tpm_info_off); /* overflow? */ if ( multiply_overflow_u32(tpm_info->count, sizeof(uint16_t)) ) { printk("size of tpm_info_list overflows\n"); return NULL; } if ( plus_overflow_u32(tpm_info_off + sizeof(tpm_info_list_t), tpm_info->count * sizeof(uint16_t)) ) { printk("size of all entries overflows\n"); return NULL; } /* check that all entries are w/in ACM */ if ( tpm_info_off + sizeof(tpm_info_list_t) + tpm_info->count * sizeof(uint16_t) > size ) { printk("TPM info list entries are too big:" " tpm_info_list->count=%x\n", tpm_info->count); return NULL; } return tpm_info; } void print_txt_caps(const char *prefix, txt_caps_t caps) { printk(TBOOT_DETA"%scapabilities: 0x%08x\n", prefix, caps._raw); printk(TBOOT_DETA"%s rlp_wake_getsec: %d\n", prefix, caps.rlp_wake_getsec); printk(TBOOT_DETA"%s rlp_wake_monitor: %d\n", prefix, caps.rlp_wake_monitor); printk(TBOOT_DETA"%s ecx_pgtbl: %d\n", prefix, caps.ecx_pgtbl); printk(TBOOT_DETA"%s stm: %d\n", prefix, caps.stm); printk(TBOOT_DETA"%s pcr_map_no_legacy: %d\n", prefix, caps.pcr_map_no_legacy); printk(TBOOT_DETA"%s pcr_map_da: %d\n", prefix, caps.pcr_map_da); printk(TBOOT_DETA"%s platform_type: %d\n", prefix, caps.platform_type); printk(TBOOT_DETA"%s max_phy_addr: %d\n", prefix, caps.max_phy_addr); printk(TBOOT_DETA"%s tcg_event_log_format: %d\n", prefix, caps.tcg_event_log_format); printk(TBOOT_DETA"%s cbnt_supported: %d\n", prefix, caps.cbnt_supported); } static void print_acm_hdr(const acm_hdr_t *hdr, const char *mod_name) { acm_info_table_t *info_table; printk(TBOOT_DETA"AC module header dump for %s:\n", (mod_name == NULL) ? "?" : mod_name); /* header */ printk(TBOOT_DETA"\t type: 0x%x ", hdr->module_type); if ( hdr->module_type == ACM_TYPE_CHIPSET ) printk(TBOOT_DETA"(ACM_TYPE_CHIPSET)\n"); else printk(TBOOT_INFO"(unknown)\n"); printk(TBOOT_DETA"\t subtype: 0x%x ", hdr->module_subtype); if ( hdr->module_subtype == ACM_SUBTYPE_RESET ) printk(TBOOT_INFO"(execute at reset)\n"); else if ( hdr->module_subtype == 0 ) printk(TBOOT_INFO"\n"); else printk(TBOOT_INFO"(unknown)\n"); printk(TBOOT_DETA"\t length: 0x%x (%u)\n", hdr->header_len, hdr->header_len); printk(TBOOT_DETA"\t version: %u\n", hdr->header_ver); printk(TBOOT_DETA"\t chipset_id: 0x%x\n", (uint32_t)hdr->chipset_id); printk(TBOOT_DETA"\t flags: 0x%x\n", (uint32_t)hdr->flags._raw); printk(TBOOT_DETA"\t\t pre_production: %d\n", (int)hdr->flags.pre_production); printk(TBOOT_DETA"\t\t debug_signed: %d\n", (int)hdr->flags.debug_signed); printk(TBOOT_DETA"\t vendor: 0x%x\n", hdr->module_vendor); printk(TBOOT_DETA"\t date: 0x%08x\n", hdr->date); printk(TBOOT_DETA"\t size*4: 0x%x (%u)\n", hdr->size*4, hdr->size*4); printk(TBOOT_DETA"\t txt_svn: 0x%08x\n", hdr->txt_svn); printk(TBOOT_DETA"\t se_svn: 0x%08x\n", hdr->se_svn); printk(TBOOT_DETA"\t code_control: 0x%x\n", hdr->code_control); printk(TBOOT_DETA"\t entry point: 0x%08x:%08x\n", hdr->seg_sel, hdr->entry_point); printk(TBOOT_DETA"\t scratch_size: 0x%x (%u)\n", hdr->scratch_size, hdr->scratch_size); /* info table */ printk(TBOOT_DETA"\t info_table:\n"); info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) { printk(TBOOT_ERR"\t\t \n"); return; } printk(TBOOT_DETA"\t\t uuid: "); print_uuid(&info_table->uuid); printk(TBOOT_DETA"\n"); if ( are_uuids_equal(&(info_table->uuid), &((uuid_t)ACM_UUID_V3)) ) printk(TBOOT_DETA"\t\t ACM_UUID_V3\n"); else printk(TBOOT_DETA"\t\t unknown\n"); printk(TBOOT_DETA"\t\t chipset_acm_type: 0x%x ", (uint32_t)info_table->chipset_acm_type); if ( info_table->chipset_acm_type == ACM_CHIPSET_TYPE_SINIT ) printk(TBOOT_DETA"(SINIT)\n"); else if ( info_table->chipset_acm_type == ACM_CHIPSET_TYPE_BIOS ) printk(TBOOT_DETA"(BIOS)\n"); else printk(TBOOT_DETA"(unknown)\n"); printk(TBOOT_DETA"\t\t version: %u\n", (uint32_t)info_table->version); printk(TBOOT_DETA"\t\t length: 0x%x (%u)\n", (uint32_t)info_table->length, (uint32_t)info_table->length); printk(TBOOT_DETA"\t\t chipset_id_list: 0x%x\n", info_table->chipset_id_list); printk(TBOOT_DETA"\t\t os_sinit_data_ver: 0x%x\n", info_table->os_sinit_data_ver); printk(TBOOT_DETA"\t\t min_mle_hdr_ver: 0x%08x\n", info_table->min_mle_hdr_ver); print_txt_caps("\t\t ", info_table->capabilities); printk(TBOOT_DETA"\t\t acm_ver: %u\n", (uint32_t)info_table->acm_ver); if (info_table->version > 6) { printk(TBOOT_DETA"\t\t acm_revision: %x.%x.%x\n", (uint32_t)info_table->acm_revision[0], (uint32_t)info_table->acm_revision[1], (uint32_t)info_table->acm_revision[2]); } /* chipset list */ printk(TBOOT_DETA"\t chipset list:\n"); acm_chipset_id_list_t *chipset_id_list = get_acmod_chipset_list(hdr); if ( chipset_id_list == NULL ) { printk(TBOOT_ERR"\t\t \n"); return; } printk(TBOOT_DETA"\t\t count: %u\n", chipset_id_list->count); for ( unsigned int i = 0; i < chipset_id_list->count; i++ ) { printk(TBOOT_DETA"\t\t entry %u:\n", i); acm_chipset_id_t *chipset_id = &(chipset_id_list->chipset_ids[i]); printk(TBOOT_DETA"\t\t flags: 0x%x\n", chipset_id->flags); printk(TBOOT_DETA"\t\t vendor_id: 0x%x\n", (uint32_t)chipset_id->vendor_id); printk(TBOOT_DETA"\t\t device_id: 0x%x\n", (uint32_t)chipset_id->device_id); printk(TBOOT_DETA"\t\t revision_id: 0x%x\n", (uint32_t)chipset_id->revision_id); printk(TBOOT_DETA"\t\t extended_id: 0x%x\n", chipset_id->extended_id); } if ( info_table->version >= 4 ) { /* processor list */ printk(TBOOT_DETA"\t processor list:\n"); acm_processor_id_list_t *proc_id_list = get_acmod_processor_list(hdr); if ( proc_id_list == NULL ) { printk(TBOOT_ERR"\t\t \n"); return; } printk(TBOOT_DETA"\t\t count: %u\n", proc_id_list->count); for ( unsigned int i = 0; i < proc_id_list->count; i++ ) { printk(TBOOT_DETA"\t\t entry %u:\n", i); acm_processor_id_t *proc_id = &(proc_id_list->processor_ids[i]); printk(TBOOT_DETA"\t\t fms: 0x%x\n", proc_id->fms); printk(TBOOT_DETA"\t\t fms_mask: 0x%x\n", proc_id->fms_mask); printk(TBOOT_DETA"\t\t platform_id: 0x%Lx\n", (unsigned long long)proc_id->platform_id); printk(TBOOT_DETA"\t\t platform_mask: 0x%Lx\n", (unsigned long long)proc_id->platform_mask); } } if ( info_table->version >= 5 ){ /* tpm infor list */ printk(TBOOT_DETA"\t TPM info list:\n"); tpm_info_list_t *info_list = get_tpm_info_list(hdr); if ( info_list == NULL ) { printk(TBOOT_ERR"\t\t \n"); return; } printk(TBOOT_DETA"\t\t TPM capability:\n"); printk(TBOOT_DETA"\t\t ext_policy: 0x%x\n", info_list->capabilities.ext_policy); printk(TBOOT_DETA"\t\t tpm_family : 0x%x\n", info_list->capabilities.tpm_family); printk(TBOOT_DETA"\t\t tpm_nv_index_set : 0x%x\n", info_list->capabilities.tpm_nv_index_set); printk(TBOOT_DETA"\t\t alg count: %u\n", info_list->count); for ( unsigned int i = 0; i < info_list->count; i++ ) { printk(TBOOT_DETA"\t\t alg_id: 0x%x\n", info_list->alg_id[i]); } } } uint32_t get_supported_os_sinit_data_ver(const acm_hdr_t* hdr) { /* assumes that it passed is_sinit_acmod() */ acm_info_table_t *info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) return 0; return info_table->os_sinit_data_ver; } txt_caps_t get_sinit_capabilities(const acm_hdr_t* hdr) { /* assumes that it passed is_sinit_acmod() */ acm_info_table_t *info_table = get_acmod_info_table(hdr); if ( info_table == NULL || info_table->version < 3 ) return (txt_caps_t){ 0 }; return info_table->capabilities; } static bool are_sizes_equal_pad_adjusted(uint32_t acmod_size, acm_hdr_t *acm_hdr) { /* Sizes are equal, so no padding */ if ( acmod_size == (acm_hdr->size * 4) ) { return true; } /* Padding can't be negative */ if ( acmod_size < (acm_hdr->size * 4) ) { return false; } /* Check if padding is in allowed range */ if ( (acmod_size - (acm_hdr->size * 4) >= ACM_SIZE_MIN_PADDING) && (acmod_size - (acm_hdr->size * 4) <= ACM_SIZE_MAX_PADDING) ) { printk(TBOOT_WARN"\t acmod_size=%x, != acm_hdr->size*4=%x" ", padding present (assuming 0x%x padding)\n", acmod_size, acm_hdr->size * 4, acmod_size - (acm_hdr->size * 4)); return true; } return false; } static bool is_acmod(const void *acmod_base, uint32_t acmod_size, uint8_t *type, bool quiet) { acm_hdr_t *acm_hdr = (acm_hdr_t *)acmod_base; /* first check size */ if ( acmod_size < sizeof(acm_hdr_t) ) { if ( !quiet ) printk(TBOOT_ERR"\t ACM size is too small: acmod_size=%x," " sizeof(acm_hdr_t)=%x\n", acmod_size, (uint32_t)sizeof(acm_hdr_t) ); return false; } /* then check overflow */ if ( multiply_overflow_u32(acm_hdr->size, 4) ) { if ( !quiet ) printk(TBOOT_ERR"\t ACM header size in bytes overflows\n"); return false; } /* then check size equivalency */ if ( !are_sizes_equal_pad_adjusted(acmod_size, acm_hdr) ) { if ( !quiet ) printk(TBOOT_ERR"\t ACM size mismatch: acmod_size=%x," " acm_hdr->size*4=%x\n", acmod_size, acm_hdr->size*4); return false; } /* then check type and vendor */ if ( (acm_hdr->module_type != ACM_TYPE_CHIPSET) || (acm_hdr->module_vendor != ACM_VENDOR_INTEL) ) { if ( !quiet ) printk(TBOOT_ERR"\t ACM type/vendor mismatch: module_type=%x," " module_vendor=%x\n", acm_hdr->module_type, acm_hdr->module_vendor); return false; } acm_info_table_t *info_table = get_acmod_info_table(acm_hdr); if ( info_table == NULL ) return false; /* check if ACM UUID is present */ if ( !are_uuids_equal(&(info_table->uuid), &((uuid_t)ACM_UUID_V3)) ) { if ( !quiet ) { printk(TBOOT_ERR"\t unknown UUID: "); print_uuid(&info_table->uuid); printk(TBOOT_ERR"\n"); } return false; } if ( type != NULL ) *type = info_table->chipset_acm_type; if ( info_table->version < 3 ) { if ( !quiet ) printk(TBOOT_ERR"\t ACM info_table version unsupported (%u)\n", (uint32_t)info_table->version); return false; } /* there is forward compatibility, so this is just a warning */ else if ( info_table->version > 7 ) { if ( !quiet ) printk(TBOOT_WARN"\t ACM info_table version mismatch (%u)\n", (uint32_t)info_table->version); } return true; } bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet) { uint8_t type; if ( !is_acmod(acmod_base, acmod_size, &type, quiet) ) return false; if ( type != ACM_CHIPSET_TYPE_BIOS_REVOC && type != ACM_CHIPSET_TYPE_SINIT_REVOC ) { printk(TBOOT_ERR"ACM is not an revocation ACM (%x)\n", type); return false; } if ( acmod_size != 0x8000 && acmod_size != 0x10000 ) { printk(TBOOT_ERR"ACM is not an RACM, bad size (0x%x)\n", acmod_size); return false; } return true; } bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet) { uint8_t type; if ( !is_acmod(acmod_base, acmod_size, &type, quiet) ) return false; if ( type != ACM_CHIPSET_TYPE_SINIT ) { printk(TBOOT_ERR"ACM is not an SINIT ACM (%x)\n", type); return false; } return true; } bool does_acmod_match_platform(const acm_hdr_t* hdr) { /* used to ensure we don't print chipset/proc info for each module */ static bool printed_host_info; /* this fn assumes that the ACM has already passed the is_acmod() checks */ acm_info_table_t *info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) return false; /* verify client/server platform match */ txt_heap_t *txt_heap = get_txt_heap(); bios_data_t *bios_data = get_bios_data_start(txt_heap); if (info_table->version >= 5 && bios_data->version >= 6) { uint32_t bios_type = bios_data->flags.bits.mle.platform_type; uint32_t sinit_type = info_table->capabilities.platform_type; if (bios_type == PLATFORM_TYPE_CLIENT && sinit_type != PLATFORM_TYPE_CLIENT) { printk(TBOOT_ERR"Error: Non-client ACM on client platform\n"); return false; } if (bios_type == PLATFORM_TYPE_SERVER && sinit_type != PLATFORM_TYPE_SERVER) { printk(TBOOT_ERR"Error: Non-server ACM on server platform\n"); return false; } } /* get chipset fusing, device, and vendor id info */ txt_didvid_t didvid; didvid._raw = read_pub_config_reg(TXTCR_DIDVID); txt_ver_fsbif_qpiif_t ver; ver._raw = read_pub_config_reg(TXTCR_VER_FSBIF); if ( (ver._raw & 0xffffffff) == 0xffffffff || (ver._raw & 0xffffffff) == 0x00 ) /* need to use VER.QPIIF */ ver._raw = read_pub_config_reg(TXTCR_VER_QPIIF); if ( !printed_host_info ) { printk(TBOOT_DETA"chipset production fused: %x\n", ver.prod_fused ); printk(TBOOT_DETA"chipset ids: vendor: 0x%x, device: 0x%x, revision: 0x%x\n", didvid.vendor_id, didvid.device_id, didvid.revision_id); } /* get processor family/model/stepping and platform ID */ uint64_t platform_id; uint32_t fms = cpuid_eax(1); platform_id = rdmsr(MSR_IA32_PLATFORM_ID); if ( !printed_host_info ) { printk(TBOOT_DETA"processor family/model/stepping: 0x%x\n", fms ); printk(TBOOT_DETA"platform id: 0x%Lx\n", (unsigned long long)platform_id); } printed_host_info = true; /* * check if chipset fusing is same */ if ( ver.prod_fused != !hdr->flags.debug_signed ) { printk(TBOOT_ERR"\t production/debug mismatch between chipset and ACM\n"); return false; } /* * check if chipset vendor/device/revision IDs match */ acm_chipset_id_list_t *chipset_id_list = get_acmod_chipset_list(hdr); if ( chipset_id_list == NULL ) return false; printk(TBOOT_DETA"\t %x ACM chipset id entries:\n", chipset_id_list->count); unsigned int i; for ( i = 0; i < chipset_id_list->count; i++ ) { acm_chipset_id_t *chipset_id = &(chipset_id_list->chipset_ids[i]); printk(TBOOT_DETA"\t vendor: 0x%x, device: 0x%x, flags: 0x%x, " "revision: 0x%x, extended: 0x%x\n", (uint32_t)chipset_id->vendor_id, (uint32_t)chipset_id->device_id, chipset_id->flags, (uint32_t)chipset_id->revision_id, chipset_id->extended_id); if ( (didvid.vendor_id == chipset_id->vendor_id ) && (didvid.device_id == chipset_id->device_id ) && ( ( ( (chipset_id->flags & 0x1) == 0) && (didvid.revision_id == chipset_id->revision_id) ) || ( ( (chipset_id->flags & 0x1) == 1) && ( (didvid.revision_id & chipset_id->revision_id) != 0 ) ) ) ) break; } if ( i >= chipset_id_list->count ) { printk(TBOOT_ERR"\t chipset id mismatch\n"); return false; } /* * check if processor family/model/stepping and platform IDs match */ if ( info_table->version >= 4 ) { acm_processor_id_list_t *proc_id_list = get_acmod_processor_list(hdr); if ( proc_id_list == NULL ) return false; printk(TBOOT_DETA"\t %x ACM processor id entries:\n", proc_id_list->count); for ( i = 0; i < proc_id_list->count; i++ ) { acm_processor_id_t *proc_id = &(proc_id_list->processor_ids[i]); printk(TBOOT_DETA"\t fms: 0x%x, fms_mask: 0x%x, platform_id: 0x%Lx, " "platform_mask: 0x%Lx\n", proc_id->fms, proc_id->fms_mask, (unsigned long long)proc_id->platform_id, (unsigned long long)proc_id->platform_mask); if ( (proc_id->fms == (fms & proc_id->fms_mask)) && (proc_id->platform_id == (platform_id & proc_id->platform_mask)) ) break; } if ( i >= proc_id_list->count ) { printk(TBOOT_ERR"\t processor mismatch\n"); return false; } } return true; } #ifndef IS_INCLUDED acm_hdr_t *get_bios_sinit(const void *sinit_region_base) { if ( sinit_region_base == NULL ) return NULL; txt_heap_t *txt_heap = get_txt_heap(); bios_data_t *bios_data = get_bios_data_start(txt_heap); if ( bios_data->bios_sinit_size == 0 ) return NULL; /* BIOS has loaded an SINIT module, so verify that it is valid */ printk(TBOOT_INFO"BIOS has already loaded an SINIT module\n"); /* is it a valid SINIT module? */ if ( !is_sinit_acmod(sinit_region_base, bios_data->bios_sinit_size, false) || !does_acmod_match_platform((acm_hdr_t *)sinit_region_base) ) return NULL; return (acm_hdr_t *)sinit_region_base; } static void *alloc_racm_region(uint32_t size) { /* TODO: find a real unused memory place through mbi */ return (void *)(long)(0x2000000 + size - size); /* 32M */ } acm_hdr_t *copy_racm(const acm_hdr_t *racm) { /* find a 32KB aligned memory */ uint32_t racm_region_size = racm->size*4; void *racm_region_base = alloc_racm_region(racm_region_size); printk(TBOOT_DETA"RACM.BASE: %p\n", racm_region_base); printk(TBOOT_DETA"RACM.SIZE: 0x%x (%u)\n", racm_region_size, racm_region_size); /* copy it there */ tb_memcpy(racm_region_base, racm, racm->size*4); printk(TBOOT_DETA"copied RACM (size=%x) to %p\n", racm->size*4, racm_region_base); return (acm_hdr_t *)racm_region_base; } acm_hdr_t *copy_sinit(const acm_hdr_t *sinit) { /* get BIOS-reserved region from TXT.SINIT.BASE config reg */ void *sinit_region_base = (void*)(unsigned long)read_pub_config_reg(TXTCR_SINIT_BASE); uint32_t sinit_region_size = (uint32_t)read_pub_config_reg(TXTCR_SINIT_SIZE); printk(TBOOT_DETA"TXT.SINIT.BASE: %p\n", sinit_region_base); printk(TBOOT_DETA"TXT.SINIT.SIZE: 0x%x (%u)\n", sinit_region_size, sinit_region_size); /* * check if BIOS already loaded an SINIT module there */ acm_hdr_t *bios_sinit = get_bios_sinit(sinit_region_base); if ( bios_sinit != NULL ) { /* no other SINIT was provided so must use one BIOS provided */ if ( sinit == NULL ) { printk(TBOOT_WARN"no SINIT provided by bootloader; using BIOS SINIT\n"); return bios_sinit; } /* is it newer than the one we've been provided? */ if ( bios_sinit->date >= sinit->date ) { printk(TBOOT_INFO"BIOS-provided SINIT is newer, so using it\n"); return bios_sinit; /* yes */ } else printk(TBOOT_INFO"BIOS-provided SINIT is older: date=%x\n", bios_sinit->date); } /* our SINIT is newer than BIOS's (or BIOS did not have one) */ /* BIOS SINIT not present or not valid and none provided */ if ( sinit == NULL ) return NULL; /* overflow? */ if ( multiply_overflow_u32(sinit->size, 4) ) { printk(TBOOT_ERR"sinit size in bytes overflows\n"); return NULL; } /* make sure our SINIT fits in the reserved region */ if ( (sinit->size * 4) > sinit_region_size ) { printk(TBOOT_ERR"BIOS-reserved SINIT size (%x) is too small for loaded " "SINIT (%x)\n", sinit_region_size, sinit->size*4); return NULL; } if ( sinit_region_base == NULL ) return NULL; /* copy it there */ tb_memcpy(sinit_region_base, sinit, sinit->size*4); printk(TBOOT_DETA"copied SINIT (size=%x) to %p\n", sinit->size*4, sinit_region_base); return (acm_hdr_t *)sinit_region_base; } #endif /* IS_INCLUDED */ bool verify_racm(const acm_hdr_t *acm_hdr) { getsec_parameters_t params; uint32_t size; /* assumes this already passed is_acmod() test */ size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */ /* * AC mod must start on 4k page boundary */ if ( (unsigned long)acm_hdr & 0xfff ) { printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr); return false; } printk(TBOOT_INFO"AC mod base alignment OK\n"); /* AC mod size must: * - be multiple of 64 * - greater than ??? * - less than max supported size for this processor */ if ( (size == 0) || ((size % 64) != 0) ) { printk(TBOOT_ERR"AC mod size %x bogus\n", size); return false; } if ( !get_parameters(¶ms) ) { printk(TBOOT_ERR"get_parameters() failed\n"); return false; } if ( size > params.acm_max_size ) { printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size, params.acm_max_size); return false; } printk(TBOOT_INFO"AC mod size OK\n"); /* * perform checks on AC mod structure */ /* print it for debugging */ print_acm_hdr(acm_hdr, "RACM"); /* entry point is offset from base addr so make sure it is within module */ if ( acm_hdr->entry_point >= size ) { printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n", acm_hdr->entry_point, size); return false; } /* overflow? */ if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) { printk(TBOOT_ERR"seg_sel plus 8 overflows\n"); return false; } if ( !acm_hdr->seg_sel || /* invalid selector */ (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */ (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) { printk(TBOOT_ERR"AC mod selector [%04x] bogus\n", acm_hdr->seg_sel); return false; } return true; } /* * Do some AC module sanity checks because any violations will cause * an TXT.RESET. Instead detect these, print a desriptive message, * and skip SENTER/ENTERACCS */ #ifndef IS_INCLUDED /* defined in utils/acminfo.c */ void verify_IA32_se_svn_status(const acm_hdr_t *acm_hdr) { struct tpm_if *tpm = get_tpm(); const struct tpm_if_fp *tpm_fp = get_tpm_fp(); printk(TBOOT_INFO"SGX:verify_IA32_se_svn_status is called\n"); //check if SGX is enabled by cpuid with ax=7, cx=0 if ((cpuid_ebx1(7,0) & 0x00000004) == 0){ printk(TBOOT_ERR"SGX is not enabled, cpuid.ebx: 0x%x\n", cpuid_ebx1(7,0)); return; } printk(TBOOT_INFO"SGX is enabled, cpuid.ebx:0x%x\n", cpuid_ebx1(7,0)); printk(TBOOT_INFO"Comparing se_svn with ACM Header se_svn\n"); if (((rdmsr(MSR_IA32_SE_SVN_STATUS)>>16) & 0xff) != acm_hdr->se_svn) { printk(TBOOT_INFO"se_svn is not equal to ACM se_svn\n"); if (!tpm_fp->nv_write(tpm, 0, tpm->sgx_svn_index, 0, (uint8_t *)&(acm_hdr->se_svn), 1)) printk(TBOOT_ERR"Write sgx_svn_index 0x%x failed. \n", tpm->sgx_svn_index); else printk(TBOOT_INFO"Write sgx_svn_index with 0x%x successful.\n", acm_hdr->se_svn); if ((rdmsr(MSR_IA32_SE_SVN_STATUS) & 0X00000001) !=0) /* reset platform */ // printk(TBOOT_INFO"SGX:A reset is required in this boot\n"); outb(0xcf9, 0x06); } else printk(TBOOT_INFO"se_svn is equal to ACM se_svn\n"); } bool verify_acmod(const acm_hdr_t *acm_hdr) { getsec_parameters_t params; uint32_t size; /* assumes this already passed is_acmod() test */ size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */ /* * AC mod must start on 4k page boundary */ if ( (unsigned long)acm_hdr & 0xfff ) { printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr); return false; } printk(TBOOT_INFO"AC mod base alignment OK\n"); /* AC mod size must: * - be multiple of 64 * - greater than ??? * - less than max supported size for this processor */ if ( (size == 0) || ((size % 64) != 0) ) { printk(TBOOT_ERR"AC mod size %x bogus\n", size); return false; } if ( !get_parameters(¶ms) ) { printk(TBOOT_ERR"get_parameters() failed\n"); return false; } if ( size > params.acm_max_size ) { printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size, params.acm_max_size); return false; } printk(TBOOT_INFO"AC mod size OK\n"); /* * perform checks on AC mod structure */ /* print it for debugging */ print_acm_hdr(acm_hdr, "SINIT"); /* entry point is offset from base addr so make sure it is within module */ if ( acm_hdr->entry_point >= size ) { printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n", acm_hdr->entry_point, size); return false; } /* overflow? */ if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) { printk(TBOOT_ERR"seg_sel plus 8 overflows\n"); return false; } if ( !acm_hdr->seg_sel || /* invalid selector */ (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */ (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) { printk(TBOOT_ERR"AC mod selector [%04x] bogus\n", acm_hdr->seg_sel); return false; } /* * check for compatibility with this MLE */ acm_info_table_t *info_table = get_acmod_info_table(acm_hdr); if ( info_table == NULL ) return false; /* check MLE header versions */ if ( info_table->min_mle_hdr_ver > MLE_HDR_VER ) { printk(TBOOT_ERR"AC mod requires a newer MLE (0x%08x)\n", info_table->min_mle_hdr_ver); return false; } /* check capabilities */ /* we need to match one of rlp_wake_{getsec, monitor} */ txt_caps_t caps_mask = { 0 }; caps_mask.rlp_wake_getsec = caps_mask.rlp_wake_monitor = 1; if ( ( ( MLE_HDR_CAPS & caps_mask._raw ) & ( info_table->capabilities._raw & caps_mask._raw) ) == 0 ) { printk(TBOOT_ERR"SINIT and MLE not support compatible RLP wake mechanisms\n"); return false; } /* we also expect ecx_pgtbl to be set */ if ( !info_table->capabilities.ecx_pgtbl ) { printk(TBOOT_ERR"SINIT does not support launch with MLE pagetable in ECX\n"); /* TODO when SINIT ready * return false; */ } /* check for version of OS to SINIT data */ /* we don't support old versions */ if ( info_table->os_sinit_data_ver < MIN_OS_SINIT_DATA_VER ) { printk(TBOOT_ERR"SINIT's os_sinit_data version unsupported (%u)\n", info_table->os_sinit_data_ver); return false; } /* only warn if SINIT supports more recent version than us */ else if ( info_table->os_sinit_data_ver > MAX_OS_SINIT_DATA_VER ) { printk(TBOOT_WARN"SINIT's os_sinit_data version unsupported (%u)\n", info_table->os_sinit_data_ver); } return true; } #endif /* IS_INCLUDED */ /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/txt/errors.c0000644000000000000000000002253114210363175014506 0ustar 00000000000000/* * errors.c: parse and return status of Intel(r) TXT error codes * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include void txt_display_errors(void) { txt_errorcode_t err; txt_ests_t ests; txt_e2sts_t e2sts; txt_errorcode_sw_t sw_err; acmod_error_t acmod_err; /* * display TXT.ERRORODE error */ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); if (txt_has_error() == false) printk(TBOOT_INFO"TXT.ERRORCODE: 0x%Lx\n", err._raw); else printk(TBOOT_ERR"TXT.ERRORCODE: 0x%Lx\n", err._raw); /* AC module error (don't know how to parse other errors) */ if ( err.valid ) { if ( err.external == 0 ) /* processor error */ printk(TBOOT_ERR"\t processor error 0x%x\n", (uint32_t)err.type); else { /* external SW error */ sw_err._raw = err.type; if ( sw_err.src == 1 ) /* unknown SW error */ printk(TBOOT_ERR"unknown SW error 0x%x:0x%x\n", sw_err.err1, sw_err.err2); else { /* ACM error */ acmod_err._raw = sw_err._raw; if ( acmod_err._raw == 0x0 || acmod_err._raw == 0x1 || acmod_err._raw == 0x9 ) printk(TBOOT_INFO"AC module error : acm_type=0x%x, progress=0x%02x, " "error=0x%x\n", acmod_err.acm_type, acmod_err.progress, acmod_err.error); else printk(TBOOT_ERR"AC module error : acm_type=0x%x, progress=0x%02x, " "error=0x%x\n", acmod_err.acm_type, acmod_err.progress, acmod_err.error); /* error = 0x0a, progress = 0x0d => TPM error */ if ( acmod_err.error == 0x0a && acmod_err.progress == 0x0d ) printk(TBOOT_ERR"TPM error code = 0x%x\n", acmod_err.tpm_err); /* progress = 0x10 => LCP2 error */ else if ( acmod_err.progress == 0x10 && acmod_err.lcp_minor != 0 ) printk(TBOOT_ERR"LCP2 error: minor error = 0x%x, index = %u\n", acmod_err.lcp_minor, acmod_err.lcp_index); } } } /* * display TXT.ESTS error */ ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS); if (ests._raw == 0) printk(TBOOT_INFO"TXT.ESTS: 0x%Lx\n", ests._raw); else printk(TBOOT_ERR"TXT.ESTS: 0x%Lx\n", ests._raw); /* * display TXT.E2STS error */ e2sts = (txt_e2sts_t)read_pub_config_reg(TXTCR_E2STS); if (e2sts._raw == 0 || e2sts._raw == 0x200000000) printk(TBOOT_INFO"TXT.E2STS: 0x%Lx\n", e2sts._raw); else printk(TBOOT_ERR"TXT.E2STS: 0x%Lx\n", e2sts._raw); } bool txt_has_error(void) { txt_errorcode_t err; err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); if (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009) { return false; } else { return true; } } #define CLASS_ACM_ENTRY 0x1 enum ENUM_ACM_ENTRY { ERR_LAUNCH = 1, ERR_NEM_ENABLED, ERR_CPU_LT_TYPE, ERR_DEV_ID, ERR_CPU_ID, ERR_NO_UCODE_UPDATE , ERR_DEBUG_MCU, ERR_DMI_LINK_DOWN, ERR_ACM_REVOKED, ERR_TPM_DOUBLE_AUX }; #define CLASS_TPM_ACCESS 0x4 enum ENUM_TPM_ACCESS { ERR_OK, /* Indicator of successful execution of the function.*/ ERR_TPM_ERROR, /* TPM returned an error */ ERR_LOCALITY, ERR_ACC_INVLD, ERR_NV_UNLOCKED, /* TPM NV RAM not locked */ ERR_TPM_DISABLED, /* TPM is disabled */ ERR_TPM_DEACTIVATED, /* TPM is deactivated */ ERR_TPM_NV_INDEX_INVALID, /* TPM NV indices incorrectly defined */ ERR_TPM_INCOMPET_BIOSAC, /* Incompatible BIOS ACM */ ERR_TPM_INCOMPET_AUXREV, /* Incompatible AUX revision */ ERR_TPM_INBUF_TOO_SHORT, /* Input buffer is too short */ ERR_TPM_OUTBUF_TOO_SHORT, /* Output buffer is too short */ ERR_TPM_NV_PO_INDEX_INVALID = 0x10, /* * Errors returned by TPM driver */ ERR_OUTPUT_BUFFER_TOO_SHORT = 0x1B, /* Output buffer for the TPM response to short */ ERR_INVALID_INPUT_PARA = 0x1C, /* Input parameter for the function invalid */ ERR_INVALID_RESPONSE_WR = 0x1D, /* The response from the TPM was invalid */ ERR_INVALID_RESPONSE_RD = 0x1E, /* The response from the TPM was invalid */ ERR_RESPONSE_TIMEOUT = 0x1F /* Time out for TPM response */ }; #define CLASS_MISC_CONFIG 0x8 enum ENUM_MISC_CONFIG { ERR_INTERRUPT = 1, ERR_FORBIDDEN_BY_OWNER = 0x10, ERR_TOOL_LAUNCH, ERR_CANNOT_REVERSE, ERR_ALREADY_REVOKED, ERR_INVALID_RETURN_ADDR, ERR_NO_TPM, }; void txt_get_racm_error(void) { txt_errorcode_t err; acmod_error_t acmod_err; /* * display TXT.ERRORODE error */ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); /* AC module error (don't know how to parse other errors) */ if ( err.valid == 0 ) { printk(TBOOT_ERR "Cannot retrieve status - ERRORSTS register is not valid.\n"); return; } if ( err.external == 0 ) { /* processor error */ printk(TBOOT_ERR"CPU generated error 0x%x\n", (uint32_t)err.type); return; } acmod_err._raw = err.type; if ( acmod_err.src == 1 ) { printk(TBOOT_ERR"Unknown SW error.\n"); return; } if ( acmod_err.acm_type != 0x9 ) { printk(TBOOT_ERR "Cannot retrieve status - wrong ACM type in ERRORSTS register.\n"); return; } if ( acmod_err.progress == CLASS_ACM_ENTRY && acmod_err.error == ERR_TPM_DOUBLE_AUX ) { printk(TBOOT_ERR "Nothing to do: double AUX index is not valid TXT configuration.\n"); return; } if ( acmod_err.progress == CLASS_TPM_ACCESS && acmod_err.error == ERR_TPM_NV_INDEX_INVALID ) { printk(TBOOT_ERR "Nothing to do: invalid AUX index attributes.\n"); return; } if ( acmod_err.progress == CLASS_TPM_ACCESS && acmod_err.error == ERR_TPM_NV_PO_INDEX_INVALID ) { printk(TBOOT_ERR "Error: invalid PO index attributes.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_ALREADY_REVOKED ) { printk(TBOOT_ERR "Nothing to do: already revoked.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_FORBIDDEN_BY_OWNER ) { printk(TBOOT_ERR "Error: revocation forbidden by owner.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_CANNOT_REVERSE ) { printk(TBOOT_ERR "Error: cannot decrement revocation version.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_INVALID_RETURN_ADDR ) { printk(TBOOT_ERR "Error: invalid input address of return point.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_NO_TPM ) { printk(TBOOT_ERR "Nothing to do: No TPM present.\n"); return; } if ( acmod_err.progress == 0 && acmod_err.error == 0 ) { printk(TBOOT_INFO "Success: Revocation completed.\n"); return; } printk(TBOOT_ERR"RACM generated error 0x%Lx.\n", err._raw); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/txt/heap.c0000644000000000000000000010500214210363175014102 0ustar 00000000000000/* * heap.c: fns for verifying and printing the Intel(r) TXT heap data structs * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef IS_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* * extended data elements */ /* HEAP_BIOS_SPEC_VER_ELEMENT */ static void print_bios_spec_ver_elt(const heap_ext_data_element_t *elt) { const heap_bios_spec_ver_elt_t *bios_spec_ver_elt = (const heap_bios_spec_ver_elt_t *)elt->data; printk(TBOOT_INFO"\t\t BIOS_SPEC_VER:\n"); printk(TBOOT_INFO"\t\t major: 0x%x\n", bios_spec_ver_elt->spec_ver_major); printk(TBOOT_INFO"\t\t minor: 0x%x\n", bios_spec_ver_elt->spec_ver_minor); printk(TBOOT_INFO"\t\t rev: 0x%x\n", bios_spec_ver_elt->spec_ver_rev); } /* HEAP_ACM_ELEMENT */ static void print_acm_elt(const heap_ext_data_element_t *elt) { const heap_acm_elt_t *acm_elt = (const heap_acm_elt_t *)elt->data; printk(TBOOT_DETA"\t\t ACM:\n"); printk(TBOOT_DETA"\t\t num_acms: %u\n", acm_elt->num_acms); for ( unsigned int i = 0; i < acm_elt->num_acms; i++ ) printk(TBOOT_DETA"\t\t acm_addrs[%u]: 0x%jx\n", i, acm_elt->acm_addrs[i]); } /* HEAP_CUSTOM_ELEMENT */ static void print_custom_elt(const heap_ext_data_element_t *elt) { const heap_custom_elt_t *custom_elt = (const heap_custom_elt_t *)elt->data; printk(TBOOT_DETA"\t\t CUSTOM:\n"); printk(TBOOT_DETA"\t\t size: %u\n", elt->size); printk(TBOOT_DETA"\t\t uuid: "); print_uuid(&custom_elt->uuid); printk(TBOOT_DETA"\n"); } /* HEAP_EVENT_LOG_POINTER_ELEMENT */ static inline void print_heap_hash(const sha1_hash_t hash) { print_hash((const tb_hash_t *)hash, TB_HALG_SHA1); } void print_event(const tpm12_pcr_event_t *evt) { printk(TBOOT_DETA"\t\t\t Event:\n"); printk(TBOOT_DETA"\t\t\t PCRIndex: %u\n", evt->pcr_index); printk(TBOOT_DETA"\t\t\t Type: 0x%x\n", evt->type); printk(TBOOT_DETA"\t\t\t Digest: "); print_heap_hash(evt->digest); printk(TBOOT_DETA"\t\t\t Data: %u bytes", evt->data_size); print_hex("\t\t\t ", evt->data, evt->data_size); } static void print_evt_log(const event_log_container_t *elog) { printk(TBOOT_DETA"\t\t\t Event Log Container:\n"); printk(TBOOT_DETA"\t\t\t Signature: %s\n", elog->signature); printk(TBOOT_DETA"\t\t\t ContainerVer: %u.%u\n", elog->container_ver_major, elog->container_ver_minor); printk(TBOOT_DETA"\t\t\t PCREventVer: %u.%u\n", elog->pcr_event_ver_major, elog->pcr_event_ver_minor); printk(TBOOT_DETA"\t\t\t Size: %u\n", elog->size); printk(TBOOT_DETA"\t\t\t EventsOffset: [%u,%u]\n", elog->pcr_events_offset, elog->next_event_offset); const tpm12_pcr_event_t *curr, *next; curr = (tpm12_pcr_event_t *)((void*)elog + elog->pcr_events_offset); next = (tpm12_pcr_event_t *)((void*)elog + elog->next_event_offset); while ( curr < next ) { print_event(curr); curr = (void *)curr + sizeof(*curr) + curr->data_size; } } static void print_evt_log_ptr_elt(const heap_ext_data_element_t *elt) { const heap_event_log_ptr_elt_t *elog_elt = (const heap_event_log_ptr_elt_t *)elt->data; printk(TBOOT_DETA"\t\t EVENT_LOG_POINTER:\n"); printk(TBOOT_DETA"\t\t size: %u\n", elt->size); printk(TBOOT_DETA"\t\t elog_addr: 0x%jx\n", elog_elt->event_log_phys_addr); if ( elog_elt->event_log_phys_addr ) print_evt_log((event_log_container_t *)(unsigned long) elog_elt->event_log_phys_addr); } void print_event_2(void *evt, uint16_t alg) { uint32_t hash_size, data_size; void *next = evt; hash_size = get_hash_size(alg); if ( hash_size == 0 ) return; printk(TBOOT_DETA"\t\t\t Event:\n"); printk(TBOOT_DETA"\t\t\t PCRIndex: %u\n", *((uint32_t *)next)); if ( *((uint32_t *)next) > 24 && *((uint32_t *)next) != 0xFF ) { printk(TBOOT_DETA"\t\t\t Wrong Event Log.\n"); return; } next += sizeof(uint32_t); printk(TBOOT_DETA"\t\t\t Type: 0x%x\n", *((uint32_t *)next)); if ( *((uint32_t *)next) > 0xFFF ) { printk(TBOOT_DETA"\t\t\t Wrong Event Log.\n"); return; } next += sizeof(uint32_t); printk(TBOOT_DETA"\t\t\t Digest: "); print_hex(NULL, (uint8_t *)next, hash_size); next += hash_size; data_size = *(uint32_t *)next; printk(TBOOT_DETA"\t\t\t Data: %u bytes", data_size); if ( data_size > 4096 ) { printk(TBOOT_DETA"\t\t\t Wrong Event Log.\n"); return; } next += sizeof(uint32_t); if ( data_size ) print_hex("\t\t\t ", (uint8_t *)next, data_size); else printk(TBOOT_DETA"\n"); } uint32_t print_event_2_1_log_header(void *evt) { tcg_pcr_event *evt_ptr = (tcg_pcr_event *)evt; tcg_efi_specid_event_strcut *evt_data_ptr = (tcg_efi_specid_event_strcut *) evt_ptr->event_data; printk(TBOOT_DETA"\t TCG Event Log Header:\n"); printk(TBOOT_DETA"\t\t pcr_index: %u\n", evt_ptr->pcr_index); printk(TBOOT_DETA"\t\t event_type: %u\n", evt_ptr->event_type); printk(TBOOT_DETA"\t\t digest: %s\n", evt_ptr->digest); printk(TBOOT_DETA"\t\t event_data_size: %u\n", evt_ptr->event_data_size); // print out event log header data printk(TBOOT_DETA"\t\t header event data: \n"); printk(TBOOT_DETA"\t\t\t signature: %s\n", evt_data_ptr->signature); printk(TBOOT_DETA"\t\t\t platform_class: %u\n", evt_data_ptr->platform_class); printk(TBOOT_DETA"\t\t\t spec_version_major: %u\n", evt_data_ptr->spec_version_major); printk(TBOOT_DETA"\t\t\t spec_version_minor: %u\n", evt_data_ptr->spec_version_minor); printk(TBOOT_DETA"\t\t\t spec_errata: %u\n", evt_data_ptr->spec_errata); printk(TBOOT_DETA"\t\t\t uintn_size: %u\n", evt_data_ptr->uintn_size); printk(TBOOT_DETA"\t\t\t number_of_algorithms: %u\n", evt_data_ptr->number_of_algorithms); for ( uint32_t i = 0; i < evt_data_ptr->number_of_algorithms; i++ ) { printk(TBOOT_DETA"\t\t\t\t algorithm_id: 0x%x \n", evt_data_ptr->digestSizes[i].algorithm_id); printk(TBOOT_DETA"\t\t\t\t digest_size: %u\n", evt_data_ptr->digestSizes[i].digest_size); } printk(TBOOT_DETA"\t\t\t vendor_info: %u bytes\n", evt_data_ptr->vendor_info_size); print_hex(NULL, evt_data_ptr->vendor_info, evt_data_ptr->vendor_info_size); return evt_ptr->event_data_size; } uint32_t print_event_2_1(void *evt) { tcg_pcr_event2 *evt_ptr = (tcg_pcr_event2 *)evt; uint8_t *evt_data_ptr; uint16_t hash_alg; uint32_t event_size = 0; printk(TBOOT_DETA"\t\t\t TCG Event:\n"); printk(TBOOT_DETA"\t\t\t pcr_index: %u\n", evt_ptr->pcr_index); printk(TBOOT_DETA"\t\t\t event_type: 0x%x\n", evt_ptr->event_type); printk(TBOOT_DETA"\t\t\t count: %u\n", evt_ptr->digest.count); if (evt_ptr->digest.count != 0) { evt_data_ptr = (uint8_t *)evt_ptr->digest.digests[0].digest; hash_alg = evt_ptr->digest.digests[0].hash_alg; for ( uint32_t i = 0; i < evt_ptr->digest.count; i++ ) { switch (hash_alg) { case TB_HALG_SHA1: printk(TBOOT_INFO"SHA1: \n"); print_hex(NULL, evt_data_ptr, SHA1_LENGTH); evt_data_ptr += SHA1_LENGTH; break; case TB_HALG_SHA256: printk(TBOOT_INFO"SHA256: \n"); print_hex(NULL, evt_data_ptr, SHA256_LENGTH); evt_data_ptr += SHA256_LENGTH; break; case TB_HALG_SM3: printk(TBOOT_INFO"SM3_256: \n"); print_hex(NULL, evt_data_ptr, SM3_LENGTH); evt_data_ptr += SM3_LENGTH; break; case TB_HALG_SHA384: printk(TBOOT_INFO"SHA384: \n"); print_hex(NULL, evt_data_ptr, SHA384_LENGTH); evt_data_ptr += SHA384_LENGTH; break; case TB_HALG_SHA512: printk(TBOOT_INFO"SHA512: \n"); print_hex(NULL, evt_data_ptr, SHA512_LENGTH); evt_data_ptr += SHA512_LENGTH; break; default: printk(TBOOT_ERR"Unsupported algorithm: %u\n", evt_ptr->digest.digests[i].hash_alg); } hash_alg = (uint16_t)*evt_data_ptr; evt_data_ptr += sizeof(uint16_t); } evt_data_ptr -= sizeof(uint16_t); event_size = (uint32_t)*evt_data_ptr; printk(TBOOT_DETA"\t\t\t event_data: %u bytes", event_size); evt_data_ptr += sizeof(uint32_t); print_hex("\t\t\t ", evt_data_ptr, event_size); } else { printk(TBOOT_DETA"sth wrong in TCG event log: algorithm count = %u\n", evt_ptr->digest.count); evt_data_ptr= (uint8_t *)evt +12; } return (evt_data_ptr + event_size - (uint8_t *)evt); } static void print_evt_log_ptr_elt_2(const heap_ext_data_element_t *elt) { const heap_event_log_ptr_elt2_t *elog_elt = (const heap_event_log_ptr_elt2_t *)elt->data; const heap_event_log_descr_t *log_descr; printk(TBOOT_DETA"\t\t EVENT_LOG_PTR:\n"); printk(TBOOT_DETA"\t\t size: %u\n", elt->size); printk(TBOOT_DETA"\t\t count: %d\n", elog_elt->count); for ( unsigned int i=0; icount; i++ ) { log_descr = &elog_elt->event_log_descr[i]; printk(TBOOT_DETA"\t\t\t Log Descrption:\n"); printk(TBOOT_DETA"\t\t\t Alg: %u\n", log_descr->alg); printk(TBOOT_DETA"\t\t\t Size: %u\n", log_descr->size); printk(TBOOT_DETA"\t\t\t EventsOffset: [%u,%u]\n", log_descr->pcr_events_offset, log_descr->next_event_offset); if (log_descr->pcr_events_offset == log_descr->next_event_offset) { printk(TBOOT_DETA"\t\t\t No Event Log.\n"); continue; } uint32_t hash_size, data_size; hash_size = get_hash_size(log_descr->alg); if ( hash_size == 0 ) return; void *curr, *next; curr = (void *)(unsigned long)log_descr->phys_addr + log_descr->pcr_events_offset; next = (void *)(unsigned long)log_descr->phys_addr + log_descr->next_event_offset; //It is required for each of the non-SHA1 event log the first entry to be the following //TPM1.2 style TCG_PCR_EVENT record specifying type of the log: //TCG_PCR_EVENT.PCRIndex = 0 //TCG_PCR_EVENT.EventType = 0x03 // EV_NO_ACTION per TCG EFI // Platform specification //TCG_PCR_EVENT.Digest = {00…00} // 20 zeros //TCG_PCR_EVENT.EventDataSize = sizeof(TCG_LOG_DESCRIPTOR). //TCG_PCR_EVENT.EventData = TCG_LOG_DESCRIPTOR //The digest of this record MUST NOT be extended into any PCR. if (log_descr->alg != TB_HALG_SHA1){ print_event_2(curr, TB_HALG_SHA1); curr += sizeof(tpm12_pcr_event_t) + sizeof(tpm20_log_descr_t); } while ( curr < next ) { print_event_2(curr, log_descr->alg); data_size = *(uint32_t *)(curr + 2*sizeof(uint32_t) + hash_size); curr += 3*sizeof(uint32_t) + hash_size + data_size; } } } static void print_evt_log_ptr_elt_2_1(const heap_ext_data_element_t *elt) { const heap_event_log_ptr_elt2_1_t *elog_elt = (const heap_event_log_ptr_elt2_1_t *)elt->data; printk(TBOOT_DETA"\t TCG EVENT_LOG_PTR:\n"); printk(TBOOT_DETA"\t\t type: %d\n", elt->type); printk(TBOOT_DETA"\t\t size: %u\n", elt->size); printk(TBOOT_DETA"\t TCG Event Log Descrption:\n"); printk(TBOOT_DETA"\t allcoated_event_container_size: %u\n", elog_elt->allcoated_event_container_size); printk(TBOOT_DETA"\t EventsOffset: [%u,%u]\n", elog_elt->first_record_offset, elog_elt->next_record_offset); if (elog_elt->first_record_offset == elog_elt->next_record_offset) { printk(TBOOT_DETA"\t\t\t No Event Log found.\n"); return; } void *curr, *next; curr = (void *)(unsigned long)elog_elt->phys_addr + elog_elt->first_record_offset; next = (void *)(unsigned long)elog_elt->phys_addr + elog_elt->next_record_offset; uint32_t event_header_data_size = print_event_2_1_log_header(curr); curr += sizeof(tcg_pcr_event) + event_header_data_size; while ( curr < next ) { curr += print_event_2_1(curr); } } static void print_ext_data_elts(const heap_ext_data_element_t elts[]) { const heap_ext_data_element_t *elt = elts; printk(TBOOT_DETA"\t ext_data_elts[]:\n"); while ( elt->type != HEAP_EXTDATA_TYPE_END ) { switch ( elt->type ) { case HEAP_EXTDATA_TYPE_BIOS_SPEC_VER: print_bios_spec_ver_elt(elt); break; case HEAP_EXTDATA_TYPE_ACM: print_acm_elt(elt); break; case HEAP_EXTDATA_TYPE_CUSTOM: print_custom_elt(elt); break; case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR: print_evt_log_ptr_elt(elt); break; case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2: print_evt_log_ptr_elt_2(elt); break; case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2_1: print_evt_log_ptr_elt_2_1(elt); break; default: printk(TBOOT_WARN"\t\t unknown element: type: %u, size: %u\n", elt->type, elt->size); break; } elt = (void *)elt + elt->size; } } static void print_bios_data(const bios_data_t *bios_data, uint64_t size) { printk(TBOOT_DETA"bios_data (@%p, %jx):\n", bios_data, *((uint64_t *)bios_data - 1)); printk(TBOOT_DETA"\t version: %u\n", bios_data->version); printk(TBOOT_DETA"\t bios_sinit_size: 0x%x (%u)\n", bios_data->bios_sinit_size, bios_data->bios_sinit_size); printk(TBOOT_DETA"\t lcp_pd_base: 0x%jx\n", bios_data->lcp_pd_base); printk(TBOOT_DETA"\t lcp_pd_size: 0x%jx (%ju)\n", bios_data->lcp_pd_size, bios_data->lcp_pd_size); printk(TBOOT_DETA"\t num_logical_procs: %u\n", bios_data->num_logical_procs); if ( bios_data->version >= 3 ) printk(TBOOT_DETA"\t flags: 0x%08jx\n", bios_data->flags.raw); if ( bios_data->version >= 4 && size > sizeof(*bios_data) + sizeof(size) ) print_ext_data_elts(bios_data->ext_data_elts); } #ifndef IS_INCLUDED static bool verify_bios_spec_ver_elt(const heap_ext_data_element_t *elt) { const heap_bios_spec_ver_elt_t *bios_spec_ver_elt = (const heap_bios_spec_ver_elt_t *)elt->data; if ( elt->size != sizeof(*elt) + sizeof(*bios_spec_ver_elt) ) { printk(TBOOT_ERR"HEAP_BIOS_SPEC_VER element has wrong size (%u)\n", elt->size); return false; } /* any values are allowed */ return true; } static bool verify_acm_elt(const heap_ext_data_element_t *elt) { const heap_acm_elt_t *acm_elt = (const heap_acm_elt_t *)elt->data; if ( elt->size != sizeof(*elt) + sizeof(*acm_elt) + acm_elt->num_acms*sizeof(uint64_t) ) { printk(TBOOT_ERR"HEAP_ACM element has wrong size (%u)\n", elt->size); return false; } /* no addrs is not error, but print warning */ if ( acm_elt->num_acms == 0 ) printk(TBOOT_WARN"HEAP_ACM element has no ACM addrs\n"); for ( unsigned int i = 0; i < acm_elt->num_acms; i++ ) { if ( acm_elt->acm_addrs[i] == 0 ) { printk(TBOOT_ERR"HEAP_ACM element ACM addr (%u) is NULL\n", i); return false; } if ( acm_elt->acm_addrs[i] >= 0x100000000UL ) { printk(TBOOT_ERR"HEAP_ACM element ACM addr (%u) is >4GB (0x%jx)\n", i, acm_elt->acm_addrs[i]); return false; } /* not going to check if ACM addrs are valid ACMs */ } return true; } static bool verify_custom_elt(const heap_ext_data_element_t *elt) { const heap_custom_elt_t *custom_elt = (const heap_custom_elt_t *)elt->data; if ( elt->size < sizeof(*elt) + sizeof(*custom_elt) ) { printk(TBOOT_ERR"HEAP_CUSTOM element has wrong size (%u)\n", elt->size); return false; } /* any values are allowed */ return true; } static bool verify_evt_log(const event_log_container_t *elog) { if ( elog == NULL ) { printk(TBOOT_ERR"Event log container pointer is NULL\n"); return false; } if ( tb_memcmp(elog->signature, EVTLOG_SIGNATURE, sizeof(elog->signature)) ) { printk(TBOOT_ERR"Bad event log container signature: %s\n", elog->signature); return false; } if ( elog->size != MAX_EVENT_LOG_SIZE ) { printk(TBOOT_ERR"Bad event log container size: 0x%x\n", elog->size); return false; } /* no need to check versions */ if ( elog->pcr_events_offset < sizeof(*elog) || elog->next_event_offset < elog->pcr_events_offset || elog->next_event_offset > elog->size ) { printk(TBOOT_ERR"Bad events offset range: [%u, %u)\n", elog->pcr_events_offset, elog->next_event_offset); return false; } return true; } static bool verify_evt_log_ptr_elt(const heap_ext_data_element_t *elt) { const heap_event_log_ptr_elt_t *elog_elt = (const heap_event_log_ptr_elt_t *)elt->data; if ( elt->size != sizeof(*elt) + sizeof(*elog_elt) ) { printk(TBOOT_ERR"HEAP_EVENT_LOG_POINTER element has wrong size (%u)\n", elt->size); return false; } return verify_evt_log((event_log_container_t *)(unsigned long) elog_elt->event_log_phys_addr); } static bool verify_evt_log_ptr_elt_2(const heap_ext_data_element_t *elt) { if ( !elt ) return false; return true; } static bool verify_ext_data_elts(const heap_ext_data_element_t elts[], size_t elts_size) { const heap_ext_data_element_t *elt = elts; while ( true ) { if ( elts_size < sizeof(*elt) ) { printk(TBOOT_ERR"heap ext data elements too small\n"); return false; } if ( elts_size < elt->size || elt->size == 0 ) { printk(TBOOT_ERR"invalid element size: type: %u, size: %u\n", elt->type, elt->size); return false; } switch ( elt->type ) { case HEAP_EXTDATA_TYPE_END: return true; case HEAP_EXTDATA_TYPE_BIOS_SPEC_VER: if ( !verify_bios_spec_ver_elt(elt) ) return false; break; case HEAP_EXTDATA_TYPE_ACM: if ( !verify_acm_elt(elt) ) return false; break; case HEAP_EXTDATA_TYPE_CUSTOM: if ( !verify_custom_elt(elt) ) return false; break; case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR: if ( !verify_evt_log_ptr_elt(elt) ) return false; break; case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2: if ( !verify_evt_log_ptr_elt_2(elt) ) return false; break; default: printk(TBOOT_WARN"unknown element: type: %u, size: %u\n", elt->type, elt->size); break; } elts_size -= elt->size; elt = (void *)elt + elt->size; } return true; } bool verify_bios_data(const txt_heap_t *txt_heap) { uint64_t heap_base = read_pub_config_reg(TXTCR_HEAP_BASE); uint64_t heap_size = read_pub_config_reg(TXTCR_HEAP_SIZE); printk(TBOOT_DETA"TXT.HEAP.BASE: 0x%jx\n", heap_base); printk(TBOOT_DETA"TXT.HEAP.SIZE: 0x%jx (%ju)\n", heap_size, heap_size); /* verify that heap base/size are valid */ if ( txt_heap == NULL || heap_base == 0 || heap_size == 0 ) return false; /* check size */ uint64_t size = get_bios_data_size(txt_heap); if ( size == 0 ) { printk(TBOOT_ERR"BIOS data size is 0\n"); return false; } if ( size > heap_size ) { printk(TBOOT_ERR"BIOS data size is larger than heap size " "(%jx, heap size=%jx)\n", size, heap_size); return false; } bios_data_t *bios_data = get_bios_data_start(txt_heap); /* check version */ if ( bios_data->version < 2 ) { printk(TBOOT_ERR"unsupported BIOS data version (%u)\n", bios_data->version); return false; } /* we assume backwards compatibility but print a warning */ if ( bios_data->version > 6 ) printk(TBOOT_WARN"unsupported BIOS data version (%u)\n", bios_data->version); /* all TXT-capable CPUs support at least 1 core */ if ( bios_data->num_logical_procs < 1 ) { printk(TBOOT_ERR"BIOS data has incorrect num_logical_procs (%u)\n", bios_data->num_logical_procs); return false; } else if ( bios_data->num_logical_procs > NR_CPUS ) { printk(TBOOT_ERR"BIOS data specifies too many CPUs (%u)\n", bios_data->num_logical_procs); return false; } if ( bios_data->version >= 4 && size > sizeof(*bios_data) + sizeof(size) ) { if ( !verify_ext_data_elts(bios_data->ext_data_elts, size - sizeof(*bios_data) - sizeof(size)) ) return false; } print_bios_data(bios_data, size); return true; } static void print_os_mle_data(const os_mle_data_t *os_mle_data) { printk(TBOOT_DETA"os_mle_data (@%p, %Lx):\n", os_mle_data, *((uint64_t *)os_mle_data - 1)); printk(TBOOT_DETA"\t version: %u\n", os_mle_data->version); /* TBD: perhaps eventually print saved_mtrr_state field */ printk(TBOOT_DETA"\t loader context addr: %p\n", os_mle_data->lctx_addr); } static bool verify_os_mle_data(const txt_heap_t *txt_heap) { uint64_t size, heap_size; os_mle_data_t *os_mle_data; /* check size */ heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); size = get_os_mle_data_size(txt_heap); if ( size == 0 ) { printk(TBOOT_ERR"OS to MLE data size is 0\n"); return false; } if ( size > heap_size ) { printk(TBOOT_ERR"OS to MLE data size is larger than heap size " "(%Lx, heap size=%Lx)\n", size, heap_size); return false; } if ( size != (sizeof(os_mle_data_t) + sizeof(size)) ) { printk(TBOOT_ERR"OS to MLE data size (%Lx) is not equal to " "os_mle_data_t size (%x)\n", size, sizeof(os_mle_data_t)); return false; } os_mle_data = get_os_mle_data_start(txt_heap); /* check version */ /* since this data is from our pre-launch to post-launch code only, it */ /* should always be this */ if ( os_mle_data->version != 3 ) { printk(TBOOT_ERR"unsupported OS to MLE data version (%u)\n", os_mle_data->version); return false; } /* field checks */ if ( os_mle_data->lctx_addr == NULL ) { printk(TBOOT_ERR"OS to MLE data loader context addr field is NULL\n"); return false; } print_os_mle_data(os_mle_data); return true; } /* * Make sure version is in [MIN_OS_SINIT_DATA_VER, MAX_OS_SINIT_DATA_VER] * before calling calc_os_sinit_data_size */ uint64_t calc_os_sinit_data_size(uint32_t version) { uint64_t size[] = { offsetof(os_sinit_data_t, efi_rsdt_ptr) + sizeof(uint64_t), sizeof(os_sinit_data_t) + sizeof(uint64_t), sizeof(os_sinit_data_t) + sizeof(uint64_t) + 2 * sizeof(heap_ext_data_element_t) + sizeof(heap_event_log_ptr_elt_t) }; struct tpm_if *tpm = get_tpm(); int log_type = get_evtlog_type(); if ( log_type == EVTLOG_TPM2_TCG ) { size[2] = sizeof(os_sinit_data_t) + sizeof(uint64_t) + 2 * sizeof(heap_ext_data_element_t) + sizeof(heap_event_log_ptr_elt2_1_t); } else if (log_type == EVTLOG_TPM2_LEGACY) { u32 count; if ( tpm->extpol == TB_EXTPOL_AGILE ) count = tpm->banks; else if ( tpm->extpol == TB_EXTPOL_EMBEDDED ) count = tpm->alg_count; else count = 1; size[2] = sizeof(os_sinit_data_t) + sizeof(uint64_t) + 2 * sizeof(heap_ext_data_element_t) + 4 + count*sizeof(heap_event_log_descr_t); } if ( version >= 6 ) return size[2]; else return size[version - MIN_OS_SINIT_DATA_VER]; } void print_os_sinit_data_vtdpmr(const os_sinit_data_t *os_sinit_data) { printk(TBOOT_DETA"\t vtd_pmr_lo_base: 0x%Lx\n", os_sinit_data->vtd_pmr_lo_base); printk(TBOOT_DETA"\t vtd_pmr_lo_size: 0x%Lx\n", os_sinit_data->vtd_pmr_lo_size); printk(TBOOT_DETA"\t vtd_pmr_hi_base: 0x%Lx\n", os_sinit_data->vtd_pmr_hi_base); printk(TBOOT_DETA"\t vtd_pmr_hi_size: 0x%Lx\n", os_sinit_data->vtd_pmr_hi_size); } void print_os_sinit_data(const os_sinit_data_t *os_sinit_data) { printk(TBOOT_DETA"os_sinit_data (@%p, %Lx):\n", os_sinit_data, *((uint64_t *)os_sinit_data - 1)); printk(TBOOT_DETA"\t version: %u\n", os_sinit_data->version); printk(TBOOT_DETA"\t flags: %u\n", os_sinit_data->flags); printk(TBOOT_DETA"\t mle_ptab: 0x%Lx\n", os_sinit_data->mle_ptab); printk(TBOOT_DETA"\t mle_size: 0x%Lx (%Lu)\n", os_sinit_data->mle_size, os_sinit_data->mle_size); printk(TBOOT_DETA"\t mle_hdr_base: 0x%Lx\n", os_sinit_data->mle_hdr_base); print_os_sinit_data_vtdpmr(os_sinit_data); printk(TBOOT_DETA"\t lcp_po_base: 0x%Lx\n", os_sinit_data->lcp_po_base); printk(TBOOT_DETA"\t lcp_po_size: 0x%Lx (%Lu)\n", os_sinit_data->lcp_po_size, os_sinit_data->lcp_po_size); print_txt_caps("\t ", os_sinit_data->capabilities); if ( os_sinit_data->version >= 5 ) printk(TBOOT_DETA"\t efi_rsdt_ptr: 0x%Lx\n", os_sinit_data->efi_rsdt_ptr); if ( os_sinit_data->version >= 6 ) print_ext_data_elts(os_sinit_data->ext_data_elts); } static bool verify_os_sinit_data(const txt_heap_t *txt_heap) { uint64_t size, heap_size; os_sinit_data_t *os_sinit_data; /* check size */ heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); size = get_os_sinit_data_size(txt_heap); if ( size == 0 ) { printk(TBOOT_ERR"OS to SINIT data size is 0\n"); return false; } if ( size > heap_size ) { printk(TBOOT_ERR"OS to SINIT data size is larger than heap size " "(%Lx, heap size=%Lx)\n", size, heap_size); return false; } os_sinit_data = get_os_sinit_data_start(txt_heap); /* check version (but since we create this, it should always be OK) */ if ( os_sinit_data->version < MIN_OS_SINIT_DATA_VER || os_sinit_data->version > MAX_OS_SINIT_DATA_VER ) { printk(TBOOT_ERR"unsupported OS to SINIT data version (%u)\n", os_sinit_data->version); return false; } if ( size != calc_os_sinit_data_size(os_sinit_data->version) ) { printk(TBOOT_ERR"OS to SINIT data size (%Lx) does not match for version (%x)\n", size, sizeof(os_sinit_data_t)); return false; } if ( os_sinit_data->version >= 6 ) { if ( !verify_ext_data_elts(os_sinit_data->ext_data_elts, size - sizeof(*os_sinit_data) - sizeof(size)) ) return false; } print_os_sinit_data(os_sinit_data); return true; } static void print_sinit_mdrs(const sinit_mdr_t mdrs[], uint32_t num_mdrs) { static const char *mem_types[] = {"GOOD", "SMRAM OVERLAY", "SMRAM NON-OVERLAY", "PCIE EXTENDED CONFIG", "PROTECTED"}; printk(TBOOT_DETA"\t sinit_mdrs:\n"); for ( unsigned int i = 0; i < num_mdrs; i++ ) { printk(TBOOT_DETA"\t\t %016Lx - %016Lx ", mdrs[i].base, mdrs[i].base + mdrs[i].length); if ( mdrs[i].mem_type < sizeof(mem_types)/sizeof(mem_types[0]) ) printk(TBOOT_DETA"(%s)\n", mem_types[mdrs[i].mem_type]); else printk(TBOOT_DETA"(%d)\n", (int)mdrs[i].mem_type); } } static void print_sinit_mle_data(const sinit_mle_data_t *sinit_mle_data) { printk(TBOOT_DETA"sinit_mle_data (@%p, %Lx):\n", sinit_mle_data, *((uint64_t *)sinit_mle_data - 1)); printk(TBOOT_DETA"\t version: %u\n", sinit_mle_data->version); printk(TBOOT_DETA"\t bios_acm_id: \n\t"); print_heap_hash(sinit_mle_data->bios_acm_id); printk(TBOOT_DETA"\t edx_senter_flags: 0x%08x\n", sinit_mle_data->edx_senter_flags); printk(TBOOT_DETA"\t mseg_valid: 0x%Lx\n", sinit_mle_data->mseg_valid); printk(TBOOT_DETA"\t sinit_hash:\n\t"); print_heap_hash(sinit_mle_data->sinit_hash); printk(TBOOT_DETA"\t mle_hash:\n\t"); print_heap_hash(sinit_mle_data->mle_hash); printk(TBOOT_DETA"\t stm_hash:\n\t"); print_heap_hash(sinit_mle_data->stm_hash); printk(TBOOT_DETA"\t lcp_policy_hash:\n\t"); print_heap_hash(sinit_mle_data->lcp_policy_hash); printk(TBOOT_DETA"\t lcp_policy_control: 0x%08x\n", sinit_mle_data->lcp_policy_control); printk(TBOOT_DETA"\t rlp_wakeup_addr: 0x%x\n", sinit_mle_data->rlp_wakeup_addr); printk(TBOOT_DETA"\t num_mdrs: %u\n", sinit_mle_data->num_mdrs); printk(TBOOT_DETA"\t mdrs_off: 0x%x\n", sinit_mle_data->mdrs_off); printk(TBOOT_DETA"\t num_vtd_dmars: %u\n", sinit_mle_data->num_vtd_dmars); printk(TBOOT_DETA"\t vtd_dmars_off: 0x%x\n", sinit_mle_data->vtd_dmars_off); print_sinit_mdrs((sinit_mdr_t *) (((void *)sinit_mle_data - sizeof(uint64_t)) + sinit_mle_data->mdrs_off), sinit_mle_data->num_mdrs); if ( sinit_mle_data->version >= 8 ) printk(TBOOT_DETA"\t proc_scrtm_status: 0x%08x\n", sinit_mle_data->proc_scrtm_status); if ( sinit_mle_data->version >= 9 ) print_ext_data_elts(sinit_mle_data->ext_data_elts); } static bool verify_sinit_mle_data(const txt_heap_t *txt_heap) { uint64_t size, heap_size; sinit_mle_data_t *sinit_mle_data; /* check size */ heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE); size = get_sinit_mle_data_size(txt_heap); if ( size == 0 ) { printk(TBOOT_ERR"SINIT to MLE data size is 0\n"); return false; } if ( size > heap_size ) { printk(TBOOT_ERR"SINIT to MLE data size is larger than heap size\n" "(%Lx, heap size=%Lx)\n", size, heap_size); return false; } sinit_mle_data = get_sinit_mle_data_start(txt_heap); /* check version */ if ( sinit_mle_data->version < 6 ) { printk(TBOOT_ERR"unsupported SINIT to MLE data version (%u)\n", sinit_mle_data->version); return false; } else if ( sinit_mle_data->version > 9 ) { printk(TBOOT_WARN"unsupported SINIT to MLE data version (%u)\n", sinit_mle_data->version); } /* this data is generated by SINIT and so is implicitly trustworthy, */ /* so we don't need to validate it's fields */ print_sinit_mle_data(sinit_mle_data); return true; } bool verify_txt_heap(const txt_heap_t *txt_heap, bool bios_data_only) { /* verify BIOS to OS data */ if ( !verify_bios_data(txt_heap) ) return false; if ( bios_data_only ) return true; /* check that total size is within the heap */ uint64_t size1 = get_bios_data_size(txt_heap); uint64_t size2 = get_os_mle_data_size(txt_heap); uint64_t size3 = get_os_sinit_data_size(txt_heap); uint64_t size4 = get_sinit_mle_data_size(txt_heap); /* overflow? */ if ( plus_overflow_u64(size1, size2) ) { printk(TBOOT_ERR"TXT heap data size overflows\n"); return false; } if ( plus_overflow_u64(size3, size4) ) { printk(TBOOT_ERR"TXT heap data size overflows\n"); return false; } if ( plus_overflow_u64(size1 + size2, size3 + size4) ) { printk(TBOOT_ERR"TXT heap data size overflows\n"); return false; } if ( (size1 + size2 + size3 + size4) > read_priv_config_reg(TXTCR_HEAP_SIZE) ) { printk(TBOOT_ERR"TXT heap data sizes (%Lx, %Lx, %Lx, %Lx) are larger than\n" "heap total size (%Lx)\n", size1, size2, size3, size4, read_priv_config_reg(TXTCR_HEAP_SIZE)); return false; } /* verify OS to MLE data */ if ( !verify_os_mle_data(txt_heap) ) return false; /* verify OS to SINIT data */ if ( !verify_os_sinit_data(txt_heap) ) return false; /* verify SINIT to MLE data */ if ( !verify_sinit_mle_data(txt_heap) ) return false; return true; } #endif /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/txt/mtrrs.c0000644000000000000000000005054114210363175014343 0ustar 00000000000000/* * mtrrs.c: support functions for manipulating MTRRs * * Copyright (c) 2003-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MTRR_TYPE_MIXED -1 #define MMIO_APIC_BASE 0xFEE00000 #define NR_MMIO_APIC_PAGES 1 #define NR_MMIO_IOAPIC_PAGES 1 #define NR_MMIO_PCICFG_PAGES 1 #define SINIT_MTRR_MASK 0xFFFFFF /* SINIT requires 36b mask */ /* saved MTRR state or NULL if orig. MTRRs have not been changed */ static __data mtrr_state_t *g_saved_mtrrs = NULL; static uint64_t get_maxphyaddr_mask(void) { static bool printed_msg = false; union { uint32_t raw; struct { uint32_t num_pa_bits : 8; uint32_t num_la_bits : 8; uint32_t reserved : 16; }; } num_addr_bits; /* does CPU support 0x80000008 CPUID leaf? (all TXT CPUs should) */ uint32_t max_ext_fn = cpuid_eax(0x80000000); if ( max_ext_fn < 0x80000008 ) return 0xffffff; /* if not, default is 36b support */ num_addr_bits.raw = cpuid_eax(0x80000008); if ( !printed_msg ) { printk(TBOOT_DETA"CPU supports %u phys address bits\n", num_addr_bits.num_pa_bits); printed_msg = true; } return ((1ULL << num_addr_bits.num_pa_bits) - 1) >> PAGE_SHIFT; } /* * this must be done for each processor so that all have the same * memory types */ bool set_mtrrs_for_acmod(const acm_hdr_t *hdr) { unsigned long eflags; unsigned long cr0, cr4; /* * need to do some things before we start changing MTRRs * * since this will modify some of the MTRRs, they should be saved first * so that they can be restored once the AC mod is done */ /* disable interrupts */ eflags = read_eflags(); disable_intr(); /* save CR0 then disable cache (CRO.CD=1, CR0.NW=0) */ cr0 = read_cr0(); write_cr0((cr0 & ~CR0_NW) | CR0_CD); /* flush caches */ wbinvd(); /* save CR4 and disable global pages (CR4.PGE=0) */ cr4 = read_cr4(); write_cr4(cr4 & ~CR4_PGE); /* disable MTRRs */ set_all_mtrrs(false); /* * now set MTRRs for AC mod and rest of memory */ if ( !set_mem_type(hdr, hdr->size*4, MTRR_TYPE_WRBACK) ) return false; /* * now undo some of earlier changes and enable our new settings */ /* flush caches */ wbinvd(); /* enable MTRRs */ set_all_mtrrs(true); /* restore CR0 (cacheing) */ write_cr0(cr0); /* restore CR4 (global pages) */ write_cr4(cr4); /* enable interrupts */ write_eflags(eflags); return true; } void save_mtrrs(mtrr_state_t *saved_state) { mtrr_cap_t mtrr_cap; /* IA32_MTRR_DEF_TYPE MSR */ saved_state->mtrr_def_type.raw = rdmsr(MSR_MTRRdefType); /* number variable MTTRRs */ mtrr_cap.raw = rdmsr(MSR_MTRRcap); if ( mtrr_cap.vcnt > MAX_VARIABLE_MTRRS ) { /* print warning but continue saving what we can */ /* (set_mem_type() won't exceed the array, so we're safe doing this) */ printk(TBOOT_WARN"actual # var MTRRs (%d) > MAX_VARIABLE_MTRRS (%d)\n", mtrr_cap.vcnt, MAX_VARIABLE_MTRRS); saved_state->num_var_mtrrs = MAX_VARIABLE_MTRRS; } else saved_state->num_var_mtrrs = mtrr_cap.vcnt; /* physmask's and physbase's */ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) { saved_state->mtrr_physmasks[ndx].raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2); saved_state->mtrr_physbases[ndx].raw = rdmsr(MTRR_PHYS_BASE0_MSR + ndx*2); } g_saved_mtrrs = saved_state; } static void print_mtrrs(const mtrr_state_t *saved_state) { printk(TBOOT_DETA"mtrr_def_type: e = %d, fe = %d, type = %x\n", saved_state->mtrr_def_type.e, saved_state->mtrr_def_type.fe, saved_state->mtrr_def_type.type ); printk(TBOOT_DETA"mtrrs:\n"); printk(TBOOT_DETA"\t\t base mask type v\n"); for ( unsigned int i = 0; i < saved_state->num_var_mtrrs; i++ ) { printk(TBOOT_DETA"\t\t%13.13Lx %13.13Lx %2.2x %d\n", (uint64_t)saved_state->mtrr_physbases[i].base, (uint64_t)saved_state->mtrr_physmasks[i].mask, saved_state->mtrr_physbases[i].type, saved_state->mtrr_physmasks[i].v ); } } /* base should be 4k-bytes aligned, no invalid overlap combination */ static int get_page_type(const mtrr_state_t *saved_state, uint32_t base) { int type = -1; bool wt = false; uint64_t maxphyaddr_mask = get_maxphyaddr_mask(); /* omit whether the fix mtrrs are enabled, just check var mtrrs */ base >>= PAGE_SHIFT; for ( unsigned int i = 0; i < saved_state->num_var_mtrrs; i++ ) { const mtrr_physbase_t *base_i = &saved_state->mtrr_physbases[i]; const mtrr_physmask_t *mask_i = &saved_state->mtrr_physmasks[i]; if ( mask_i->v == 0 ) continue; if ( (base & mask_i->mask & maxphyaddr_mask) != (base_i->base & mask_i->mask & maxphyaddr_mask) ) continue; type = base_i->type; if ( type == MTRR_TYPE_UNCACHABLE ) return MTRR_TYPE_UNCACHABLE; if ( type == MTRR_TYPE_WRTHROUGH ) wt = true; } if ( wt ) return MTRR_TYPE_WRTHROUGH; if ( type != -1 ) return type; return saved_state->mtrr_def_type.type; } static int get_region_type(const mtrr_state_t *saved_state, uint32_t base, uint32_t pages) { int type; uint32_t end; if ( pages == 0 ) return MTRR_TYPE_MIXED; /* wrap the 4G address space */ if ( ((uint32_t)(~0) - base) < (pages << PAGE_SHIFT) ) return MTRR_TYPE_MIXED; if ( saved_state->mtrr_def_type.e == 0 ) return MTRR_TYPE_UNCACHABLE; /* align to 4k page boundary */ base &= PAGE_MASK; end = base + (pages << PAGE_SHIFT); type = get_page_type(saved_state, base); base += PAGE_SIZE; for ( ; base < end; base += PAGE_SIZE ) if ( type != get_page_type(saved_state, base) ) return MTRR_TYPE_MIXED; return type; } static bool validate_mmio_regions(const mtrr_state_t *saved_state) { acpi_table_mcfg_t *acpi_table_mcfg; acpi_table_ioapic_t *acpi_table_ioapic; /* mmio space for TXT private config space should be UC */ if ( get_region_type(saved_state, TXT_PRIV_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE >> PAGE_SHIFT) != MTRR_TYPE_UNCACHABLE ) { printk(TBOOT_ERR"MMIO space for TXT private config space should be UC\n"); return false; } /* mmio space for TXT public config space should be UC */ if ( get_region_type(saved_state, TXT_PUB_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE >> PAGE_SHIFT) != MTRR_TYPE_UNCACHABLE ) { printk(TBOOT_ERR"MMIO space for TXT public config space should be UC\n"); return false; } /* mmio space for TPM should be UC */ if ( get_region_type(saved_state, TPM_LOCALITY_BASE, NR_TPM_LOCALITY_PAGES * TPM_NR_LOCALITIES) != MTRR_TYPE_UNCACHABLE ) { printk(TBOOT_ERR"MMIO space for TPM should be UC\n"); return false; } /* mmio space for APIC should be UC */ if ( get_region_type(saved_state, MMIO_APIC_BASE, NR_MMIO_APIC_PAGES) != MTRR_TYPE_UNCACHABLE ) { printk(TBOOT_ERR"MMIO space for APIC should be UC\n"); return false; } /* TBD: is this check useful if we aren't DMA protecting ACPI? */ /* mmio space for IOAPIC should be UC */ acpi_table_ioapic = (acpi_table_ioapic_t *)get_acpi_ioapic_table(); if ( acpi_table_ioapic == NULL) { printk(TBOOT_ERR"acpi_table_ioapic == NULL\n"); return false; } printk(TBOOT_DETA"acpi_table_ioapic @ %p, .address = %x\n", acpi_table_ioapic, acpi_table_ioapic->address); if ( get_region_type(saved_state, acpi_table_ioapic->address, NR_MMIO_IOAPIC_PAGES) != MTRR_TYPE_UNCACHABLE ) { printk(TBOOT_ERR"MMIO space(%x) for IOAPIC should be UC\n", acpi_table_ioapic->address); return false; } /* TBD: is this check useful if we aren't DMA protecting ACPI? */ /* mmio space for PCI config space should be UC */ acpi_table_mcfg = (acpi_table_mcfg_t *)get_acpi_mcfg_table(); if ( acpi_table_mcfg == NULL) { printk(TBOOT_ERR"acpi_table_mcfg == NULL\n"); return false; } printk(TBOOT_DETA"acpi_table_mcfg @ %p, .base_address = %x\n", acpi_table_mcfg, acpi_table_mcfg->base_address); if ( get_region_type(saved_state, acpi_table_mcfg->base_address, NR_MMIO_PCICFG_PAGES) != MTRR_TYPE_UNCACHABLE ) { printk(TBOOT_ERR"MMIO space(%x) for PCI config space should be UC\n", acpi_table_mcfg->base_address); return false; } return true; } bool validate_mtrrs(const mtrr_state_t *saved_state) { mtrr_cap_t mtrr_cap; uint64_t maxphyaddr_mask = get_maxphyaddr_mask(); uint64_t max_pages = maxphyaddr_mask + 1; /* max # 4k pages supported */ /* check is meaningless if MTRRs were disabled */ if ( saved_state->mtrr_def_type.e == 0 ) return true; /* number variable MTRRs */ mtrr_cap.raw = rdmsr(MSR_MTRRcap); if ( mtrr_cap.vcnt < saved_state->num_var_mtrrs ) { printk(TBOOT_ERR"actual # var MTRRs (%d) < saved # (%d)\n", mtrr_cap.vcnt, saved_state->num_var_mtrrs); return false; } /* variable MTRRs describing non-contiguous memory regions */ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) { uint64_t tb; if ( saved_state->mtrr_physmasks[ndx].v == 0 ) continue; for ( tb = 1; tb != max_pages; tb = tb << 1 ) { if ( (tb & saved_state->mtrr_physmasks[ndx].mask & maxphyaddr_mask) != 0 ) break; } for ( ; tb != max_pages; tb = tb << 1 ) { if ( (tb & saved_state->mtrr_physmasks[ndx].mask & maxphyaddr_mask) == 0 ) break; } if ( tb != max_pages ) { printk(TBOOT_ERR"var MTRRs with non-contiguous regions: base=0x%Lx, mask=0x%Lx\n", (uint64_t)saved_state->mtrr_physbases[ndx].base & maxphyaddr_mask, (uint64_t)saved_state->mtrr_physmasks[ndx].mask & maxphyaddr_mask); print_mtrrs(saved_state); return false; } } /* overlaping regions with invalid memory type combinations */ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) { const mtrr_physbase_t *base_ndx = &saved_state->mtrr_physbases[ndx]; const mtrr_physmask_t *mask_ndx = &saved_state->mtrr_physmasks[ndx]; if ( mask_ndx->v == 0 ) continue; for ( unsigned int i = ndx + 1; i < saved_state->num_var_mtrrs; i++ ) { const mtrr_physbase_t *base_i = &saved_state->mtrr_physbases[i]; const mtrr_physmask_t *mask_i = &saved_state->mtrr_physmasks[i]; if ( mask_i->v == 0 ) continue; if ( (base_ndx->base & mask_ndx->mask & mask_i->mask & maxphyaddr_mask) != (base_i->base & mask_i->mask & maxphyaddr_mask) && (base_i->base & mask_i->mask & mask_ndx->mask & maxphyaddr_mask) != (base_ndx->base & mask_ndx->mask & maxphyaddr_mask) ) continue; if ( base_ndx->type == base_i->type ) continue; if ( base_ndx->type == MTRR_TYPE_UNCACHABLE || base_i->type == MTRR_TYPE_UNCACHABLE ) continue; if ( base_ndx->type == MTRR_TYPE_WRTHROUGH && base_i->type == MTRR_TYPE_WRBACK ) continue; if ( base_ndx->type == MTRR_TYPE_WRBACK && base_i->type == MTRR_TYPE_WRTHROUGH ) continue; /* 2 overlapped regions have invalid mem type combination, */ /* need to check whether there is a third region which has type */ /* of UNCACHABLE and contains at least one of these two regions. */ /* If there is, then the combination of these 3 region is valid */ unsigned int j; for ( j = 0; j < saved_state->num_var_mtrrs; j++ ) { const mtrr_physbase_t *base_j = &saved_state->mtrr_physbases[j]; const mtrr_physmask_t *mask_j = &saved_state->mtrr_physmasks[j]; if ( mask_j->v == 0 ) continue; if ( base_j->type != MTRR_TYPE_UNCACHABLE ) continue; if ( (base_ndx->base & mask_ndx->mask & mask_j->mask & maxphyaddr_mask) == (base_j->base & mask_j->mask & maxphyaddr_mask) && (mask_j->mask & ~mask_ndx->mask & maxphyaddr_mask) == 0 ) break; if ( (base_i->base & mask_i->mask & mask_j->mask & maxphyaddr_mask) == (base_j->base & mask_j->mask & maxphyaddr_mask) && (mask_j->mask & ~mask_i->mask & maxphyaddr_mask) == 0 ) break; } if ( j < saved_state->num_var_mtrrs ) continue; printk(TBOOT_ERR"var MTRRs overlaping regions, invalid type combinations\n"); print_mtrrs(saved_state); return false; } } if ( !validate_mmio_regions(saved_state) ) { printk(TBOOT_ERR"Some mmio region should be UC type\n"); print_mtrrs(saved_state); return false; } print_mtrrs(saved_state); return true; } void restore_mtrrs(const mtrr_state_t *saved_state) { /* called by apply_policy() so use saved ptr */ if ( saved_state == NULL ) saved_state = g_saved_mtrrs; /* haven't saved them yet, so return */ if ( saved_state == NULL ) return; /* disable all MTRRs first */ set_all_mtrrs(false); /* physmask's and physbase's */ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) { wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, saved_state->mtrr_physmasks[ndx].raw); wrmsr(MTRR_PHYS_BASE0_MSR + ndx*2, saved_state->mtrr_physbases[ndx].raw); } /* IA32_MTRR_DEF_TYPE MSR */ wrmsr(MSR_MTRRdefType, saved_state->mtrr_def_type.raw); } /* * set the memory type for specified range (base to base+size) * to mem_type and everything else to UC */ bool set_mem_type(const void *base, uint32_t size, uint32_t mem_type) { int num_pages; int ndx; mtrr_def_type_t mtrr_def_type; mtrr_cap_t mtrr_cap; mtrr_physmask_t mtrr_physmask; mtrr_physbase_t mtrr_physbase; /* * disable all fixed MTRRs * set default type to UC */ mtrr_def_type.raw = rdmsr(MSR_MTRRdefType); mtrr_def_type.fe = 0; mtrr_def_type.type = MTRR_TYPE_UNCACHABLE; wrmsr(MSR_MTRRdefType, mtrr_def_type.raw); /* * initially disable all variable MTRRs (we'll enable the ones we use) */ mtrr_cap.raw = rdmsr(MSR_MTRRcap); for ( ndx = 0; ndx < mtrr_cap.vcnt; ndx++ ) { mtrr_physmask.raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2); mtrr_physmask.v = 0; wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); } /* * map all AC module pages as mem_type */ num_pages = PAGE_UP(size) >> PAGE_SHIFT; ndx = 0; printk(TBOOT_DETA"setting MTRRs for acmod: base=%p, size=%x, num_pages=%d\n", base, size, num_pages); /* * Each VAR MTRR base must be a multiple if that MTRR's Size */ unsigned long base_v; base_v = (unsigned long) base; int i =0; // mtrr size in pages int mtrr_s = 1; while ((base_v & 0x01) == 0) { i++; base_v = base_v >>1 ; } for (int j=i-12; j>0; j--) mtrr_s =mtrr_s*2; //mtrr_s = mtrr_s << 1 printk(TBOOT_DETA"The maximum allowed MTRR range size=%d Pages \n", mtrr_s); while (num_pages >= mtrr_s){ /* set the base of the current MTRR */ mtrr_physbase.raw = rdmsr(MTRR_PHYS_BASE0_MSR + ndx*2); mtrr_physbase.base = ((unsigned long)base >> PAGE_SHIFT) & SINIT_MTRR_MASK; mtrr_physbase.type = mem_type; wrmsr(MTRR_PHYS_BASE0_MSR + ndx*2, mtrr_physbase.raw); mtrr_physmask.raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2); mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK; mtrr_physmask.v = 1; wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); base += (mtrr_s * PAGE_SIZE); num_pages -= mtrr_s; ndx++; if ( ndx == mtrr_cap.vcnt ) { printk(TBOOT_ERR"exceeded number of var MTRRs when mapping range\n"); return false; } } while ( num_pages > 0 ) { uint32_t pages_in_range; /* set the base of the current MTRR */ mtrr_physbase.raw = rdmsr(MTRR_PHYS_BASE0_MSR + ndx*2); mtrr_physbase.base = ((unsigned long)base >> PAGE_SHIFT) & SINIT_MTRR_MASK; mtrr_physbase.type = mem_type; wrmsr(MTRR_PHYS_BASE0_MSR + ndx*2, mtrr_physbase.raw); /* * calculate MTRR mask * MTRRs can map pages in power of 2 * may need to use multiple MTRRS to map all of region */ pages_in_range = 1 << (fls(num_pages) - 1); mtrr_physmask.raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2); mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK; mtrr_physmask.v = 1; wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw); /*prepare for the next loop depending on number of pages * We figure out from the above how many pages could be used in this * mtrr. Then we decrement the count, increment the base, * increment the mtrr we are dealing with, and if num_pages is * still not zero, we do it again. */ base += (pages_in_range * PAGE_SIZE); num_pages -= pages_in_range; ndx++; if ( ndx == mtrr_cap.vcnt ) { printk(TBOOT_ERR"exceeded number of var MTRRs when mapping range\n"); return false; } } return true; } /* enable/disable all MTRRs */ void set_all_mtrrs(bool enable) { mtrr_def_type_t mtrr_def_type; mtrr_def_type.raw = rdmsr(MSR_MTRRdefType); mtrr_def_type.e = enable ? 1 : 0; wrmsr(MSR_MTRRdefType, mtrr_def_type.raw); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/txt/txt.c0000644000000000000000000014057214210363175014017 0ustar 00000000000000/* * txt.c: Intel(r) TXT support functions, including initiating measured * launch, post-launch, AP wakeup, etc. * * Copyright (c) 2003-2011, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* counter timeout for waiting for all APs to enter wait-for-sipi */ #define AP_WFS_TIMEOUT 0x10000000 __data struct acpi_rsdp g_rsdp; extern char _start[]; /* start of module */ extern char _end[]; /* end of module */ extern char _mle_start[]; /* start of text section */ extern char _mle_end[]; /* end of text section */ extern char _post_launch_entry[]; /* entry point post SENTER, in boot.S */ extern char _txt_wakeup[]; /* RLP join address for GETSEC[WAKEUP] */ extern long s3_flag; extern struct mutex ap_lock; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; extern void apply_policy(tb_error_t error); extern void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec); extern void print_event(const tpm12_pcr_event_t *evt); extern void print_event_2(void *evt, uint16_t alg); extern uint32_t print_event_2_1(void *evt); extern void __enable_nmi(void); /* * this is the structure whose addr we'll put in TXT heap * it needs to be within the MLE pages, so force it to the .text section */ static __text const mle_hdr_t g_mle_hdr = { uuid : MLE_HDR_UUID, length : sizeof(mle_hdr_t), version : MLE_HDR_VER, entry_point : (uint32_t)&_post_launch_entry - TBOOT_START, first_valid_page : 0, mle_start_off : (uint32_t)&_mle_start - TBOOT_BASE_ADDR, mle_end_off : (uint32_t)&_mle_end - TBOOT_BASE_ADDR, capabilities : { MLE_HDR_CAPS }, cmdline_start_off : (uint32_t)g_cmdline - TBOOT_BASE_ADDR, cmdline_end_off : (uint32_t)g_cmdline + CMDLINE_SIZE - 1 - TBOOT_BASE_ADDR, }; /* * counts of APs going into wait-for-sipi */ /* count of APs in WAIT-FOR-SIPI */ atomic_t ap_wfs_count; static void print_file_info(void) { printk(TBOOT_DETA"file addresses:\n"); printk(TBOOT_DETA"\t &_start=%p\n", &_start); printk(TBOOT_DETA"\t &_end=%p\n", &_end); printk(TBOOT_DETA"\t &_mle_start=%p\n", &_mle_start); printk(TBOOT_DETA"\t &_mle_end=%p\n", &_mle_end); printk(TBOOT_DETA"\t &_post_launch_entry=%p\n", &_post_launch_entry); printk(TBOOT_DETA"\t &_txt_wakeup=%p\n", &_txt_wakeup); printk(TBOOT_DETA"\t &g_mle_hdr=%p\n", &g_mle_hdr); } static void print_mle_hdr(const mle_hdr_t *mle_hdr) { printk(TBOOT_DETA"MLE header:\n"); printk(TBOOT_DETA"\t uuid="); print_uuid(&mle_hdr->uuid); printk(TBOOT_DETA"\n"); printk(TBOOT_DETA"\t length=%x\n", mle_hdr->length); printk(TBOOT_DETA"\t version=%08x\n", mle_hdr->version); printk(TBOOT_DETA"\t entry_point=%08x\n", mle_hdr->entry_point); printk(TBOOT_DETA"\t first_valid_page=%08x\n", mle_hdr->first_valid_page); printk(TBOOT_DETA"\t mle_start_off=%x\n", mle_hdr->mle_start_off); printk(TBOOT_DETA"\t mle_end_off=%x\n", mle_hdr->mle_end_off); print_txt_caps("\t ", mle_hdr->capabilities); } /* * build_mle_pagetable() */ /* page dir/table entry is phys addr + P + R/W + PWT */ #define MAKE_PDTE(addr) (((uint64_t)(unsigned long)(addr) & PAGE_MASK) | 0x01) /* we assume/know that our image is <2MB and thus fits w/in a single */ /* PT (512*4KB = 2MB) and thus fixed to 1 pg dir ptr and 1 pgdir and */ /* 1 ptable = 3 pages and just 1 loop loop for ptable MLE page table */ /* can only contain 4k pages */ static __mlept uint8_t g_mle_pt[3 * PAGE_SIZE]; /* pgdir ptr + pgdir + ptab = 3 */ static void *build_mle_pagetable(uint32_t mle_start, uint32_t mle_size) { void *ptab_base; uint32_t ptab_size, mle_off; void *pg_dir_ptr_tab, *pg_dir, *pg_tab; uint64_t *pte; printk(TBOOT_DETA"MLE start=0x%x, end=0x%x, size=0x%x\n", mle_start, mle_start+mle_size, mle_size); if ( mle_size > 512*PAGE_SIZE ) { printk(TBOOT_ERR"MLE size too big for single page table\n"); return NULL; } /* should start on page boundary */ if ( mle_start & ~PAGE_MASK ) { printk(TBOOT_ERR"MLE start is not page-aligned\n"); return NULL; } /* place ptab_base below MLE */ ptab_size = sizeof(g_mle_pt); ptab_base = &g_mle_pt; tb_memset(ptab_base, 0, ptab_size); printk(TBOOT_DETA"ptab_size=%x, ptab_base=%p\n", ptab_size, ptab_base); pg_dir_ptr_tab = ptab_base; pg_dir = pg_dir_ptr_tab + PAGE_SIZE; pg_tab = pg_dir + PAGE_SIZE; /* only use first entry in page dir ptr table */ *(uint64_t *)pg_dir_ptr_tab = MAKE_PDTE(pg_dir); /* only use first entry in page dir */ *(uint64_t *)pg_dir = MAKE_PDTE(pg_tab); pte = pg_tab; mle_off = 0; do { *pte = MAKE_PDTE(mle_start + mle_off); pte++; mle_off += PAGE_SIZE; } while ( mle_off < mle_size ); return ptab_base; } static __data event_log_container_t *g_elog = NULL; static __data heap_event_log_ptr_elt2_t *g_elog_2 = NULL; static __data heap_event_log_ptr_elt2_1_t *g_elog_2_1 = NULL; /* should be called after os_mle_data initialized */ static void *init_event_log(void) { os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap()); g_elog = (event_log_container_t *)&os_mle_data->event_log_buffer; tb_memcpy((void *)g_elog->signature, EVTLOG_SIGNATURE, sizeof(g_elog->signature)); g_elog->container_ver_major = EVTLOG_CNTNR_MAJOR_VER; g_elog->container_ver_minor = EVTLOG_CNTNR_MINOR_VER; g_elog->pcr_event_ver_major = EVTLOG_EVT_MAJOR_VER; g_elog->pcr_event_ver_minor = EVTLOG_EVT_MINOR_VER; g_elog->size = sizeof(os_mle_data->event_log_buffer); g_elog->pcr_events_offset = sizeof(*g_elog); g_elog->next_event_offset = sizeof(*g_elog); return (void *)g_elog; } /* initialize TCG compliant TPM 2.0 event log descriptor */ static void init_evtlog_desc_1(heap_event_log_ptr_elt2_1_t *evt_log) { os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap()); evt_log->phys_addr = (uint64_t)(unsigned long)(os_mle_data->event_log_buffer); evt_log->allcoated_event_container_size = 2*PAGE_SIZE; evt_log->first_record_offset = 0; evt_log->next_record_offset = 0; printk(TBOOT_DETA"TCG compliant TPM 2.0 event log descriptor:\n"); printk(TBOOT_DETA"\t phys_addr = 0x%LX\n", evt_log->phys_addr); printk(TBOOT_DETA"\t allcoated_event_container_size = 0x%x \n", evt_log->allcoated_event_container_size); printk(TBOOT_DETA"\t first_record_offset = 0x%x \n", evt_log->first_record_offset); printk(TBOOT_DETA"\t next_record_offset = 0x%x \n", evt_log->next_record_offset); } static void init_evtlog_desc(heap_event_log_ptr_elt2_t *evt_log) { unsigned int i; os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap()); struct tpm_if *tpm = get_tpm(); switch (tpm->extpol) { case TB_EXTPOL_AGILE: for (i=0; icount; i++) { evt_log->event_log_descr[i].alg = tpm->algs_banks[i]; evt_log->event_log_descr[i].phys_addr = (uint64_t)(unsigned long)(os_mle_data->event_log_buffer + i*4096); evt_log->event_log_descr[i].size = 4096; evt_log->event_log_descr[i].pcr_events_offset = 0; evt_log->event_log_descr[i].next_event_offset = 0; } break; case TB_EXTPOL_EMBEDDED: for (i=0; icount; i++) { evt_log->event_log_descr[i].alg = tpm->algs[i]; evt_log->event_log_descr[i].phys_addr = (uint64_t)(unsigned long)(os_mle_data->event_log_buffer + i*4096); evt_log->event_log_descr[i].size = 4096; evt_log->event_log_descr[i].pcr_events_offset = 0; evt_log->event_log_descr[i].next_event_offset = 0; } break; case TB_EXTPOL_FIXED: evt_log->event_log_descr[0].alg = tpm->cur_alg; evt_log->event_log_descr[0].phys_addr = (uint64_t)(unsigned long)os_mle_data->event_log_buffer; evt_log->event_log_descr[0].size = 4096; evt_log->event_log_descr[0].pcr_events_offset = 0; evt_log->event_log_descr[0].next_event_offset = 0; break; default: return; } } int get_evtlog_type(void) { struct tpm_if *tpm = get_tpm(); if (tpm->major == TPM12_VER_MAJOR) { return EVTLOG_TPM12; } else if (tpm->major == TPM20_VER_MAJOR) { /* * Force use of legacy TPM2 log format to deal with a bug in some SINIT * ACMs that where they don't log the MLE hash to the event log. */ if (get_tboot_force_tpm2_legacy_log()) { return EVTLOG_TPM2_LEGACY; } if (g_sinit) { txt_caps_t sinit_caps = get_sinit_capabilities(g_sinit); return sinit_caps.tcg_event_log_format ? EVTLOG_TPM2_TCG : EVTLOG_TPM2_LEGACY; } else { printk(TBOOT_ERR"SINIT not found\n"); } } else { printk(TBOOT_ERR"Unknown TPM major version: %d\n", tpm->major); } printk(TBOOT_ERR"Unable to determine log type\n"); return EVTLOG_UNKNOWN; } static void init_os_sinit_ext_data(heap_ext_data_element_t* elts) { heap_ext_data_element_t* elt = elts; heap_event_log_ptr_elt_t* evt_log; struct tpm_if *tpm = get_tpm(); int log_type = get_evtlog_type(); if ( log_type == EVTLOG_TPM12 ) { evt_log = (heap_event_log_ptr_elt_t *)elt->data; evt_log->event_log_phys_addr = (uint64_t)(unsigned long)init_event_log(); elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR; elt->size = sizeof(*elt) + sizeof(*evt_log); } else if ( log_type == EVTLOG_TPM2_TCG ) { g_elog_2_1 = (heap_event_log_ptr_elt2_1_t *)elt->data; init_evtlog_desc_1(g_elog_2_1); elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2_1; elt->size = sizeof(*elt) + sizeof(heap_event_log_ptr_elt2_1_t); printk(TBOOT_DETA"heap_ext_data_element TYPE = %d \n", elt->type); printk(TBOOT_DETA"heap_ext_data_element SIZE = %d \n", elt->size); } else if ( log_type == EVTLOG_TPM2_LEGACY ) { g_elog_2 = (heap_event_log_ptr_elt2_t *)elt->data; if ( tpm->extpol == TB_EXTPOL_AGILE ) g_elog_2->count = tpm->banks; else if ( tpm->extpol == TB_EXTPOL_EMBEDDED ) g_elog_2->count = tpm->alg_count; else g_elog_2->count = 1; init_evtlog_desc(g_elog_2); elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2; elt->size = sizeof(*elt) + sizeof(u32) + g_elog_2->count * sizeof(heap_event_log_descr_t); printk(TBOOT_DETA"INTEL TXT LOG elt SIZE = %d \n", elt->size); } elt = (void *)elt + elt->size; elt->type = HEAP_EXTDATA_TYPE_END; elt->size = sizeof(*elt); } bool evtlog_append_tpm12(uint8_t pcr, tb_hash_t *hash, uint32_t type) { if ( g_elog == NULL ) return true; tpm12_pcr_event_t *next = (tpm12_pcr_event_t *) ((void*)g_elog + g_elog->next_event_offset); if ( g_elog->next_event_offset + sizeof(*next) > g_elog->size ) return false; next->pcr_index = pcr; next->type = type; tb_memcpy(next->digest, hash, sizeof(next->digest)); next->data_size = 0; g_elog->next_event_offset += sizeof(*next) + next->data_size; print_event(next); return true; } void dump_event_2(void) { heap_event_log_descr_t *log_descr; for ( unsigned int i=0; icount; i++ ) { log_descr = &g_elog_2->event_log_descr[i]; printk(TBOOT_DETA"\t\t\t Log Descrption:\n"); printk(TBOOT_DETA"\t\t\t Alg: %u\n", log_descr->alg); printk(TBOOT_DETA"\t\t\t Size: %u\n", log_descr->size); printk(TBOOT_DETA"\t\t\t EventsOffset: [%u,%u)\n", log_descr->pcr_events_offset, log_descr->next_event_offset); uint32_t hash_size, data_size; hash_size = get_hash_size(log_descr->alg); if ( hash_size == 0 ) return; void *curr, *next; *((u64 *)(&curr)) = log_descr->phys_addr + log_descr->pcr_events_offset; *((u64 *)(&next)) = log_descr->phys_addr + log_descr->next_event_offset; if ( log_descr->alg != TB_HALG_SHA1 ) { print_event_2(curr, TB_HALG_SHA1); curr += sizeof(tpm12_pcr_event_t) + sizeof(tpm20_log_descr_t); } while ( curr < next ) { print_event_2(curr, log_descr->alg); data_size = *(uint32_t *)(curr + 2*sizeof(uint32_t) + hash_size); curr += 3*sizeof(uint32_t) + hash_size + data_size; } } } bool evtlog_append_tpm2_legacy(uint8_t pcr, uint16_t alg, tb_hash_t *hash, uint32_t type) { heap_event_log_descr_t *cur_desc = NULL; uint32_t hash_size; void *cur, *next; for ( unsigned int i=0; icount; i++ ) { if ( g_elog_2->event_log_descr[i].alg == alg ) { cur_desc = &g_elog_2->event_log_descr[i]; break; } } if ( !cur_desc ) return false; hash_size = get_hash_size(alg); if ( hash_size == 0 ) return false; if ( cur_desc->next_event_offset + 32 > cur_desc->size ) return false; cur = next = (void *)(unsigned long)cur_desc->phys_addr + cur_desc->next_event_offset; *((u32 *)next) = pcr; next += sizeof(u32); *((u32 *)next) = type; next += sizeof(u32); tb_memcpy((uint8_t *)next, hash, hash_size); next += hash_size; *((u32 *)next) = 0; cur_desc->next_event_offset += 3*sizeof(uint32_t) + hash_size; print_event_2(cur, alg); return true; } bool evtlog_append_tpm2_tcg(uint8_t pcr, uint32_t type, hash_list_t *hl) { uint32_t i, event_size; unsigned int hash_size; tcg_pcr_event2 *event; uint8_t *hash_entry; tcg_pcr_event2 dummy; /* * Dont't use sizeof(tcg_pcr_event2) since that has TPML_DIGESTV_VALUES_1.digests * set to 5. Compute the static size as pcr_index + event_type + * digest.count + event_size. Then add the space taken up by the hashes. */ event_size = sizeof(dummy.pcr_index) + sizeof(dummy.event_type) + sizeof(dummy.digest.count) + sizeof(dummy.event_size); for (i = 0; i < hl->count; i++) { hash_size = get_hash_size(hl->entries[i].alg); if (hash_size == 0) { return false; } event_size += sizeof(uint16_t); // hash_alg field event_size += hash_size; } // Check if event will fit in buffer. if (event_size + g_elog_2_1->next_record_offset > g_elog_2_1->allcoated_event_container_size) { return false; } event = (tcg_pcr_event2*)(void *)(unsigned long)(g_elog_2_1->phys_addr + g_elog_2_1->next_record_offset); event->pcr_index = pcr; event->event_type = type; event->event_size = 0; // No event data passed by tboot. event->digest.count = hl->count; hash_entry = (uint8_t *)&event->digest.digests[0]; for (i = 0; i < hl->count; i++) { // Populate individual TPMT_HA_1 structs. *((uint16_t *)hash_entry) = hl->entries[i].alg; // TPMT_HA_1.hash_alg hash_entry += sizeof(uint16_t); hash_size = get_hash_size(hl->entries[i].alg); // already checked above tb_memcpy(hash_entry, &(hl->entries[i].hash), hash_size); hash_entry += hash_size; } g_elog_2_1->next_record_offset += event_size; print_event_2_1(event); return true; } bool evtlog_append(uint8_t pcr, hash_list_t *hl, uint32_t type) { int log_type = get_evtlog_type(); switch (log_type) { case EVTLOG_TPM12: if ( !evtlog_append_tpm12(pcr, &hl->entries[0].hash, type) ) return false; break; case EVTLOG_TPM2_LEGACY: for (unsigned int i=0; icount; i++) { if ( !evtlog_append_tpm2_legacy(pcr, hl->entries[i].alg, &hl->entries[i].hash, type)) return false; } break; case EVTLOG_TPM2_TCG: if ( !evtlog_append_tpm2_tcg(pcr, type, hl) ) return false; break; default: return false; } return true; } __data uint32_t g_using_da = 0; __data acm_hdr_t *g_sinit = 0; static void configure_vtd(void) { uint32_t remap_length; struct dmar_remapping *dmar_remap = vtd_get_dmar_remap(&remap_length); if (dmar_remap == NULL) { printk("cannot get DMAR remapping structures, skipping configuration\n"); return; } else { printk("configuring DMAR remapping\n"); } struct dmar_remapping *iter, *next; struct dmar_remapping *end = ((void *)dmar_remap) + remap_length; for (iter = dmar_remap; iter < end; iter = next) { next = (void *)iter + iter->length; if (iter->length == 0) { /* Avoid looping forever on bad ACPI tables */ printk(" invalid 0-length structure\n"); break; } else if (next > end) { /* Avoid passing table end */ printk(" record passes table end\n"); break; } if (iter->type == DMAR_REMAPPING_DRHD) { if (!vtd_disable_dma_remap(iter)) { printk(" vtd_disable_dma_remap failed!\n"); } } } } /* * sets up TXT heap */ static txt_heap_t *init_txt_heap(void *ptab_base, acm_hdr_t *sinit, loader_ctx *lctx) { txt_heap_t *txt_heap; uint64_t *size; struct tpm_if *tpm = get_tpm(); txt_heap = get_txt_heap(); /* * BIOS data already setup by BIOS */ if ( !verify_txt_heap(txt_heap, true) ) return NULL; /* * OS/loader to MLE data */ os_mle_data_t *os_mle_data = get_os_mle_data_start(txt_heap); size = (uint64_t *)((uint32_t)os_mle_data - sizeof(uint64_t)); *size = sizeof(*os_mle_data) + sizeof(uint64_t); tb_memset(os_mle_data, 0, sizeof(*os_mle_data)); os_mle_data->version = 3; os_mle_data->lctx_addr = lctx->addr; os_mle_data->saved_misc_enable_msr = rdmsr(MSR_IA32_MISC_ENABLE); /* * OS/loader to SINIT data */ /* check sinit supported os_sinit_data version */ uint32_t version = get_supported_os_sinit_data_ver(sinit); if ( version < MIN_OS_SINIT_DATA_VER ) { printk(TBOOT_ERR"unsupported OS to SINIT data version(%u) in sinit\n", version); return NULL; } if ( version > MAX_OS_SINIT_DATA_VER ) version = MAX_OS_SINIT_DATA_VER; os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap); size = (uint64_t *)((uint32_t)os_sinit_data - sizeof(uint64_t)); *size = calc_os_sinit_data_size(version); tb_memset(os_sinit_data, 0, *size); os_sinit_data->version = version; /* this is phys addr */ os_sinit_data->mle_ptab = (uint64_t)(unsigned long)ptab_base; os_sinit_data->mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off; /* this is linear addr (offset from MLE base) of mle header */ os_sinit_data->mle_hdr_base = (uint64_t)(unsigned long)&g_mle_hdr - (uint64_t)(unsigned long)&_mle_start; /* VT-d PMRs */ uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram; if ( !get_ram_ranges(&min_lo_ram, &max_lo_ram, &min_hi_ram, &max_hi_ram) ) return NULL; set_vtd_pmrs(os_sinit_data, min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram); /* LCP owner policy data */ void *lcp_base = NULL; uint32_t lcp_size = 0; if ( find_lcp_module(lctx, &lcp_base, &lcp_size) && lcp_size > 0 ) { /* copy to heap */ if ( lcp_size > sizeof(os_mle_data->lcp_po_data) ) { printk(TBOOT_ERR"LCP owner policy data file is too large (%u)\n", lcp_size); return NULL; } tb_memcpy(os_mle_data->lcp_po_data, lcp_base, lcp_size); os_sinit_data->lcp_po_base = (unsigned long)&os_mle_data->lcp_po_data; os_sinit_data->lcp_po_size = lcp_size; } /* capabilities : choose monitor wake mechanism first */ txt_caps_t sinit_caps = get_sinit_capabilities(sinit); txt_caps_t caps_mask = { 0 }; caps_mask.rlp_wake_getsec = 1; caps_mask.rlp_wake_monitor = 1; caps_mask.pcr_map_da = 1; caps_mask.tcg_event_log_format = 1; caps_mask.tcg_event_log_format = 1; os_sinit_data->capabilities._raw = MLE_HDR_CAPS & ~caps_mask._raw; if ( sinit_caps.rlp_wake_monitor ) os_sinit_data->capabilities.rlp_wake_monitor = 1; else if ( sinit_caps.rlp_wake_getsec ) os_sinit_data->capabilities.rlp_wake_getsec = 1; else { /* should have been detected in verify_acmod() */ printk(TBOOT_ERR"SINIT capabilities are incompatible (0x%x)\n", sinit_caps._raw); return NULL; } if ( get_evtlog_type() == EVTLOG_TPM2_TCG ) { printk(TBOOT_INFO"SINIT ACM supports TCG compliant TPM 2.0 event log format, tcg_event_log_format = %d \n", sinit_caps.tcg_event_log_format); os_sinit_data->capabilities.tcg_event_log_format = 1; } /* capabilities : require MLE pagetable in ECX on launch */ /* TODO: when SINIT ready * os_sinit_data->capabilities.ecx_pgtbl = 1; */ os_sinit_data->capabilities.ecx_pgtbl = 0; if (is_loader_launch_efi(lctx)){ /* we were launched EFI, set efi_rsdt_ptr */ struct acpi_rsdp *rsdp = get_rsdp(lctx); if (rsdp != NULL){ if (version < 6){ /* rsdt */ /* NOTE: Winston Wang says this doesn't work for v5 */ os_sinit_data->efi_rsdt_ptr = (uint64_t) rsdp->rsdp1.rsdt; } else { /* rsdp */ tb_memcpy((void *)&g_rsdp, rsdp, sizeof(struct acpi_rsdp)); os_sinit_data->efi_rsdt_ptr = (uint64_t)((uint32_t)&g_rsdp); } } else { /* per discussions--if we don't have an ACPI pointer, die */ printk(TBOOT_ERR"Failed to find RSDP for EFI launch\n"); return NULL; } } /* capabilities : choose DA/LG */ os_sinit_data->capabilities.pcr_map_no_legacy = 1; if ( sinit_caps.pcr_map_da && (get_tboot_prefer_da() || sinit_caps.cbnt_supported) ) os_sinit_data->capabilities.pcr_map_da = 1; else if ( !sinit_caps.pcr_map_no_legacy ) os_sinit_data->capabilities.pcr_map_no_legacy = 0; else if ( sinit_caps.pcr_map_da ) { printk(TBOOT_INFO "DA is the only supported PCR mapping by SINIT, use it\n"); os_sinit_data->capabilities.pcr_map_da = 1; } else { printk(TBOOT_ERR"SINIT capabilities are incompatible (0x%x)\n", sinit_caps._raw); return NULL; } g_using_da = os_sinit_data->capabilities.pcr_map_da; /* PCR mapping selection MUST be zero in TPM2.0 mode * since D/A mapping is the only supported by TPM2.0 */ if ( tpm->major >= TPM20_VER_MAJOR ) { os_sinit_data->flags = (tpm->extpol == TB_EXTPOL_AGILE) ? 0 : 1; os_sinit_data->capabilities.pcr_map_no_legacy = 0; os_sinit_data->capabilities.pcr_map_da = 0; g_using_da = 1; } /* Event log initialization */ if ( os_sinit_data->version >= 6 ) init_os_sinit_ext_data(os_sinit_data->ext_data_elts); print_os_sinit_data(os_sinit_data); /* * SINIT to MLE data will be setup by SINIT */ return txt_heap; } static void txt_wakeup_cpus(void) { uint16_t cs; mle_join_t mle_join; unsigned int ap_wakeup_count; if ( !verify_stm(get_apicid()) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* enable SMIs on BSP before waking APs (which will enable them on APs) because some SMM may take immediate SMI and hang if AP gets in first */ printk(TBOOT_DETA"enabling SMIs and NMI on BSP\n"); __getsec_smctrl(); __enable_nmi(); atomic_set(&ap_wfs_count, 0); /* RLPs will use our GDT and CS */ extern char gdt_table[], gdt_table_end[]; __asm__ __volatile__ ("mov %%cs, %0\n" : "=r"(cs)); mle_join.entry_point = (uint32_t)(unsigned long)&_txt_wakeup; mle_join.seg_sel = cs; mle_join.gdt_base = (uint32_t)gdt_table; mle_join.gdt_limit = gdt_table_end - gdt_table - 1; printk(TBOOT_DETA"mle_join.entry_point = %x\n", mle_join.entry_point); printk(TBOOT_DETA"mle_join.seg_sel = %x\n", mle_join.seg_sel); printk(TBOOT_DETA"mle_join.gdt_base = %x\n", mle_join.gdt_base); printk(TBOOT_DETA"mle_join.gdt_limit = %x\n", mle_join.gdt_limit); write_priv_config_reg(TXTCR_MLE_JOIN, (uint64_t)(unsigned long)&mle_join); mtx_init(&ap_lock); txt_heap_t *txt_heap = get_txt_heap(); sinit_mle_data_t *sinit_mle_data = get_sinit_mle_data_start(txt_heap); os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap); /* choose wakeup mechanism based on capabilities used */ if ( os_sinit_data->capabilities.rlp_wake_monitor ) { printk(TBOOT_INFO"joining RLPs to MLE with MONITOR wakeup\n"); printk(TBOOT_DETA"rlp_wakeup_addr = 0x%x\n", sinit_mle_data->rlp_wakeup_addr); *((uint32_t *)(unsigned long)(sinit_mle_data->rlp_wakeup_addr)) = 0x01; } else { printk(TBOOT_INFO"joining RLPs to MLE with GETSEC[WAKEUP]\n"); __getsec_wakeup(); printk(TBOOT_INFO"GETSEC[WAKEUP] completed\n"); } /* assume BIOS isn't lying to us about # CPUs, else some CPUS may not */ /* have entered wait-for-sipi before we launch *or* we have to wait */ /* for timeout before launching */ /* (all TXT-capable CPUs have at least 2 cores) */ bios_data_t *bios_data = get_bios_data_start(txt_heap); ap_wakeup_count = bios_data->num_logical_procs - 1; if ( ap_wakeup_count >= NR_CPUS ) { printk(TBOOT_INFO"there are too many CPUs (%u)\n", ap_wakeup_count); ap_wakeup_count = NR_CPUS - 1; } printk(TBOOT_INFO"waiting for all APs (%d) to enter wait-for-sipi...\n", ap_wakeup_count); /* wait for all APs that woke up to have entered wait-for-sipi */ uint32_t timeout = AP_WFS_TIMEOUT; do { if ( timeout % 0x8000 == 0 ) printk(TBOOT_INFO"."); else cpu_relax(); if ( timeout % 0x200000 == 0 ) printk(TBOOT_INFO"\n"); timeout--; } while ( ( atomic_read(&ap_wfs_count) < ap_wakeup_count ) && timeout > 0 ); printk(TBOOT_INFO"\n"); if ( timeout == 0 ) printk(TBOOT_INFO"wait-for-sipi loop timed-out\n"); else printk(TBOOT_INFO"all APs in wait-for-sipi\n"); } bool txt_is_launched(void) { txt_sts_t sts; sts._raw = read_pub_config_reg(TXTCR_STS); return sts.senter_done_sts; } tb_error_t txt_launch_environment(loader_ctx *lctx) { void *mle_ptab_base; os_mle_data_t *os_mle_data; txt_heap_t *txt_heap; /* * find correct SINIT AC module in modules list */ // find_platform_sinit_module(lctx, (void **)&g_sinit, NULL); /* if it is newer than BIOS-provided version, then copy it to */ /* BIOS reserved region */ // g_sinit = copy_sinit(g_sinit); // if ( g_sinit == NULL ) // return TB_ERR_SINIT_NOT_PRESENT; /* do some checks on it */ // if ( !verify_acmod(g_sinit) ) // return TB_ERR_ACMOD_VERIFY_FAILED; /* print some debug info */ print_file_info(); print_mle_hdr(&g_mle_hdr); /* create MLE page table */ mle_ptab_base = build_mle_pagetable( g_mle_hdr.mle_start_off + TBOOT_BASE_ADDR, g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off); if ( mle_ptab_base == NULL ) return TB_ERR_FATAL; configure_vtd(); /* initialize TXT heap */ txt_heap = init_txt_heap(mle_ptab_base, g_sinit, lctx); if ( txt_heap == NULL ) return TB_ERR_TXT_NOT_SUPPORTED; /* save MTRRs before we alter them for SINIT launch */ os_mle_data = get_os_mle_data_start(txt_heap); save_mtrrs(&(os_mle_data->saved_mtrr_state)); /* * Disable VGA logging when using framebuffer. Writing to it will be * extreme slow when memory is set to UC. */ if (get_framebuffer_info(g_ldr_ctx) != NULL) { printk(TBOOT_INFO"Disabling VGA logging before GETSEC[SENTER]\n"); printk_disable_vga(); } /* * If memlog decide to compress logs after setting MTRRs, * it will take very much time. Better do it now. */ printk_flush(); /* set MTRRs properly for AC module (SINIT) */ if ( !set_mtrrs_for_acmod(g_sinit) ) return TB_ERR_FATAL; /*{ tpm_reg_loc_ctrl_t reg_loc_ctrl; tpm_reg_loc_state_t reg_loc_state; reg_loc_ctrl._raw[0] = 0; reg_loc_ctrl.relinquish = 1; write_tpm_reg(0, TPM_REG_LOC_CTRL, ®_loc_ctrl); printk(TBOOT_INFO"Relinquish CRB localility 0 before executing GETSEC[SENTER]...\n"); read_tpm_reg(0, TPM_REG_LOC_STATE, ®_loc_state); printk(TBOOT_INFO"CRB reg_loc_state.active_locality is 0x%x \n", reg_loc_state.active_locality); printk(TBOOT_INFO"CRB reg_loc_state.loc_assigned is 0x%x \n", reg_loc_state.loc_assigned); }*/ printk(TBOOT_INFO"executing GETSEC[SENTER]...\n"); /* (optionally) pause before executing GETSEC[SENTER] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); __getsec_senter((uint32_t)g_sinit, (g_sinit->size)*4); printk(TBOOT_INFO"ERROR--we should not get here!\n"); return TB_ERR_FATAL; } bool txt_s3_launch_environment(void) { /* initial launch's TXT heap data is still in place and assumed valid */ /* so don't re-create; this is OK because it was untrusted initially */ /* and would be untrusted now */ int log_type = get_evtlog_type(); /* get sinit binary loaded */ g_sinit = (acm_hdr_t *)(uint32_t)read_pub_config_reg(TXTCR_SINIT_BASE); if ( g_sinit == NULL ){ return false; } /* initialize event log in os_sinit_data, so that events will not */ /* repeat when s3 */ if ( log_type == EVTLOG_TPM12 && g_elog ) { g_elog = (event_log_container_t *)init_event_log(); } else if ( log_type == EVTLOG_TPM2_TCG && g_elog_2_1) { init_evtlog_desc_1(g_elog_2_1); } else if ( log_type == EVTLOG_TPM2_LEGACY && g_elog_2) { init_evtlog_desc(g_elog_2); } /* * If memlog decide to compress logs after setting MTRRs, * it will take very much time. Better do it now. */ printk_flush(); /* set MTRRs properly for AC module (SINIT) */ set_mtrrs_for_acmod(g_sinit); printk(TBOOT_INFO"executing GETSEC[SENTER]...\n"); /* (optionally) pause before executing GETSEC[SENTER] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); __getsec_senter((uint32_t)g_sinit, (g_sinit->size)*4); printk(TBOOT_ERR"ERROR--we should not get here!\n"); return false; } tb_error_t txt_launch_racm(loader_ctx *lctx) { acm_hdr_t *racm = NULL; /* * find correct revocation AC module in modules list */ find_platform_racm(lctx, (void **)&racm, NULL); if ( racm == NULL ) return TB_ERR_SINIT_NOT_PRESENT; /* copy it to a 32KB aligned memory address */ racm = copy_racm(racm); if ( racm == NULL ) return TB_ERR_SINIT_NOT_PRESENT; /* do some checks on it */ if ( !verify_racm(racm) ) return TB_ERR_ACMOD_VERIFY_FAILED; /* save MTRRs before we alter them for RACM launch */ /* - not needed by far since always reboot after RACM launch */ //save_mtrrs(...); /* * If memlog decide to compress logs after setting MTRRs, * it will take very much time. Better do it now. */ printk_flush(); /* set MTRRs properly for AC module (RACM) */ if ( !set_mtrrs_for_acmod(racm) ) return TB_ERR_FATAL; /* clear MSEG_BASE/SIZE registers */ write_pub_config_reg(TXTCR_MSEG_BASE, 0); write_pub_config_reg(TXTCR_MSEG_SIZE, 0); printk(TBOOT_INFO"executing GETSEC[ENTERACCS]...\n"); /* (optionally) pause before executing GETSEC[ENTERACCS] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); __getsec_enteraccs((uint32_t)racm, (racm->size)*4, 0xF0); /* powercycle by writing 0x0a+0x0e to port 0xcf9, */ /* warm reset by write 0x06 to port 0xcf9 */ //outb(0xcf9, 0x0a); //outb(0xcf9, 0x0e); outb(0xcf9, 0x06); printk(TBOOT_ERR"ERROR--we should not get here!\n"); return TB_ERR_FATAL; } bool txt_prepare_cpu(void) { unsigned long eflags, cr0; uint64_t mcg_cap, mcg_stat; /* must be running at CPL 0 => this is implicit in even getting this far */ /* since our bootstrap code loads a GDT, etc. */ cr0 = read_cr0(); /* must be in protected mode */ if ( !(cr0 & CR0_PE) ) { printk(TBOOT_ERR"ERR: not in protected mode\n"); return false; } /* cache must be enabled (CR0.CD = CR0.NW = 0) */ if ( cr0 & CR0_CD ) { printk(TBOOT_INFO"CR0.CD set\n"); cr0 &= ~CR0_CD; } if ( cr0 & CR0_NW ) { printk(TBOOT_INFO"CR0.NW set\n"); cr0 &= ~CR0_NW; } /* native FPU error reporting must be enabled for proper */ /* interaction behavior */ if ( !(cr0 & CR0_NE) ) { printk(TBOOT_INFO"CR0.NE not set\n"); cr0 |= CR0_NE; } write_cr0(cr0); /* cannot be in virtual-8086 mode (EFLAGS.VM=1) */ eflags = read_eflags(); if ( eflags & X86_EFLAGS_VM ) { printk(TBOOT_INFO"EFLAGS.VM set\n"); write_eflags(eflags | ~X86_EFLAGS_VM); } printk(TBOOT_INFO"CR0 and EFLAGS OK\n"); /* * verify that we're not already in a protected environment */ if ( txt_is_launched() ) { printk(TBOOT_ERR"already in protected environment\n"); return false; } /* * verify all machine check status registers are clear (unless * support preserving them) */ /* no machine check in progress (IA32_MCG_STATUS.MCIP=1) */ mcg_stat = rdmsr(MSR_MCG_STATUS); if ( mcg_stat & 0x04 ) { printk(TBOOT_ERR"machine check in progress\n"); return false; } getsec_parameters_t params; if ( !get_parameters(¶ms) ) { printk(TBOOT_ERR"get_parameters() failed\n"); return false; } /* check if all machine check regs are clear */ mcg_cap = rdmsr(MSR_MCG_CAP); for ( unsigned int i = 0; i < (mcg_cap & 0xff); i++ ) { mcg_stat = rdmsr(MSR_MC0_STATUS + 4*i); if ( mcg_stat & (1ULL << 63) ) { printk(TBOOT_ERR"MCG[%u] = %Lx ERROR\n", i, mcg_stat); if ( !params.preserve_mce ) return false; } } if ( params.preserve_mce ) printk(TBOOT_INFO"supports preserving machine check errors\n"); else printk(TBOOT_INFO"no machine check errors\n"); if ( params.proc_based_scrtm ) printk(TBOOT_INFO"CPU support processor-based S-CRTM\n"); /* all is well with the processor state */ printk(TBOOT_INFO"CPU is ready for SENTER\n"); return true; } void txt_post_launch(void) { txt_heap_t *txt_heap; os_mle_data_t *os_mle_data; tb_error_t err; /* verify MTRRs, VT-d settings, TXT heap, etc. */ err = txt_post_launch_verify_platform(); /* don't return the error yet, because we need to restore settings */ if ( err != TB_ERR_NONE ) printk(TBOOT_ERR"failed to verify platform\n"); /* get saved OS state (os_mvmm_data_t) from LT heap */ txt_heap = get_txt_heap(); os_mle_data = get_os_mle_data_start(txt_heap); /* clear error registers so that we start fresh */ write_priv_config_reg(TXTCR_ERRORCODE, 0x00000000); write_priv_config_reg(TXTCR_ESTS, 0xffffffff); /* write 1's to clear */ /* bring RLPs into environment (do this before restoring MTRRs to ensure */ /* SINIT area is mapped WB for MONITOR-based RLP wakeup) */ txt_wakeup_cpus(); /* restore pre-SENTER IA32_MISC_ENABLE_MSR (no verification needed) (do after AP wakeup so that if restored MSR has MWAIT clear it won't prevent wakeup) */ printk(TBOOT_DETA"saved IA32_MISC_ENABLE = 0x%08x\n", os_mle_data->saved_misc_enable_msr); wrmsr(MSR_IA32_MISC_ENABLE, os_mle_data->saved_misc_enable_msr); if ( use_mwait() ) { /* set MONITOR/MWAIT support */ uint64_t misc; misc = rdmsr(MSR_IA32_MISC_ENABLE); misc |= MSR_IA32_MISC_ENABLE_MONITOR_FSM; wrmsr(MSR_IA32_MISC_ENABLE, misc); } /* restore pre-SENTER MTRRs that were overwritten for SINIT launch */ restore_mtrrs(&(os_mle_data->saved_mtrr_state)); /* now, if there was an error, apply policy */ apply_policy(err); /* always set the TXT.CMD.SECRETS flag */ write_priv_config_reg(TXTCR_CMD_SECRETS, 0x01); read_priv_config_reg(TXTCR_E2STS); /* just a fence, so ignore return */ printk(TBOOT_INFO"set TXT.CMD.SECRETS flag\n"); /* open TPM locality 1 */ write_priv_config_reg(TXTCR_CMD_OPEN_LOCALITY1, 0x01); read_priv_config_reg(TXTCR_E2STS); /* just a fence, so ignore return */ printk(TBOOT_INFO"opened TPM locality 1\n"); } void ap_wait(unsigned int cpuid) { if ( cpuid >= NR_CPUS ) { printk(TBOOT_ERR"cpuid (%u) exceeds # supported CPUs\n", cpuid); apply_policy(TB_ERR_FATAL); mtx_leave(&ap_lock); return; } /* ensure MONITOR/MWAIT support is set */ uint64_t misc; misc = rdmsr(MSR_IA32_MISC_ENABLE); misc |= MSR_IA32_MISC_ENABLE_MONITOR_FSM; wrmsr(MSR_IA32_MISC_ENABLE, misc); /* this is close enough to entering monitor/mwait loop, so inc counter */ atomic_inc((atomic_t *)&_tboot_shared.num_in_wfs); mtx_leave(&ap_lock); printk(TBOOT_INFO"cpu %u mwait'ing\n", cpuid); while ( _tboot_shared.ap_wake_trigger != cpuid ) { cpu_monitor(&_tboot_shared.ap_wake_trigger, 0, 0); mb(); if ( _tboot_shared.ap_wake_trigger == cpuid ) break; cpu_mwait(0, 0); } uint32_t sipi_vec = (uint32_t)_tboot_shared.ap_wake_addr; atomic_dec(&ap_wfs_count); atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs); cpu_wakeup(cpuid, sipi_vec); } void txt_cpu_wakeup(void) { txt_heap_t *txt_heap; os_mle_data_t *os_mle_data; uint64_t madt_apicbase, msr_apicbase; unsigned int cpuid = get_apicid(); if ( cpuid >= NR_CPUS ) { printk(TBOOT_ERR"cpuid (%u) exceeds # supported CPUs\n", cpuid); apply_policy(TB_ERR_FATAL); return; } mtx_enter(&ap_lock); printk(TBOOT_INFO"cpu %u waking up from TXT sleep\n", cpuid); /* restore LAPIC base address for AP */ madt_apicbase = (uint64_t)get_madt_apic_base(); if ( madt_apicbase == 0 ) { printk(TBOOT_ERR"not able to get apci base from MADT\n"); apply_policy(TB_ERR_FATAL); return; } msr_apicbase = rdmsr(MSR_APICBASE); if ( madt_apicbase != (msr_apicbase & ~0xFFFULL) ) { printk(TBOOT_INFO"cpu %u restore apic base to %llx\n", cpuid, madt_apicbase); wrmsr(MSR_APICBASE, (msr_apicbase & 0xFFFULL) | madt_apicbase); } txt_heap = get_txt_heap(); os_mle_data = get_os_mle_data_start(txt_heap); /* apply (validated) (pre-SENTER) MTRRs from BSP to each AP */ restore_mtrrs(&(os_mle_data->saved_mtrr_state)); /* restore pre-SENTER IA32_MISC_ENABLE_MSR */ wrmsr(MSR_IA32_MISC_ENABLE, os_mle_data->saved_misc_enable_msr); if ( !verify_stm(cpuid) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* enable SMIs and NMI */ printk(TBOOT_DETA"enabling SMIs and NMI on cpu %u\n", cpuid); __getsec_smctrl(); __enable_nmi(); atomic_inc(&ap_wfs_count); if ( use_mwait() ) ap_wait(cpuid); else handle_init_sipi_sipi(cpuid); } tb_error_t txt_protect_mem_regions(void) { uint64_t base, size; /* * TXT has 2 regions of RAM that need to be reserved for use by only the * hypervisor; not even dom0 should have access: * TXT heap, SINIT AC module */ /* TXT heap */ base = read_pub_config_reg(TXTCR_HEAP_BASE); size = read_pub_config_reg(TXTCR_HEAP_SIZE); printk(TBOOT_INFO"protecting TXT heap (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; if (!efi_memmap_reserve(base, size)) { return TB_ERR_FATAL; } /* SINIT */ base = read_pub_config_reg(TXTCR_SINIT_BASE); size = read_pub_config_reg(TXTCR_SINIT_SIZE); printk(TBOOT_INFO"protecting SINIT (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; if (!efi_memmap_reserve(base, size)) { return TB_ERR_FATAL; } /* TXT private space */ base = TXT_PRIV_CONFIG_REGS_BASE; size = TXT_CONFIG_REGS_SIZE; printk(TBOOT_INFO "protecting TXT Private Space (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; if (!efi_memmap_reserve(base, size)) { return TB_ERR_FATAL; } /* ensure that memory not marked as good RAM by the MDRs is RESERVED in the e820 table */ txt_heap_t* txt_heap = get_txt_heap(); sinit_mle_data_t *sinit_mle_data = get_sinit_mle_data_start(txt_heap); uint32_t num_mdrs = sinit_mle_data->num_mdrs; sinit_mdr_t *mdrs_base = (sinit_mdr_t *)(((void *)sinit_mle_data - sizeof(uint64_t)) + sinit_mle_data->mdrs_off); printk(TBOOT_INFO"verifying e820 table against SINIT MDRs: "); if ( !verify_e820_map(mdrs_base, num_mdrs) ) { printk(TBOOT_ERR"verification failed.\n"); return TB_ERR_POST_LAUNCH_VERIFICATION; } printk(TBOOT_INFO"verification succeeded.\n"); return TB_ERR_NONE; } void txt_shutdown(void) { unsigned long apicbase; /* shutdown shouldn't be called on APs, but if it is then just hlt */ apicbase = rdmsr(MSR_APICBASE); if ( !(apicbase & APICBASE_BSP) ) { printk(TBOOT_INFO"calling txt_shutdown on AP\n"); while ( true ) halt(); } /* set TXT.CMD.NO-SECRETS flag (i.e. clear SECRETS flag) */ write_priv_config_reg(TXTCR_CMD_NO_SECRETS, 0x01); read_priv_config_reg(TXTCR_E2STS); /* fence */ printk(TBOOT_INFO"secrets flag cleared\n"); /* unlock memory configuration */ write_priv_config_reg(TXTCR_CMD_UNLOCK_MEM_CONFIG, 0x01); read_pub_config_reg(TXTCR_E2STS); /* fence */ printk(TBOOT_INFO"memory configuration unlocked\n"); /* if some APs are still in wait-for-sipi then SEXIT will hang */ /* so TXT reset the platform instead, expect mwait case */ if ( (!use_mwait()) && atomic_read(&ap_wfs_count) > 0 ) { printk(TBOOT_INFO "exiting with some APs still in wait-for-sipi state (%u)\n", atomic_read(&ap_wfs_count)); write_priv_config_reg(TXTCR_CMD_RESET, 0x01); } /* close TXT private config space */ /* implicitly closes TPM localities 1 + 2 */ read_priv_config_reg(TXTCR_E2STS); /* fence */ write_priv_config_reg(TXTCR_CMD_CLOSE_PRIVATE, 0x01); read_pub_config_reg(TXTCR_E2STS); /* fence */ printk(TBOOT_INFO"private config space closed\n"); /* SMXE may not be enabled any more, so set it to make sure */ write_cr4(read_cr4() | CR4_SMXE); /* call GETSEC[SEXIT] */ printk(TBOOT_INFO"executing GETSEC[SEXIT]...\n"); __getsec_sexit(); printk(TBOOT_INFO"measured environment torn down\n"); } bool txt_is_powercycle_required(void) { /* a powercycle is required to clear the TXT_RESET.STS flag */ txt_ests_t ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS); return ests.txt_reset_sts; } #define ACM_MEM_TYPE_UC 0x0100 #define ACM_MEM_TYPE_WC 0x0200 #define ACM_MEM_TYPE_WT 0x1000 #define ACM_MEM_TYPE_WP 0x2000 #define ACM_MEM_TYPE_WB 0x4000 #define DEF_ACM_MAX_SIZE 0x8000 #define DEF_ACM_VER_MASK 0xffffffff #define DEF_ACM_VER_SUPPORTED 0x00 #define DEF_ACM_MEM_TYPES ACM_MEM_TYPE_UC #define DEF_SENTER_CTRLS 0x00 bool get_parameters(getsec_parameters_t *params) { unsigned long cr4; uint32_t index, eax, ebx, ecx; int param_type; /* sanity check because GETSEC[PARAMETERS] will fail if not set */ cr4 = read_cr4(); if ( !(cr4 & CR4_SMXE) ) { printk(TBOOT_ERR"SMXE not enabled, can't read parameters\n"); return false; } tb_memset(params, 0, sizeof(*params)); params->acm_max_size = DEF_ACM_MAX_SIZE; params->acm_mem_types = DEF_ACM_MEM_TYPES; params->senter_controls = DEF_SENTER_CTRLS; params->proc_based_scrtm = false; params->preserve_mce = false; index = 0; do { __getsec_parameters(index++, ¶m_type, &eax, &ebx, &ecx); /* the code generated for a 'switch' statement doesn't work in this */ /* environment, so use if/else blocks instead */ /* NULL - all reserved */ if ( param_type == 0 ) ; /* supported ACM versions */ else if ( param_type == 1 ) { if ( params->n_versions == MAX_SUPPORTED_ACM_VERSIONS ) printk(TBOOT_WARN"number of supported ACM version exceeds " "MAX_SUPPORTED_ACM_VERSIONS\n"); else { params->acm_versions[params->n_versions].mask = ebx; params->acm_versions[params->n_versions].version = ecx; params->n_versions++; } } /* max size AC execution area */ else if ( param_type == 2 ) params->acm_max_size = eax & 0xffffffe0; /* supported non-AC mem types */ else if ( param_type == 3 ) params->acm_mem_types = eax & 0xffffffe0; /* SENTER controls */ else if ( param_type == 4 ) params->senter_controls = (eax & 0x00007fff) >> 8; /* TXT extensions support */ else if ( param_type == 5 ) { params->proc_based_scrtm = (eax & 0x00000020) ? true : false; params->preserve_mce = (eax & 0x00000040) ? true : false; } else { printk(TBOOT_WARN"unknown GETSEC[PARAMETERS] type: %d\n", param_type); param_type = 0; /* set so that we break out of the loop */ } } while ( param_type != 0 ); if ( params->n_versions == 0 ) { params->acm_versions[0].mask = DEF_ACM_VER_MASK; params->acm_versions[0].version = DEF_ACM_VER_SUPPORTED; params->n_versions = 1; } return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/txt/verify.c0000644000000000000000000004756114210363175014510 0ustar 00000000000000/* * verify.c: verify that platform and processor supports Intel(r) TXT * * Copyright (c) 2003-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern long s3_flag; /* * CPUID extended feature info */ static unsigned int g_cpuid_ext_feat_info; /* * IA32_FEATURE_CONTROL_MSR */ static unsigned long g_feat_ctrl_msr; static bool read_processor_info(void) { unsigned long f1, f2; /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */ uint32_t regs[4]; /* is CPUID supported? */ /* (it's supported if ID flag in EFLAGS can be set and cleared) */ asm("pushf\n\t" "pushf\n\t" "pop %0\n\t" "mov %0,%1\n\t" "xor %2,%0\n\t" "push %0\n\t" "popf\n\t" "pushf\n\t" "pop %0\n\t" "popf\n\t" : "=&r" (f1), "=&r" (f2) : "ir" (X86_EFLAGS_ID)); if ( ((f1^f2) & X86_EFLAGS_ID) == 0 ) { g_cpuid_ext_feat_info = 0; printk(TBOOT_ERR"CPUID instruction is not supported.\n"); return false; } do_cpuid(0, regs); if ( regs[1] != 0x756e6547 /* "Genu" */ || regs[2] != 0x6c65746e /* "ntel" */ || regs[3] != 0x49656e69 ) { /* "ineI" */ g_cpuid_ext_feat_info = 0; printk(TBOOT_ERR"Non-Intel CPU detected.\n"); return false; } g_cpuid_ext_feat_info = cpuid_ecx(1); /* read feature control msr only if processor supports VMX or SMX instructions */ if ( (g_cpuid_ext_feat_info & CPUID_X86_FEATURE_VMX) || (g_cpuid_ext_feat_info & CPUID_X86_FEATURE_SMX) ) { g_feat_ctrl_msr = rdmsr(MSR_IA32_FEATURE_CONTROL); printk(TBOOT_DETA"IA32_FEATURE_CONTROL_MSR: %08lx\n", g_feat_ctrl_msr); } return true; } static bool supports_vmx(void) { /* check that processor supports VMX instructions */ if ( !(g_cpuid_ext_feat_info & CPUID_X86_FEATURE_VMX) ) { printk(TBOOT_ERR"ERR: CPU does not support VMX\n"); return false; } printk(TBOOT_INFO"CPU is VMX-capable\n"); /* and that VMX is enabled in the feature control MSR */ if ( !(g_feat_ctrl_msr & IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX) ) { printk(TBOOT_ERR"ERR: VMXON disabled by feature control MSR (%lx)\n", g_feat_ctrl_msr); return false; } return true; } static bool supports_smx(void) { /* check that processor supports SMX instructions */ if ( !(g_cpuid_ext_feat_info & CPUID_X86_FEATURE_SMX) ) { printk(TBOOT_ERR"ERR: CPU does not support SMX\n"); return false; } printk(TBOOT_INFO"CPU is SMX-capable\n"); /* * and that SMX is enabled in the feature control MSR */ /* check that the MSR is locked -- BIOS should always lock it */ if ( !(g_feat_ctrl_msr & IA32_FEATURE_CONTROL_MSR_LOCK) ) { printk(TBOOT_ERR"ERR: IA32_FEATURE_CONTROL_MSR_LOCK is not locked\n"); /* this should not happen, as BIOS is required to lock the MSR */ #ifdef PERMISSIVE_BOOT /* we enable VMX outside of SMX as well so that if there was some */ /* error in the TXT boot, VMX will continue to work */ g_feat_ctrl_msr |= IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX | IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX | IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER | IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL | IA32_FEATURE_CONTROL_MSR_LOCK; wrmsrl(MSR_IA32_FEATURE_CONTROL, g_feat_ctrl_msr); return true; #else return false; #endif } /* check that SENTER (w/ full params) is enabled */ if ( !(g_feat_ctrl_msr & (IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER | IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL)) ) { printk(TBOOT_ERR"ERR: SENTER disabled by feature control MSR (%lx)\n", g_feat_ctrl_msr); return false; } return true; } bool use_mwait(void) { return get_tboot_mwait() && (g_cpuid_ext_feat_info & CPUID_X86_FEATURE_XMM3); } tb_error_t supports_txt(void) { capabilities_t cap; /* processor must support cpuid and must be Intel CPU */ if ( !read_processor_info() ) return TB_ERR_SMX_NOT_SUPPORTED; /* processor must support SMX */ if ( !supports_smx() ) return TB_ERR_SMX_NOT_SUPPORTED; if ( use_mwait() ) { /* set MONITOR/MWAIT support (SENTER will clear, so always set) */ uint64_t misc; misc = rdmsr(MSR_IA32_MISC_ENABLE); misc |= MSR_IA32_MISC_ENABLE_MONITOR_FSM; wrmsr(MSR_IA32_MISC_ENABLE, misc); } else if ( !supports_vmx() ) { return TB_ERR_VMX_NOT_SUPPORTED; } /* testing for chipset support requires enabling SMX on the processor */ write_cr4(read_cr4() | CR4_SMXE); printk(TBOOT_INFO"SMX is enabled\n"); /* * verify that an TXT-capable chipset is present and * check that all needed SMX capabilities are supported */ cap = __getsec_capabilities(0); if ( cap.chipset_present ) { if ( cap.senter && cap.sexit && cap.parameters && cap.smctrl && cap.wakeup ) { printk(TBOOT_INFO"TXT chipset and all needed capabilities present\n"); return TB_ERR_NONE; } else printk(TBOOT_ERR"ERR: insufficient SMX capabilities (%x)\n", cap._raw); } else printk(TBOOT_ERR"ERR: TXT-capable chipset not present\n"); /* since we are failing, we should clear the SMX flag */ write_cr4(read_cr4() & ~CR4_SMXE); return TB_ERR_TXT_NOT_SUPPORTED; } static bool reserve_vtd_delta_mem(uint64_t min_lo_ram, uint64_t max_lo_ram, uint64_t min_hi_ram, uint64_t max_hi_ram) { uint64_t base, length; (void)min_lo_ram; (void)min_hi_ram;/* portably suppress compiler warning */ txt_heap_t* txt_heap = get_txt_heap(); os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap); if ( max_lo_ram != (os_sinit_data->vtd_pmr_lo_base + os_sinit_data->vtd_pmr_lo_size) ) { base = os_sinit_data->vtd_pmr_lo_base + os_sinit_data->vtd_pmr_lo_size; length = max_lo_ram - base; printk(TBOOT_INFO"reserving 0x%Lx - 0x%Lx, which was truncated for VT-d\n", base, base + length); if ( !e820_reserve_ram(base, length) ) return false; if (!efi_memmap_reserve(base, length)) { return false; } } if ( max_hi_ram != (os_sinit_data->vtd_pmr_hi_base + os_sinit_data->vtd_pmr_hi_size) ) { base = os_sinit_data->vtd_pmr_hi_base + os_sinit_data->vtd_pmr_hi_size; length = max_hi_ram - base; printk(TBOOT_INFO"reserving 0x%Lx - 0x%Lx, which was truncated for VT-d\n", base, base + length); if ( !e820_reserve_ram(base, length) ) return false; if (!efi_memmap_reserve(base, length)) { return false; } } return true; } static bool verify_vtd_pmrs(txt_heap_t *txt_heap) { os_sinit_data_t *os_sinit_data, tmp_os_sinit_data; uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram; os_sinit_data = get_os_sinit_data_start(txt_heap); /* * make sure the VT-d PMRs were actually set to cover what * we expect */ /* calculate what they should have been */ /* no e820 table on S3 resume, so use saved (sealed) values */ if ( s3_flag ) { min_lo_ram = g_pre_k_s3_state.vtd_pmr_lo_base; max_lo_ram = min_lo_ram + g_pre_k_s3_state.vtd_pmr_lo_size; min_hi_ram = g_pre_k_s3_state.vtd_pmr_hi_base; max_hi_ram = min_hi_ram + g_pre_k_s3_state.vtd_pmr_hi_size; } else { if ( !get_ram_ranges(&min_lo_ram, &max_lo_ram, &min_hi_ram, &max_hi_ram) ) return false; /* if vtd_pmr_lo/hi sizes rounded to 2MB granularity are less than the max_lo/hi_ram values determined from the e820 table, then we must reserve the differences in e820 table so that unprotected memory is not used by the kernel */ if ( !reserve_vtd_delta_mem(min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram) ) { printk(TBOOT_ERR"failed to reserve VT-d PMR delta memory\n"); return false; } } /* compare to current values */ tb_memset(&tmp_os_sinit_data, 0, sizeof(tmp_os_sinit_data)); tmp_os_sinit_data.version = os_sinit_data->version; set_vtd_pmrs(&tmp_os_sinit_data, min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram); if ( (tmp_os_sinit_data.vtd_pmr_lo_base != os_sinit_data->vtd_pmr_lo_base) || (tmp_os_sinit_data.vtd_pmr_lo_size != os_sinit_data->vtd_pmr_lo_size) || (tmp_os_sinit_data.vtd_pmr_hi_base != os_sinit_data->vtd_pmr_hi_base) || (tmp_os_sinit_data.vtd_pmr_hi_size != os_sinit_data->vtd_pmr_hi_size) ) { printk(TBOOT_ERR"OS to SINIT data VT-d PMR settings do not match:\n"); print_os_sinit_data_vtdpmr(&tmp_os_sinit_data); print_os_sinit_data_vtdpmr(os_sinit_data); return false; } if ( !s3_flag ) { /* save the verified values so that they can be sealed for S3 */ g_pre_k_s3_state.vtd_pmr_lo_base = os_sinit_data->vtd_pmr_lo_base; g_pre_k_s3_state.vtd_pmr_lo_size = os_sinit_data->vtd_pmr_lo_size; g_pre_k_s3_state.vtd_pmr_hi_base = os_sinit_data->vtd_pmr_hi_base; g_pre_k_s3_state.vtd_pmr_hi_size = os_sinit_data->vtd_pmr_hi_size; } return true; } void set_vtd_pmrs(os_sinit_data_t *os_sinit_data, uint64_t min_lo_ram, uint64_t max_lo_ram, uint64_t min_hi_ram, uint64_t max_hi_ram) { printk(TBOOT_DETA"min_lo_ram: 0x%Lx, max_lo_ram: 0x%Lx\n", min_lo_ram, max_lo_ram); printk(TBOOT_DETA"min_hi_ram: 0x%Lx, max_hi_ram: 0x%Lx\n", min_hi_ram, max_hi_ram); /* * base must be 2M-aligned and size must be multiple of 2M * (so round bases and sizes down--rounding size up might conflict * with a BIOS-reserved region and cause problems; in practice, rounding * base down doesn't) * we want to protect all of usable mem so that any kernel allocations * before VT-d remapping is enabled are protected */ min_lo_ram &= ~0x1fffffULL; uint64_t lo_size = (max_lo_ram - min_lo_ram) & ~0x1fffffULL; os_sinit_data->vtd_pmr_lo_base = min_lo_ram; os_sinit_data->vtd_pmr_lo_size = lo_size; min_hi_ram &= ~0x1fffffULL; uint64_t hi_size = (max_hi_ram - min_hi_ram) & ~0x1fffffULL; os_sinit_data->vtd_pmr_hi_base = min_hi_ram; os_sinit_data->vtd_pmr_hi_size = hi_size; } tb_error_t txt_verify_platform(void) { txt_heap_t *txt_heap; tb_error_t err; /* check TXT supported */ err = supports_txt(); if ( err != TB_ERR_NONE ) return err; if ( !vtd_bios_enabled() ) { return TB_ERR_VTD_NOT_SUPPORTED; } /* check is TXT_RESET.STS is set, since if it is SENTER will fail */ txt_ests_t ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS); if ( ests.txt_reset_sts ) { printk(TBOOT_ERR"TXT_RESET.STS is set and SENTER is disabled (0x%02Lx)\n", ests._raw); return TB_ERR_SMX_NOT_SUPPORTED; } /* verify BIOS to OS data */ txt_heap = get_txt_heap(); if ( !verify_bios_data(txt_heap) ) return TB_ERR_TXT_NOT_SUPPORTED; return TB_ERR_NONE; } static bool verify_saved_mtrrs(txt_heap_t *txt_heap) { os_mle_data_t *os_mle_data; os_mle_data = get_os_mle_data_start(txt_heap); return validate_mtrrs(&(os_mle_data->saved_mtrr_state)); } tb_error_t txt_post_launch_verify_platform(void) { txt_heap_t *txt_heap; /* * verify some of the heap structures */ txt_heap = get_txt_heap(); if ( !verify_txt_heap(txt_heap, false) ) return TB_ERR_POST_LAUNCH_VERIFICATION; /* verify the saved MTRRs */ if ( !verify_saved_mtrrs(txt_heap) ) return TB_ERR_POST_LAUNCH_VERIFICATION; /* verify that VT-d PMRs were really set as required */ if ( !verify_vtd_pmrs(txt_heap) ) return TB_ERR_POST_LAUNCH_VERIFICATION; return TB_ERR_NONE; } bool verify_e820_map(sinit_mdr_t* mdrs_base, uint32_t num_mdrs) { sinit_mdr_t* mdr_entry; sinit_mdr_t tmp_entry; uint64_t base, length; uint32_t i, j, pos; if ( (mdrs_base == NULL) || (num_mdrs == 0) ) return false; /* sort mdrs */ for( i = 0; i < num_mdrs; i++ ) { tb_memcpy(&tmp_entry, &mdrs_base[i], sizeof(sinit_mdr_t)); pos = i; for ( j = i + 1; j < num_mdrs; j++ ) { if ( ( tmp_entry.base > mdrs_base[j].base ) || (( tmp_entry.base == mdrs_base[j].base ) && ( tmp_entry.length > mdrs_base[j].length )) ) { tb_memcpy(&tmp_entry, &mdrs_base[j], sizeof(sinit_mdr_t)); pos = j; } } if ( pos > i ) { tb_memcpy(&mdrs_base[pos], &mdrs_base[i], sizeof(sinit_mdr_t)); tb_memcpy(&mdrs_base[i], &tmp_entry, sizeof(sinit_mdr_t)); } } /* verify e820 map against mdrs */ /* find all ranges *not* in MDRs: if any of it is in e820 as RAM then set that to RESERVED. */ i = 0; base = 0; while ( i < num_mdrs ) { mdr_entry = &mdrs_base[i]; i++; if ( mdr_entry->mem_type > MDR_MEMTYPE_GOOD ) continue; length = mdr_entry->base - base; if ( (length > 0) && (!e820_reserve_ram(base, length)) ) return false; base = mdr_entry->base + mdr_entry->length; } /* deal with the last gap */ length = (uint64_t)-1 - base; return e820_reserve_ram(base, length); } static void print_mseg_hdr(mseg_hdr_t *mseg_hdr) { printk(TBOOT_DETA"MSEG header dump for 0x%x:\n", (uint32_t)mseg_hdr); printk(TBOOT_DETA"\t revision_id = 0x%x\n", mseg_hdr->revision_id); printk(TBOOT_DETA"\t smm_monitor_features = 0x%x\n", mseg_hdr->smm_mon_feat); printk(TBOOT_DETA"\t gdtr_limit = 0x%x\n", mseg_hdr->gdtr_limit); printk(TBOOT_DETA"\t gdtr_base_offset = 0x%x\n", mseg_hdr->gdtr_base_offset); printk(TBOOT_DETA"\t cs_sel = 0x%x\n", mseg_hdr->cs_sel); printk(TBOOT_DETA"\t eip_offset = 0x%x\n", mseg_hdr->eip_offset); printk(TBOOT_DETA"\t esp_offset = 0x%x\n", mseg_hdr->esp_offset); printk(TBOOT_DETA"\t cr3_offset = 0x%x\n", mseg_hdr->cr3_offset); } static bool are_mseg_hdrs_equal(void *mseg_base1, void *mseg_base2) { mseg_hdr_t *mseg_hdr1, *mseg_hdr2; mseg_hdr1 = (mseg_hdr_t *)mseg_base1; mseg_hdr2 = (mseg_hdr_t *)mseg_base2; print_mseg_hdr(mseg_hdr1); print_mseg_hdr(mseg_hdr2); if ( mseg_hdr1->revision_id != mseg_hdr2->revision_id ) { printk(TBOOT_ERR"revision id is not consistent.\n"); return false; } if ( (mseg_hdr1->smm_mon_feat & 0xfffffffe) || (mseg_hdr2->smm_mon_feat & 0xfffffffe) ) { printk(TBOOT_ERR"bits 1:31 of SMM-monitor features field should be zero.\n"); return false; } if ( mseg_hdr1->smm_mon_feat != mseg_hdr2->smm_mon_feat ) { printk(TBOOT_ERR"SMM-monitor features are not consistent.\n"); return false; } if ( (mseg_hdr1->gdtr_limit != mseg_hdr2->gdtr_limit) || (mseg_hdr1->gdtr_base_offset != mseg_hdr2->gdtr_base_offset) || (mseg_hdr1->cs_sel != mseg_hdr2->cs_sel) || (mseg_hdr1->eip_offset != mseg_hdr2->eip_offset) || (mseg_hdr1->esp_offset != mseg_hdr2->esp_offset) || (mseg_hdr1->cr3_offset != mseg_hdr2->cr3_offset) ) { printk(TBOOT_ERR"states for SMM activation are not consistent.\n"); return false; } return true; } static bool verify_mseg(uint64_t smm_mon_ctl) { txt_heap_t *txt_heap = get_txt_heap(); sinit_mle_data_t *sinit_mle_data = get_sinit_mle_data_start(txt_heap); void *mseg_base, *txt_mseg_base; /* opt-out */ if ( !(smm_mon_ctl & MSR_IA32_SMM_MONITOR_CTL_VALID) ) { printk(TBOOT_INFO"\topt-out\n"); return true; } if ( !sinit_mle_data->mseg_valid ) { printk(TBOOT_INFO"\topt-out\n"); return true; } /* opt-in */ printk(TBOOT_INFO"\topt-in "); mseg_base = (void *)(unsigned long) MSR_IA32_SMM_MONITOR_CTL_MSEG_BASE(smm_mon_ctl); txt_mseg_base = (void *)(uint32_t)read_pub_config_reg(TXTCR_MSEG_BASE); if ( are_mseg_hdrs_equal(mseg_base, txt_mseg_base) ) { printk(TBOOT_INFO"and same MSEG header\n"); return true; } printk(TBOOT_ERR"but different MSEG headers\n"); return false; } bool verify_stm(unsigned int cpuid) { static uint64_t ilp_smm_mon_ctl; uint64_t smm_mon_ctl, apicbase; smm_mon_ctl = rdmsr(MSR_IA32_SMM_MONITOR_CTL); apicbase = rdmsr(MSR_APICBASE); if ( apicbase & APICBASE_BSP ) { ilp_smm_mon_ctl = smm_mon_ctl; printk(TBOOT_DETA"MSR for SMM monitor control on BSP is 0x%Lx.\n", ilp_smm_mon_ctl); /* verify ILP's MSEG == TXT.MSEG.BASE */ printk(TBOOT_INFO"verifying ILP is opt-out " "or has the same MSEG header with TXT.MSEG.BASE\n\t"); if ( !verify_mseg(ilp_smm_mon_ctl) ) { printk(TBOOT_ERR" : failed.\n"); return false; } printk(TBOOT_INFO" : succeeded.\n"); } else { printk(TBOOT_DETA"MSR for SMM monitor control on cpu %u is 0x%Lx\n", cpuid, smm_mon_ctl); /* verify ILP's SMM MSR == RLP's SMM MSR */ printk(TBOOT_INFO"verifying ILP's MSR_IA32_SMM_MONITOR_CTL with cpu %u\n\t", cpuid); if ( smm_mon_ctl != ilp_smm_mon_ctl ) { printk(TBOOT_ERR" : failed.\n"); return false; } printk(TBOOT_INFO" : succeeded.\n"); /* since the RLP's MSR is the same. No need to verify MSEG header */ } return true; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/tboot/txt/vmcs.c0000644000000000000000000004404614210363175014147 0ustar 00000000000000/* * vmcs.c: create and manage mini-VT VM for APs to handle INIT-SIPI-SIPI * * Copyright (c) 2003-2010, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* no vmexit on external intr as mini guest only handle INIT & SIPI */ #define MONITOR_PIN_BASED_EXEC_CONTROLS \ ( PIN_BASED_NMI_EXITING ) /* no vmexit on hlt as guest only run this instruction */ #define MONITOR_CPU_BASED_EXEC_CONTROLS \ ( CPU_BASED_INVDPG_EXITING | \ CPU_BASED_MWAIT_EXITING ) #define MONITOR_VM_EXIT_CONTROLS \ ( VM_EXIT_ACK_INTR_ON_EXIT ) /* Basic flags for VM-Entry controls. */ #define MONITOR_VM_ENTRY_CONTROLS 0x00000000 #define EXCEPTION_BITMAP_BP (1 << 3) /* Breakpoint */ #define EXCEPTION_BITMAP_PG (1 << 14) /* Page Fault */ #define MONITOR_DEFAULT_EXCEPTION_BITMAP \ ( EXCEPTION_BITMAP_PG | \ EXCEPTION_BITMAP_BP ) #define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" ((n)<<3) ) extern char gdt_table[]; #define RESET_TSS_DESC(n) gdt_table[((n)<<3)+5] = 0x89 /* lock that protects APs against race conditions on wakeup and shutdown */ struct mutex ap_lock; /* counter for APs entering/exiting wait-for-sipi */ extern atomic_t ap_wfs_count; /* flag for (all APs) exiting mini guest (1 = exit) */ uint32_t aps_exit_guest; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; extern char _end[]; extern void print_cr0(const char *s); extern void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec); extern void apply_policy(tb_error_t error); static uint32_t vmcs_rev_id; static uint32_t pin_based_vm_exec_ctrls; static uint32_t proc_based_vm_exec_ctrls; static uint32_t vm_exit_ctrls; static uint32_t vm_entry_ctrls; static void init_vmx_ctrl(uint32_t msr, uint32_t ctrl_val, uint32_t *ctrl) { uint32_t lo, hi; uint64_t val; val = rdmsr(msr); lo = (uint32_t)(val & 0xffffffffUL); hi = (uint32_t)(val >> 32); *ctrl = (ctrl_val & hi) | lo; /* make sure that the conditions we want are actually allowed */ if ( (*ctrl & ctrl_val) != ctrl_val ) apply_policy(TB_ERR_FATAL); } static void init_vmcs_config(void) { uint64_t val; val = rdmsr(MSR_IA32_VMX_BASIC_MSR); vmcs_rev_id = (uint32_t)(val & 0xffffffffUL); init_vmx_ctrl(MSR_IA32_VMX_PINBASED_CTLS_MSR, MONITOR_PIN_BASED_EXEC_CONTROLS, &pin_based_vm_exec_ctrls); init_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS_MSR, MONITOR_CPU_BASED_EXEC_CONTROLS, &proc_based_vm_exec_ctrls); init_vmx_ctrl(MSR_IA32_VMX_EXIT_CTLS_MSR, MONITOR_VM_EXIT_CONTROLS, &vm_exit_ctrls); init_vmx_ctrl(MSR_IA32_VMX_ENTRY_CTLS_MSR, MONITOR_VM_ENTRY_CONTROLS, &vm_entry_ctrls); } extern uint32_t idle_pg_table[PAGE_SIZE / 4]; /* build a 1-level identity-map page table [0, _end] on AP for vmxon */ static void build_ap_pagetable(void) { #define PTE_FLAGS 0xe3 /* PRESENT+RW+A+D+4MB */ uint32_t pt_entry = PTE_FLAGS; uint32_t *pte = &idle_pg_table[0]; while ( pt_entry <= (uint32_t)&_end + PTE_FLAGS ) { *pte = pt_entry; /* Incriments 4MB page at a time */ pt_entry += 1 << FOURMB_PAGE_SHIFT; pte++; } } extern char host_vmcs[PAGE_SIZE]; extern char ap_vmcs[NR_CPUS][PAGE_SIZE]; static bool start_vmx(unsigned int cpuid) { struct vmcs_struct *vmcs; static bool init_done = false; write_cr4(read_cr4() | CR4_VMXE); vmcs = (struct vmcs_struct *)host_vmcs; /* TBD: it would be good to check VMX config is same on all CPUs */ /* only initialize this data the first time */ if ( !init_done ) { /*printk(TBOOT_INFO"one-time initializing VMX mini-guest\n");*/ tb_memset(vmcs, 0, PAGE_SIZE); init_vmcs_config(); vmcs->vmcs_revision_id = vmcs_rev_id; /* enable paging as required by vmentry */ build_ap_pagetable(); init_done = true; } /*printk(TBOOT_INFO"per-cpu initializing VMX mini-guest on cpu %u\n", cpuid);*/ /* enable paging using 1:1 page table [0, _end] */ /* addrs outside of tboot (e.g. MMIO) are not mapped) */ write_cr3((unsigned long)idle_pg_table); write_cr4(read_cr4() | CR4_PSE); write_cr0(read_cr0() | CR0_PG); if ( __vmxon((unsigned long)vmcs) ) { write_cr4(read_cr4() & ~CR4_VMXE); write_cr4(read_cr4() & ~CR4_PSE); write_cr0(read_cr0() & ~CR0_PG); printk(TBOOT_ERR"VMXON failed for cpu %u\n", cpuid); return false; } printk(TBOOT_DETA"VMXON done for cpu %u\n", cpuid); return true; } static void stop_vmx(unsigned int cpuid) { struct vmcs_struct *vmcs = NULL; if ( !(read_cr4() & CR4_VMXE) ) { printk(TBOOT_DETA"stop_vmx() called when VMX not enabled\n"); return; } __vmptrst((unsigned long)vmcs); __vmpclear((unsigned long)vmcs); __vmxoff(); write_cr4(read_cr4() & ~CR4_VMXE); /* diable paging to restore AP's state to boot xen */ write_cr0(read_cr0() & ~CR0_PG); write_cr4(read_cr4() & ~CR4_PSE); printk(TBOOT_DETA"VMXOFF done for cpu %u\n", cpuid); } /* in tboot/common/boot.S */ extern void vmx_asm_vmexit_handler(void); extern void _mini_guest(void); /* consturct guest/host vmcs: * make guest vmcs from physical environment, * so only one binary switch between root and non-root */ static void construct_vmcs(void) { struct __packed { uint16_t limit; uint32_t base; } xdt; unsigned long cr0, cr3, cr4, eflags, rsp; unsigned int tr; union vmcs_arbytes arbytes; uint16_t seg; __vmwrite(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_ctrls); __vmwrite(VM_EXIT_CONTROLS, vm_exit_ctrls); __vmwrite(VM_ENTRY_CONTROLS, vm_entry_ctrls); __vmwrite(CPU_BASED_VM_EXEC_CONTROL, proc_based_vm_exec_ctrls); /* segments selectors. */ __asm__ __volatile__ ("mov %%ss, %0\n" : "=r"(seg)); __vmwrite(HOST_SS_SELECTOR, seg); __vmwrite(GUEST_SS_SELECTOR, seg); __asm__ __volatile__ ("mov %%ds, %0\n" : "=r"(seg)); __vmwrite(HOST_DS_SELECTOR, seg); __vmwrite(GUEST_DS_SELECTOR, seg); __asm__ __volatile__ ("mov %%es, %0\n" : "=r"(seg)); __vmwrite(HOST_ES_SELECTOR, seg); __vmwrite(GUEST_ES_SELECTOR, seg); __asm__ __volatile__ ("mov %%fs, %0\n" : "=r"(seg)); __vmwrite(HOST_FS_SELECTOR, seg); __vmwrite(GUEST_FS_SELECTOR, seg); __asm__ __volatile__ ("mov %%gs, %0\n" : "=r"(seg)); __vmwrite(HOST_GS_SELECTOR, seg); __vmwrite(GUEST_GS_SELECTOR, seg); __asm__ __volatile__ ("mov %%cs, %0\n" : "=r"(seg)); __vmwrite(GUEST_CS_SELECTOR, seg); __vmwrite(GUEST_RIP, (uint32_t)&_mini_guest); __vmwrite(HOST_CS_SELECTOR, seg); __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler); /* segment limits */ #define GUEST_SEGMENT_LIMIT 0xffffffff __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT); __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT); __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT); __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT); __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT); __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT); /* segment AR bytes, see boot.S for details */ arbytes.bytes = 0; arbytes.fields.seg_type = 0x3; /* type = 3 */ arbytes.fields.s = 1; /* code or data, i.e. not system */ arbytes.fields.dpl = 0; /* DPL = 0 */ arbytes.fields.p = 1; /* segment present */ arbytes.fields.default_ops_size = 1; /* 32-bit */ arbytes.fields.g = 1; arbytes.fields.null_bit = 0; /* not null */ __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes); __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes); __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes); __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes); __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes); arbytes.fields.seg_type = 0xb; /* type = 0xb */ __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes); /* segment BASE */ __vmwrite(GUEST_ES_BASE, 0); __vmwrite(GUEST_SS_BASE, 0); __vmwrite(GUEST_DS_BASE, 0); __vmwrite(GUEST_FS_BASE, 0); __vmwrite(GUEST_GS_BASE, 0); __vmwrite(GUEST_CS_BASE, 0); __vmwrite(HOST_FS_BASE, 0); __vmwrite(HOST_GS_BASE, 0); /* Guest LDT and TSS */ __vmwrite(GUEST_LDTR_SELECTOR, 0); __vmwrite(GUEST_LDTR_BASE, 0); __vmwrite(GUEST_LDTR_LIMIT, 0xffff); __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory"); if ( tr == 0 ) printk(TBOOT_ERR"tr is 0 on ap, may vmlaunch fail.\n"); __vmwrite(GUEST_TR_SELECTOR, tr); __vmwrite(GUEST_TR_BASE, 0); __vmwrite(GUEST_TR_LIMIT, 0xffff); __vmwrite(HOST_TR_SELECTOR, tr); __vmwrite(HOST_TR_BASE, 0); /* tboot does not use ldt */ arbytes.bytes = 0; arbytes.fields.s = 0; /* not code or data segement */ arbytes.fields.seg_type = 0x2; /* LDT */ arbytes.fields.p = 1; /* segment present */ arbytes.fields.default_ops_size = 0; /* 16-bit */ arbytes.fields.g = 1; __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes); /* setup a TSS for vmentry as zero TR is not allowed */ arbytes.bytes = 0; arbytes.fields.s = 0; /* not code or data seg */ arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */ arbytes.fields.p = 1; /* segment present */ arbytes.fields.default_ops_size = 0; /* 16-bit */ arbytes.fields.g = 1; __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes); /* GDT */ __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&xdt) : "memory"); __vmwrite(GUEST_GDTR_BASE, xdt.base); __vmwrite(GUEST_GDTR_LIMIT, xdt.limit); __vmwrite(HOST_GDTR_BASE, xdt.base); /* IDT */ __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&xdt) : "memory"); /*printk(TBOOT_INFO"idt.base=0x%x, limit=0x%x.\n", xdt.base, xdt.limit);*/ __vmwrite(GUEST_IDTR_BASE, xdt.base); __vmwrite(GUEST_IDTR_LIMIT, xdt.limit); __vmwrite(HOST_IDTR_BASE, xdt.base); /* control registers. */ cr0 = read_cr0(); cr3 = read_cr3(); cr4 = read_cr4(); __vmwrite(HOST_CR0, cr0); __vmwrite(HOST_CR4, cr4); __vmwrite(HOST_CR3, cr3); __vmwrite(GUEST_CR0, cr0); __vmwrite(CR0_READ_SHADOW, cr0); __vmwrite(GUEST_CR4, cr4); __vmwrite(CR4_READ_SHADOW, cr4); __vmwrite(GUEST_CR3, cr3); /* debug register */ __vmwrite(GUEST_DR7, 0); /* rflags & rsp */ eflags = read_eflags(); __vmwrite(GUEST_RFLAGS, eflags); __asm__ __volatile__ ("mov %%esp,%0\n\t" :"=r" (rsp)); __vmwrite(GUEST_RSP, rsp); __vmwrite(HOST_RSP, rsp); /* MSR intercepts. */ __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0); __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0); __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0); __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); __vmwrite(CR0_GUEST_HOST_MASK, ~0UL); __vmwrite(CR4_GUEST_HOST_MASK, ~0UL); __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0); __vmwrite(CR3_TARGET_COUNT, 0); __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_ACTIVE); __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); __vmwrite(VMCS_LINK_POINTER, ~0UL); __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL); __vmwrite(EXCEPTION_BITMAP, MONITOR_DEFAULT_EXCEPTION_BITMAP); /*printk(TBOOT_INFO"vmcs setup done.\n");*/ } static bool vmx_create_vmcs(unsigned int cpuid) { struct vmcs_struct *vmcs = (struct vmcs_struct *)&ap_vmcs[cpuid]; tb_memset(vmcs, 0, PAGE_SIZE); vmcs->vmcs_revision_id = vmcs_rev_id; /* vir addr equal to phy addr as we setup identity page table */ __vmpclear((unsigned long)vmcs); __vmptrld((unsigned long)vmcs); construct_vmcs(); return true; } static void launch_mini_guest(unsigned int cpuid) { unsigned long error; printk(TBOOT_DETA"launching mini-guest for cpu %u\n", cpuid); /* this is close enough to entering wait-for-sipi, so inc counter */ atomic_inc((atomic_t *)&_tboot_shared.num_in_wfs); __vmlaunch(); /* should not reach here */ atomic_dec(&ap_wfs_count); atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs); error = __vmread(VM_INSTRUCTION_ERROR); printk(TBOOT_ERR"vmlaunch failed for cpu %u, error code %lx\n", cpuid, error); apply_policy(TB_ERR_FATAL); } static void print_failed_vmentry_reason(unsigned int exit_reason) { unsigned long exit_qualification; exit_qualification = __vmread(EXIT_QUALIFICATION); printk(TBOOT_ERR"Failed vm entry (exit reason 0x%x) ", exit_reason); switch ( (uint16_t)exit_reason ) { case EXIT_REASON_INVALID_GUEST_STATE: printk(TBOOT_ERR"caused by invalid guest state (%ld).\n", exit_qualification); break; case EXIT_REASON_MSR_LOADING: printk(TBOOT_ERR"caused by MSR entry %ld loading.\n", exit_qualification); break; case EXIT_REASON_MACHINE_CHECK: printk(TBOOT_ERR"caused by machine check.\n"); break; default: printk(TBOOT_ERR"reason not known yet!"); break; } } /* Vmexit handler for physical INIT-SIPI-SIPI from the BSP * Do not use printk in this critical path as BSP only * wait for a short time */ void vmx_vmexit_handler(void) { unsigned int apicid = get_apicid(); unsigned int exit_reason = __vmread(VM_EXIT_REASON); /*printk("vmx_vmexit_handler, cpu= %d, exit_reason=%x.\n", apicid, exit_reason);*/ if ( (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) ) { print_failed_vmentry_reason(exit_reason); stop_vmx(apicid); atomic_dec(&ap_wfs_count); atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs); apply_policy(TB_ERR_FATAL); } else if ( exit_reason == EXIT_REASON_INIT ) { __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_WAIT_SIPI); __vmresume(); } else if ( exit_reason == EXIT_REASON_SIPI ) { /* even though standard MP sequence is INIT-SIPI-SIPI */ /* there is no need to wait for second SIPI (which may not */ /* always be delivered) */ /* but we should expect there to already have been INIT */ /* disable VT then jump to xen code */ unsigned long exit_qual = __vmread(EXIT_QUALIFICATION); uint32_t sipi_vec = (exit_qual & 0xffUL) << PAGE_SHIFT; /*printk("exiting due to SIPI: vector=%x\n", sipi_vec); */ stop_vmx(apicid); atomic_dec(&ap_wfs_count); atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs); cpu_wakeup(apicid, sipi_vec); /* cpu_wakeup() doesn't return, so we should never get here */ printk(TBOOT_ERR"cpu_wakeup() failed\n"); apply_policy(TB_ERR_FATAL); } else if ( exit_reason == EXIT_REASON_VMCALL ) { stop_vmx(apicid); atomic_dec(&ap_wfs_count); atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs); /* spin */ while ( true ) __asm__ __volatile__("cli; hlt;"); } else { printk(TBOOT_ERR"can't handle vmexit due to 0x%x.\n", exit_reason); __vmresume(); } } /* Launch a mini guest to handle the physical INIT-SIPI-SIPI from BSP */ void handle_init_sipi_sipi(unsigned int cpuid) { if ( cpuid >= NR_CPUS ) { printk(TBOOT_ERR"cpuid (%u) exceeds # supported CPUs\n", cpuid); apply_policy(TB_ERR_FATAL); mtx_leave(&ap_lock); return; } /* setup a dummy tss as vmentry require a non-zero host TR */ load_TR(3); /* clear the tss busy flag to avoid blocking other APs */ RESET_TSS_DESC(3); /* prepare a guest for INIT-SIPI-SIPI handling */ /* 1: setup VMX environment and VMXON */ if ( !start_vmx(cpuid) ) { apply_policy(TB_ERR_FATAL); mtx_leave(&ap_lock); return; } /* 2: setup VMCS */ if ( vmx_create_vmcs(cpuid) ) { mtx_leave(&ap_lock); /* 3: launch VM */ launch_mini_guest(cpuid); } printk(TBOOT_ERR"control should not return here from launch_mini_guest\n"); apply_policy(TB_ERR_FATAL); return; } void force_aps_exit(void) { aps_exit_guest = 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/test-patches/e820-test.patch0000644000000000000000000001653514210363175016147 0ustar 00000000000000diff -r 4ea7c584151a tboot/common/e820.c --- a/tboot/common/e820.c Tue Jan 13 11:29:14 2009 -0800 +++ b/tboot/common/e820.c Tue Jan 20 22:25:23 2009 -0800 @@ -623,6 +623,202 @@ bool get_ram_ranges(multiboot_info_t *mb return true; } +#define RUN_CASE(caseid) \ +{ \ + if ( caseid() ) \ + printk("VALIDATE_E820_UNIT_TEST: " #caseid " passed\n"); \ + else \ + printk("VALIDATE_E820_UNIT_TEST: " #caseid " failed\n"); \ +} + +#define E820_ENTRY(s, e, t) \ + { \ + sizeof(memory_map_t)-sizeof(uint32_t), \ + ((uint64_t)(s) & 0xffffffULL), \ + ((uint64_t)(s) >> 32), \ + (((uint64_t)(e) - (uint64_t)(s)) & 0xffffffffULL), \ + (((uint64_t)(e) - (uint64_t)(s)) >> 32), \ + (t) \ + } + +static memory_map_t test_map[32] = { + E820_ENTRY(0x00000, 0x04000, E820_RAM), + E820_ENTRY(0x08000, 0x0c000, E820_RAM), + E820_ENTRY(0x10000, 0x14000, E820_RAM), + E820_ENTRY(0x18000, 0x1c000, E820_RAM), + E820_ENTRY(0x20000, 0x24000, E820_RAM), + E820_ENTRY(0x28000, 0x2c000, E820_RAM), + E820_ENTRY(0x30000, 0x34000, E820_RAM), + E820_ENTRY(0x38000, 0x3c000, E820_RAM), + E820_ENTRY(0x40000, 0x44000, E820_RAM), + E820_ENTRY(0x48000, 0x4c000, E820_RAM), + E820_ENTRY(0x50000, 0x54000, E820_RAM), + E820_ENTRY(0x58000, 0x5c000, E820_RAM), + E820_ENTRY(0x60000, 0x64000, E820_RAM), + E820_ENTRY(0x68000, 0x6c000, E820_RAM), + E820_ENTRY(0x70080, 0x74080, E820_RAM), + E820_ENTRY(0x78000, 0x7c000, E820_RAM), + E820_ENTRY(0x100000000ULL, 0x120000000ULL, E820_RAM), +}; +static int nr_test_map = 17; + +#define UNIT_PROTECT_REG(s, e) \ + printk("protecting 0x%Lx - 0x%Lx\n", (uint64_t)(s), (uint64_t)(e)); \ + if ( !protect_region(test_map, &nr_test_map, (s), ((e) - (s)), \ + E820_RESERVED) ) { \ + printk("\tFAILED\n"); \ + return false; \ + } + +static bool verify_entry(int idx, uint64_t start, uint64_t end, uint32_t type) +{ + memory_map_t *entry = &test_map[idx]; + uint64_t base = e820_base_64(entry); + uint64_t length = e820_length_64(entry); + + if ( start == base && (end - start) == length && type == entry->type ) + return true; + else + return false; +} + +#define UNIT_VERIFY(idx, s, e, t) \ + if ( !verify_entry(idx, s, e, t) ) { \ + printk("verification of index %u failed\n", idx); \ + return false; \ + } + + +static bool UNIT_PROT_01(void) +{ + /* reserve within gap space (e1---e1 r1---r1 e2---e2) */ + UNIT_PROTECT_REG(0x05000, 0x06000); + UNIT_VERIFY(0, 0x0, 0x04000, E820_RAM); + UNIT_VERIFY(1, 0x05000, 0x06000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_02(void) +{ + /* reserve partially overlapping beginning 1 (r1---e1+++r1---e1) */ + UNIT_PROTECT_REG(0x07000, 0x0a000); + UNIT_VERIFY(2, 0x07000, 0x0a000, E820_RESERVED); + UNIT_VERIFY(3, 0x0a000, 0x0c000, E820_RAM); + return true; +} + +static bool UNIT_PROT_03(void) +{ + /* reserve partially overlapping beginning 2 (r1---e1+++e1--e2+++r1--e2) */ + UNIT_PROTECT_REG(0x0e000, 0x1a000); + UNIT_VERIFY(4, 0x0e000, 0x1a000, E820_RESERVED); + UNIT_VERIFY(5, 0x1a000, 0x1c000, E820_RAM); + return true; +} + +static bool UNIT_PROT_04(void) +{ + /* reserve partially overlapping end 1 (e1---r1+++e1---r1) */ + UNIT_PROTECT_REG(0x22000, 0x26000); + UNIT_VERIFY(6, 0x20000, 0x22000, E820_RAM); + UNIT_VERIFY(7, 0x22000, 0x26000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_05(void) +{ + /* reserve partially overlapping end 2 (e1---r1+++e1---e2+++e2---r1) */ + UNIT_PROTECT_REG(0x2a000, 0x36000); + UNIT_VERIFY(8, 0x28000, 0x2a000, E820_RAM); + UNIT_VERIFY(9, 0x2a000, 0x36000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_06(void) +{ + /* reserve partially overlapping 2 (e1---r1+++e1---e2+++r1---e1) */ + UNIT_PROTECT_REG(0x3a000, 0x42000); + UNIT_VERIFY(10, 0x38000, 0x3a000, E820_RAM); + UNIT_VERIFY(11, 0x3a000, 0x42000, E820_RESERVED); + UNIT_VERIFY(12, 0x42000, 0x44000, E820_RAM); + return true; +} + +static bool UNIT_PROT_07(void) +{ + /* reserve fully containing 1 (r1---e1+++e1---r1) */ + UNIT_PROTECT_REG(0x46000, 0x4e000); + UNIT_VERIFY(13, 0x46000, 0x4e000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_08(void) +{ + /* reserve fully containing 2 (r1---e1+++e1-e2+++e2---r1) */ + UNIT_PROTECT_REG(0x4e000, 0x5d000); + UNIT_VERIFY(14, 0x4e000, 0x5d000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_09(void) +{ + /* reserve fully contained (e1---r1+++r1---e1) */ + UNIT_PROTECT_REG(0x62000, 0x63000); + UNIT_VERIFY(15, 0x60000, 0x62000, E820_RAM); + UNIT_VERIFY(16, 0x62000, 0x63000, E820_RESERVED); + UNIT_VERIFY(17, 0x63000, 0x64000, E820_RAM); + return true; +} + +static bool UNIT_PROT_10(void) +{ + /* reserve identical (e1r1+++e1r1) */ + UNIT_PROTECT_REG(0x68000, 0x6c000); + UNIT_VERIFY(18, 0x68000, 0x6c000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_11(void) +{ + /* reserve sub-page in sub-page range */ + UNIT_PROTECT_REG(0x70040, 0x74040); + UNIT_VERIFY(19, 0x70040, 0x74040, E820_RESERVED); + UNIT_VERIFY(20, 0x74040, 0x74080, E820_RAM); + UNIT_VERIFY(21, 0x78000, 0x7c000, E820_RAM); + return true; +} + +static bool UNIT_PROT_12(void) +{ + /* reserve in high memory (e1---r1+++r1---e1) */ + UNIT_PROTECT_REG(0x100004000ULL, 0x100006000ULL); + UNIT_VERIFY(22, 0x100000000ULL, 0x100004000ULL, E820_RAM); + UNIT_VERIFY(23, 0x100004000ULL, 0x100006000ULL, E820_RESERVED); + UNIT_VERIFY(24, 0x100006000ULL, 0x120000000ULL, E820_RAM); + return true; +} + +void unit_test_validate_e820(void) +{ + printk("test map before:\n"); + print_map(test_map, nr_test_map); + + RUN_CASE(UNIT_PROT_01); + RUN_CASE(UNIT_PROT_02); + RUN_CASE(UNIT_PROT_03); + RUN_CASE(UNIT_PROT_04); + RUN_CASE(UNIT_PROT_05); + RUN_CASE(UNIT_PROT_06); + RUN_CASE(UNIT_PROT_07); + RUN_CASE(UNIT_PROT_08); + RUN_CASE(UNIT_PROT_09); + RUN_CASE(UNIT_PROT_10); + RUN_CASE(UNIT_PROT_11); + RUN_CASE(UNIT_PROT_12); + + printk("all e820 unit tests passed:\n"); + print_map(test_map, nr_test_map); +} /* * Local variables: diff -r 4ea7c584151a tboot/common/tboot.c --- a/tboot/common/tboot.c Tue Jan 13 11:29:14 2009 -0800 +++ b/tboot/common/tboot.c Tue Jan 20 22:25:23 2009 -0800 @@ -267,6 +267,9 @@ void begin_launch(multiboot_info_t *mbi) printk("command line: %s\n", g_cmdline); if ( s3_flag ) printk("resume from S3\n"); + + extern void unit_test_validate_e820(void); + unit_test_validate_e820(); /* we should only be executing on the BSP */ rdmsrl(MSR_IA32_APICBASE, apicbase); tboot-1.10.5/test-patches/mtrrs-test.patch0000644000000000000000000004305114210363175016631 0ustar 00000000000000--- tboot/txt/mtrrs.c 2008-05-28 12:01:12.000000000 -0700 +++ tboot/txt/mtrrs-test.c 2008-05-28 12:00:34.000000000 -0700 @@ -415,10 +415,423 @@ return true; } +#ifdef MTRR_VALIDATION_UNITTEST + +#define RUN_CASE(caseid) {\ + if ( caseid() )\ + printk("VALIDATE_MTTR_UNIT_TEST: " #caseid " passed\n");\ + else\ + printk("VALIDATE_MTTR_UNIT_TEST: " #caseid " failed\n");\ +} + +static mtrr_state_t g_test_state; + +static bool UNIT_VM_V_01(void) +{ + g_test_state.num_var_mtrrs = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_02(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 0; + g_test_state.mtrr_physmasks[0].mask = 0x000000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_03(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x000000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_04(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFFFFF; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_05(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_06(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x001000; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF000; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_07(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x001000; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 0; + g_test_state.mtrr_physmasks[1].mask = 0xFFF000; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_08(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_09(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRCOMB; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_10(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRBACK; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_11(void) +{ + g_test_state.num_var_mtrrs = 3; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + g_test_state.mtrr_physbases[2].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[2].reserved1 = 0; + g_test_state.mtrr_physbases[2].base = 0x000800; + g_test_state.mtrr_physbases[2].reserved2 = 0; + g_test_state.mtrr_physmasks[2].reserved1 = 0; + g_test_state.mtrr_physmasks[2].v = 1; + g_test_state.mtrr_physmasks[2].mask = 0xFFF000; + g_test_state.mtrr_physmasks[2].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_01(void) +{ + g_test_state.num_var_mtrrs = 17; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_02(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x000001; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_03(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x800001; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_04(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x000002; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_05(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x00FF00; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_06(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x400000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_07(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x001000; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF0F0; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_08(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRCOMB; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_09(void) +{ + g_test_state.num_var_mtrrs = 3; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF800; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF000; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + g_test_state.mtrr_physbases[2].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[2].reserved1 = 0; + g_test_state.mtrr_physbases[2].base = 0x000800; + g_test_state.mtrr_physbases[2].reserved2 = 0; + g_test_state.mtrr_physmasks[2].reserved1 = 0; + g_test_state.mtrr_physmasks[2].v = 1; + g_test_state.mtrr_physmasks[2].mask = 0xFFF000; + g_test_state.mtrr_physmasks[2].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +void unit_test_validate_mtrrs(void) +{ + RUN_CASE(UNIT_VM_V_01 ); /* Zero items */ + RUN_CASE(UNIT_VM_V_02 ); /* 1 invalid item */ + RUN_CASE(UNIT_VM_V_03 ); /* 1 valid item. Whole region protected. */ + RUN_CASE(UNIT_VM_V_04 ); /* 1 valid item. 1 page protected. */ + RUN_CASE(UNIT_VM_V_05 ); /* 1 valid item. 2^n pages protected. */ + RUN_CASE(UNIT_VM_V_06 ); /* 2 valid item. 2^n pages protected. */ + RUN_CASE(UNIT_VM_V_07 ); /* 2 items, 1 valid, 1 invalid. 2^n pages protected. */ + RUN_CASE(UNIT_VM_V_08 ); /* 2 overlapped items, with same type. */ + RUN_CASE(UNIT_VM_V_09 ); /* 2 overlapped items, 1 MTRR_TYPE_UNCACHABLE (0) */ + RUN_CASE(UNIT_VM_V_10 ); /* 2 overlapped items, 1 MTRR_TYPE_WRTHROUGH (4), 1 MTRR_TYPE_WRBACK(6) */ + RUN_CASE(UNIT_VM_V_11 ); /* 3 overlapped items, 1 MTRR_TYPE_UNCACHABLE(0), 1 MTRR_TYPE_WRTHROUGH (4), 1 MTRR_TYPE_WRPROT(5) */ + RUN_CASE(UNIT_VM_IV_01); /* 17 items, should be larger than mtrr_cap.vcnt */ + RUN_CASE(UNIT_VM_IV_02); /* 1 valid item, non-contiguous case 1. */ + RUN_CASE(UNIT_VM_IV_03); /* 1 valid item, non-contiguous case 2. */ + RUN_CASE(UNIT_VM_IV_04); /* 1 valid item, non-contiguous case 3. */ + RUN_CASE(UNIT_VM_IV_05); /* 1 valid item, non-contiguous case 4. */ + RUN_CASE(UNIT_VM_IV_06); /* 1 valid item, non-contiguous case 5. */ + RUN_CASE(UNIT_VM_IV_07); /* 2 valid items. One with non-contiguous region. */ + RUN_CASE(UNIT_VM_IV_08); /* 2 overlapped items, 1 MTRR_TYPE_WRCOMB(1), 1 MTRR_TYPE_WRTHROUGH(4) */ + RUN_CASE(UNIT_VM_IV_09); /* 3 overlapped items, 1 MTRR_TYPE_UNCACHABLE(0), 1 MTRR_TYPE_WRTHROUGH (4), 1 MTRR_TYPE_WRPROT(5) */ +} + +#endif /* MTRR_VALIDATION_UNITTEST */ + void restore_mtrrs(mtrr_state_t *saved_state) { int ndx; +#ifdef MTRR_VALIDATION_UNITTEST + unit_test_validate_mtrrs(); +#endif /* MTRR_VALIDATION_UNITTEST */ + /* disable all MTRRs first */ set_all_mtrrs(false); tboot-1.10.5/test-patches/tpm-test.patch0000644000000000000000000032142014210363175016261 0ustar 00000000000000diff -r 950fec11ef90 tboot/common/tboot.c --- a/tboot/common/tboot.c Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/common/tboot.c Tue Apr 17 10:15:33 2012 +0800 @@ -313,6 +313,7 @@ void begin_launch(multiboot_info_t *mbi) /* has already been launched */ /* make TPM ready for measured launch */ + tpm_unit_test_before_senter(); if ( !is_tpm_ready(0) ) apply_policy(TB_ERR_TPM_NOT_READY); diff -r 950fec11ef90 tboot/common/tpm.c --- a/tboot/common/tpm.c Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/common/tpm.c Tue Apr 17 10:13:40 2012 +0800 @@ -2121,6 +2121,2815 @@ uint32_t tpm_get_random(uint32_t localit return ret; } +#ifdef TPM_UNIT_TEST + +static void clean_buf(void) +{ + memset(cmd_buf, 0, TPM_CMD_SIZE_MAX); + memset(rsp_buf, 0, TPM_RSP_SIZE_MAX); +} + +static bool check_buf(uint8_t *exp_cmd, uint32_t cmd_size, + uint8_t *exp_rsp, uint32_t rsp_size) +{ + if ( memcmp(exp_cmd, cmd_buf, cmd_size) != 0 ) + return false; + if ( memcmp(exp_rsp, rsp_buf, rsp_size) != 0 ) + return false; + return true; +} + +static bool UNIT_PE_V_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t *out = NULL; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, out); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_04(void) +{ + uint32_t locality = 2; + uint32_t pcr = 17; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + /* for SDP3 */ + /* + 0xe2, 0x76, 0x21, 0x70, 0x8d, 0x8b, 0x74, 0x20, + 0x5e, 0x61, 0x3c, 0xe6, 0xd3, 0x39, 0xf8, 0x0b, + 0x3d, 0x83, 0x18, 0x42}};*/ + /* for WB */ + 0x46, 0xF5, 0xBE, 0x07, 0x41, 0xA0, 0xCC, 0x80, + 0x0C, 0x9D, 0x14, 0x68, 0x25, 0x75, 0x48, 0x7B, + 0x78, 0xB6, 0xD2, 0xA1}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + /* for SDP3 */ + /* 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xe2, 0x76, 0x21, 0x70, 0x8d, 0x8b, + 0x74, 0x20, 0x5e, 0x61, 0x3c, 0xe6, 0xd3, 0x39, + 0xf8, 0x0b, 0x3d, 0x83, 0x18, 0x42}; */ + /* for WB */ + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x46, 0xF5, 0xBE, 0x07, 0x41, 0xA0, + 0xCC, 0x80, 0x0C, 0x9D, 0x14, 0x68, 0x25, 0x75, + 0x48, 0x7B, 0x78, 0xB6, 0xD2, 0xA1}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_05(void) +{ + uint32_t locality = 2; + uint32_t pcr = 18; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + /* + tpm_pcr_value_t exp_out = {{ + 0xe5, 0x9b, 0x4b, 0xf8, 0xd3, 0x42, 0x3f, 0xe7, + 0xeb, 0xc4, 0x2c, 0xe3, 0xb0, 0xf8, 0x98, 0x35, + 0x09, 0x9e, 0x2b, 0x96}}; + */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00/*, 0xe5, 0x9b, 0x4b, 0xf8, 0xd3, 0x42, + 0x3f, 0xe7, 0xeb, 0xc4, 0x2c, 0xe3, 0xb0, 0xf8, + 0x98, 0x35, 0x09, 0x9e, 0x2b, 0x96*/}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + /* + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + */ + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_06(void) +{ + uint32_t locality = 2; + uint32_t pcr = 19; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_07(void) +{ + uint32_t locality = 2; + uint32_t pcr = 20; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_IV_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_digest_t *in = NULL; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_02(void) +{ + uint32_t locality = 5; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_03(void) +{ + uint32_t locality = 0; + uint32_t pcr = 24; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_04(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_05(void) +{ + uint32_t locality = 1; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_06(void) +{ + uint32_t locality = 0; + uint32_t pcr = 17; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_LOCALITY;/* in SPD 3 whould be TPM_NOTLOCAL */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x3d}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_04(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_05(void) +{ + uint32_t locality = 2; + uint32_t pcr = 17; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + /* for SDP3 */ + /* 0xf8, 0xf2, 0xfb, 0x54, 0xdb, 0x1b, 0xcb, 0xdf, + 0xcf, 0x48, 0xbe, 0xde, 0xb4, 0xf6, 0x94, 0x97, + 0x19, 0x25, 0xbd, 0x9b}}; */ + /* for WB */ + 0x68, 0x2C, 0xC6, 0x4B, 0x89, 0x60, 0x4A, 0xF6, + 0x53, 0x0B, 0x80, 0xC2, 0xD7, 0x35, 0x00, 0x4F, + 0xC8, 0x95, 0x74, 0xE0}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x11}; + uint8_t exp_rsp[] = { + /* for SDP3 */ + /* 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xf2, 0xfb, 0x54, 0xdb, 0x1b, + 0xcb, 0xdf, 0xcf, 0x48, 0xbe, 0xde, 0xb4, 0xf6, + 0x94, 0x97, 0x19, 0x25, 0xbd, 0x9b}; */ + /* for WB */ + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x68, 0x2C, 0xC6, 0x4B, 0x89, 0x60, + 0x4A, 0xF6, 0x53, 0x0B, 0x80, 0xC2, 0xD7, 0x35, + 0x00, 0x4F, 0xC8, 0x95, 0x74, 0xE0}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_06(void) +{ + uint32_t locality = 2; + uint32_t pcr = 18; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + /* + tpm_pcr_value_t exp_out = {{ + 0x8d, 0x84, 0xdb, 0x02, 0xc0, 0x13, 0x9d, 0x2c, + 0x51, 0xdb, 0x15, 0xd8, 0xc6, 0xc4, 0x1b, 0xc0, + 0x6b, 0x34, 0xbe, 0xeb}}; + */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x12}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00/*, 0x8d, 0x84, 0xdb, 0x02, 0xc0, 0x13, + 0x9d, 0x2c, 0x51, 0xdb, 0x15, 0xd8, 0xc6, 0xc4, + 0x1b, 0xc0, 0x6b, 0x34, 0xbe, 0xeb*/}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + /* + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + */ + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_07(void) +{ + uint32_t locality = 2; + uint32_t pcr = 19; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_08(void) +{ + uint32_t locality = 2; + uint32_t pcr = 20; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_09(void) +{ + uint32_t locality = 0; + uint32_t pcr = 17; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x11}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_IV_01(void) +{ + uint32_t locality = 5; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PR_IV_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 24; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PR_IV_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PR_IV_04(void) +{ + uint32_t locality = 1; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_V_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x01}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_V_02(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x01}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_V_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 20; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_IV_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 15; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_IV_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 24; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_IV_03(void) +{ + uint32_t locality = 5; + uint32_t pcr = 16; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_IV_04(void) +{ + uint32_t locality = 0; + uint32_t pcr = 20; + uint32_t ret; + + uint32_t exp_ret = TPM_NOTLOCAL; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x33}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_IV_05(void) +{ + uint32_t locality = 2; + uint32_t pcr = 17; + uint32_t ret; + + uint32_t exp_ret = TPM_NOTLOCAL; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x02}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x33}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +#define TPM_NV_INDEX_LCP_OWN 0x40000002 +#define TPM_NV_INDEX_SELFDEF 0x400000ff +#define TPM_NV_INDEX_UNDEF 0x400000ee + +static bool UNIT_NW_V_01(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_V_02(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09}; /* 746 */ + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + static uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xea, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; /* 768 */ + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, + (uint8_t *)data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf((uint8_t *)exp_cmd, sizeof(exp_cmd), + exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_V_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 746; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x02, 0xea, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_V_04(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_01(void) +{ + uint32_t locality = 5; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NW_IV_02(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NW_IV_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_UNDEF; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BADINDEX; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0xee, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x02}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_04(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 29; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_05(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 20; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_06(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a}; /* 747 */ + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, + (uint8_t *)data, data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NR_V_01(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[29] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp(data, &exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_V_02(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[TPM_NV_READ_VALUE_DATA_SIZE_MAX] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + static uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, }; /* 754 */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2}; + static uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; /* 768 */ + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, + (uint8_t *)data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp((uint8_t *)data, (uint8_t *)exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), + (uint8_t *)exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_V_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 754; + uint8_t data[14] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + uint8_t exp_data[] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x02, 0xf2, 0x00, 0x00, 0x00, 0x0e}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp(data, &exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_V_04(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp(data, &exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_01(void) +{ + uint32_t locality = 5; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NR_IV_02(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NR_IV_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_UNDEF; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BADINDEX; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xee, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x02}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_04(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 29; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_05(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 20; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_06(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[TPM_NV_READ_VALUE_DATA_SIZE_MAX + 1] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = TPM_NV_READ_VALUE_DATA_SIZE_MAX; + static uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, }; /* 754 */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2}; + static uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; /* 768 */ + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, + (uint8_t *)data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp((uint8_t *)data, (uint8_t *)exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), + (uint8_t *)exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_HMAC_V_01(void) +{ + uint8_t key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00}; + uint32_t in_data_size = 8; + uint8_t in_data[9] = "Hi There"; + uint8_t digest[20]; + bool ret; + + bool exp_ret = true; + uint8_t exp_md[20] = { + 0x67, 0x5b, 0x0b, 0x3a, 0x1b, 0x4d, 0xdf, 0x4e, 0x12, 0x48, + 0x72, 0xda, 0x6c, 0x2f, 0x63, 0x2b, 0xfe, 0xd9, 0x57, 0xe9}; + + clean_buf(); + ret = hmac(key, in_data, in_data_size, digest); + + if ( ret != exp_ret ) + return false; + { + printk("hmac result:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", digest[i]); + printk("\n"); + } + + if ( memcmp( digest, exp_md, sizeof(digest)) != 0 ) + return false; + + return true; +} + +/* +static bool UNIT_OS_V_01(void) +{ + uint32_t locality = 0; + tpm_entity_type_t ent_type = TPM_ET_SRK; + uint32_t ent_value = TPM_KH_SRK; + tpm_nonce_t odd_osap, even_osap, nonce_even; + tpm_authhandle_t hauth; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + clean_buf(); + ret = tpm_osap(locality, ent_type, ent_value, &odd_osap, &hauth, + &nonce_even, &even_osap); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_OI_V_01(void) +{ + uint32_t locality = 0; + tpm_nonce_t nonce_even; + tpm_authhandle_t hauth; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + clean_buf(); + ret = tpm_oiap(locality, &hauth, &nonce_even); + if ( ret != exp_ret ) + return false; + + return true; +} +*/ + +static bool test_tpm_wrap_seal(void) +{ + //uint32_t locality = 0; + //tpm_pcr_info_long_t pcr_info = + // {0x16, 0x01, 0x01, {3, {0, 0, 0}}, {3, {0, 0, 0}}, {{0,}}, {{0,}}}; + uint32_t in_data_size = 0x20; + uint8_t in_data[] = { + 0xaa,0xbd,0x5e,0x82,0xee,0x67,0x78,0x5e,0x43,0xbc,0x5e,0x26, + 0x64,0x5e,0x12,0x12,0x5b,0x90,0xdf,0x0a,0x53,0x61,0x96,0x4b, + 0xb9,0x4e,0x1d,0x2e,0x3c,0xb5,0xe6,0x1d}; + //tpm_stored_data12_t *sealed_data = (tpm_stored_data12_t *)&blob; + uint32_t ret = true; + uint8_t key_authdata[20] = { + 0x5b, 0xaa, 0x61, 0xe4, 0xc9, 0xb9, 0x3f, 0x3f, 0x06, 0x82, + 0x25, 0x0b, 0x6c, 0xf8, 0x33, 0x1b, 0x7e, 0xe6, 0x8f, 0xd8}; + uint8_t bb_authdata[20] = { + 0x5b, 0xaa, 0x61, 0xe4, 0xc9, 0xb9, 0x3f, 0x3f, 0x06, 0x82, + 0x25, 0x0b, 0x6c, 0xf8, 0x33, 0x1b, 0x7e, 0xe6, 0x8f, 0xd8}; + tpm_nonce_t odd_osap = {{ + 0x1f, 0xd5, 0xc9, 0xa9, 0x4c, 0x67, 0xed, 0xe2, 0x66, 0x8d, + 0x7f, 0xde, 0x7e, 0x81, 0xd4, 0x29, 0xc3, 0xbe, 0xbb, 0xb3}}; + tpm_nonce_t even_osap = {{ + 0x4f, 0xe5, 0xf4, 0xe3, 0x92, 0x35, 0x2e, 0x22, 0x9b, 0xe7, + 0xdd, 0x1b, 0xe0, 0xb7, 0x70, 0xf9, 0xd1, 0xf5, 0x6f, 0x74}}; + tpm_nonce_t nonce_even = {{ + 0xff, 0xbe, 0x07, 0x7c, 0x87, 0x07, 0x98, 0x0c, 0x00, 0xbc, + 0xbb, 0x96, 0x01, 0x88, 0xda, 0xc3, 0x0d, 0x02, 0xc0, 0x2e}}; + tpm_nonce_t nonce_odd = {{ + 0x1f, 0xd5, 0xc9, 0xa9, 0x4c, 0x67, 0xed, 0xe2, 0x66, 0x8d, + 0x7f, 0xde, 0x7e, 0x81, 0xd4, 0x29, 0xc3, 0xbe, 0xbb, 0xb3}}; + //tpm_authhandle_t hauth = 0; + tpm_authdata_t shared_secret, pub_auth;//, res_auth; + tpm_encauth_t enc_auth; + uint8_t cont_session = false; + //tpm_key_handle_t hkey = TPM_KH_SRK; + uint32_t pcr_info_size = 0;//sizeof(pcr_info); + uint32_t offset; + uint32_t ordinal = TPM_ORD_SEAL; + tpm_digest_t digest; + + /* generate nonce */ + //odd_osap = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + + /* establish a osap session */ + //ret = tpm_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth, + // &nonce_even, &even_osap); + //if ( ret != TPM_SUCCESS ) + // return ret; + + /* calculate the shared secret + shared-secret = HMAC(srk_auth, even_osap || odd_osap) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap); + hmac((uint8_t *)&key_authdata, WRAPPER_IN_BUF, offset, + (uint8_t *)&shared_secret); + { + printk("shared_secret:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", shared_secret[i]); + printk("\n"); + } + + /* generate ecrypted authdata for data + enc_auth = XOR(authdata, sha1(shared_secret || last_even_nonce)) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &shared_secret); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); + sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); + memcpy(&enc_auth, &bb_authdata, sizeof(blob_authdata)); + XOR_BLOB_TYPE(&enc_auth, &digest); + { + printk("enc_auth:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", enc_auth[i]); + printk("\n"); + } + + /* generate nonce */ + //nonce_odd = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + + /* calculate authdata */ + /* in_param_digest = sha1(1S ~ 6S) */ + offset = 0; + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &enc_auth); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size); + //UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, &pcr_info); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size); + UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size); + sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest); + { + printk("in param digest:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", digest.digest[i]); + printk("\n"); + } + + + /* authdata = hmac(key, in_param_digest || auth_params) */ + offset = 0; + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session); + hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset, + (uint8_t *)&pub_auth); + { + printk("pub auth data:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", pub_auth[i]); + printk("\n"); + } + + + /* call the simple seal function */ + /*ret = tpm_seal(locality, hkey, (const tpm_encauth_t *)&enc_auth, + pcr_info_size, &pcr_info, in_data_size, in_data, + hauth, &nonce_odd, &cont_session, + (const tpm_authdata_t *)&pub_auth, + (tpm_stored_data12_header_t *)sealed_data, + &nonce_even, &res_auth); + */ + + return ret; +} + +static uint8_t blob[512]; +static uint32_t sealed_data_size; + +static bool UNIT_SL_V_01(void) +{ + uint32_t locality = 0; + tpm_pcr_info_long_t pcr_info = + {0x6, 0x01, 0x01, {3, {0, 0, 0}}, {3, {0, 0, 0}}, {{0,}}, {{0,}}}; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + sealed_data_size = 512; + clean_buf(); + ret = _tpm_wrap_seal(locality, &pcr_info, in_data_size, in_data, + &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_02(void) +{ + uint32_t locality = 2; + tpm_pcr_info_long_t pcr_info = + {0x6, 0x04, 0x04, {3, {0, 0, 2}}, {3, {0, 0, 2}}, {{0,}}, {{0,}}}; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + uint32_t offset = 0; + uint32_t blob_size = 20; + + uint32_t exp_ret = TPM_SUCCESS; + + + tpm_pcr_value_t pcr_value; + ret = tpm_pcr_read(locality, 17, &pcr_value); + if ( ret != TPM_SUCCESS ) + return false; + offset = 0; + UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, &pcr_info.creation_pcr_selection); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &pcr_value); + sha1_buffer(WRAPPER_IN_BUF, offset, + (uint8_t *)&pcr_info.digest_at_creation); + memcpy((uint8_t *)&pcr_info.digest_at_release, + (uint8_t *)&pcr_info.digest_at_creation, + sizeof(pcr_info.digest_at_release)); + + sealed_data_size = 512; + clean_buf(); + ret = _tpm_wrap_seal(locality, &pcr_info, in_data_size, in_data, + &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_03(void) +{ + uint32_t locality = 0; + tpm_locality_selection_t release_locs = TPM_LOC_ZERO; + uint32_t pcr_nr_create = 0, pcr_nr_release = 0; + uint8_t *pcr_indcs_create = NULL, *pcr_indcs_release = NULL; + const tpm_pcr_value_t ** pcr_values_release = NULL; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + sealed_data_size = 512; + clean_buf(); + ret = tpm_seal(locality, release_locs, pcr_nr_create, pcr_indcs_create, + pcr_nr_release, pcr_indcs_release, pcr_values_release, + in_data_size, in_data, &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_04(void) +{ + uint32_t locality = 2; + tpm_locality_selection_t release_locs = TPM_LOC_TWO; + uint32_t pcr_nr_create = 1, pcr_nr_release = 1; + uint8_t pcr_indcs_create[1] = {17}, pcr_indcs_release[1] = {17}; + const tpm_pcr_value_t *pcr_values_release[1]; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + + tpm_pcr_value_t pcr_value; + ret = tpm_pcr_read(locality, 17, &pcr_value); + if ( ret != TPM_SUCCESS ) + return false; + pcr_values_release[0] = &pcr_value; + + sealed_data_size = 512; + clean_buf(); + ret = tpm_seal(locality, release_locs, pcr_nr_create, pcr_indcs_create, + pcr_nr_release, pcr_indcs_release, pcr_values_release, + in_data_size, in_data, &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_05(void) +{ + uint32_t locality = 2; + tpm_locality_selection_t release_locs = TPM_LOC_TWO; + uint32_t pcr_nr_create = 4, pcr_nr_release = 4; + uint8_t pcr_indcs_create[4] = {17,18,19,20}, + pcr_indcs_release[4] = {17,18,19,20}; + const tpm_pcr_value_t *pcr_values_release[4]; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + + tpm_pcr_value_t pcr_value[4]; + + for ( uint32_t i = 0; i < 4; i++ ) { + ret = tpm_pcr_read(locality, 17 + i, &pcr_value[i]); + if ( ret != TPM_SUCCESS ) + return false; + pcr_values_release[i] = &pcr_value[i]; + } + + sealed_data_size = 512; + clean_buf(); + ret = tpm_seal(locality, release_locs, pcr_nr_create, pcr_indcs_create, + pcr_nr_release, pcr_indcs_release, pcr_values_release, + in_data_size, in_data, &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_USL_V_01(void) +{ + uint32_t locality = 0; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = _tpm_wrap_unseal(locality, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_V_02(void) +{ + uint32_t locality = 2; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = _tpm_wrap_unseal(locality, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_V_03(void) +{ + uint32_t locality = 0; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = tpm_unseal(locality, sealed_data_size, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_V_04(void) +{ + uint32_t locality = 2; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = tpm_unseal(locality, sealed_data_size, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_IV_01(void) +{ + uint32_t locality = 2; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + blob[sealed_data_size/2] ^= 0x10; + clean_buf(); + ret = tpm_unseal(locality, sealed_data_size, blob, &data_size, data); + if ( ret != exp_ret ) + return true; + if ( data_size != exp_data_size ) + return true; + if ( memcmp(data, exp_data, data_size) != 0 ) + return true; + + return false; +} + +#define RUN_CASE(caseid) {\ + if ( caseid() )\ + printk("TPM_UNIT_TEST: " #caseid " passed\n");\ + else\ + printk("TPM_UNIT_TEST: " #caseid " failed\n");\ +} + +void tpm_unit_test_before_senter(void) +{ + RUN_CASE(UNIT_PR_V_01 ); /* Pcr16 */ + RUN_CASE(UNIT_PE_V_01 ); /* Pcr16, out != NULL */ + RUN_CASE(UNIT_PR_V_02 ); /* Pcr16 */ + RUN_CASE(UNIT_PS_V_01 ); /* Pcr16 */ + RUN_CASE(UNIT_PE_V_02 ); /* Pcr16, out = NULL */ + RUN_CASE(UNIT_PR_V_09 ); /* Pcr17 */ + RUN_CASE(UNIT_PE_IV_01); /* in = NULL */ + RUN_CASE(UNIT_PE_IV_02); /* locality = 5 */ + RUN_CASE(UNIT_PE_IV_03); /* pcr24 */ + RUN_CASE(UNIT_PE_IV_04); /* locality = 2 */ + RUN_CASE(UNIT_PE_IV_06); /* pcr17 */ + RUN_CASE(UNIT_PR_IV_01); /* locality = 5 */ + RUN_CASE(UNIT_PR_IV_02); /* Pcr24 */ + RUN_CASE(UNIT_PR_IV_03); /* Locality = 2 */ + RUN_CASE(UNIT_PS_IV_01); /* Pcr15 */ + RUN_CASE(UNIT_PS_IV_02); /* Pcr24 */ + RUN_CASE(UNIT_PS_IV_03); /* Locality = 5 */ + RUN_CASE(UNIT_PS_IV_04); /* Pcr20, locality = 0 */ + RUN_CASE(UNIT_NW_V_01 ); /* LCP_OWN, off 0, 29 bytes */ + RUN_CASE(UNIT_NR_V_01 ); /* LCP_OWN, off 0, 29 bytes */ + RUN_CASE(UNIT_NW_V_02 ); /* SELFDEF, off 0, 746 bytes */ + RUN_CASE(UNIT_NW_V_03 ); /* SELFDEF, off 746, 22bytes */ + RUN_CASE(UNIT_NR_V_02 ); /* SELFDEF, off 0, 754 bytes */ + RUN_CASE(UNIT_NR_V_03 ); /* SELFDEF, off 754, 14bytes */ + RUN_CASE(UNIT_NW_IV_01); /* Locality = 5 */ + RUN_CASE(UNIT_NW_IV_02); /* Locality = 2 */ + RUN_CASE(UNIT_NW_IV_03); /* UNDEF */ + RUN_CASE(UNIT_NW_IV_04); /* LCP_OWN, off 29 */ + RUN_CASE(UNIT_NW_IV_05); /* LCP_OWN, off 20, 20bytes */ + RUN_CASE(UNIT_NW_IV_06); /* SELFDEF, off 0, 747bytes */ + RUN_CASE(UNIT_NR_IV_01); /* Locality = 5 */ + RUN_CASE(UNIT_NR_IV_02); /* Locality = 2 */ + RUN_CASE(UNIT_NR_IV_03); /* UNDEF */ + RUN_CASE(UNIT_NR_IV_04); /* LCP_OWN, off 29 */ + RUN_CASE(UNIT_NR_IV_05); /* LCP_OWN, off 20, 20bytes */ + RUN_CASE(UNIT_NR_IV_06); /* SELFDEF, off 0, 755bytes */ +} + +void tpm_unit_test_after_senter(void) +{ + RUN_CASE(UNIT_PS_V_02 ); /* Pcr16 */ + RUN_CASE(UNIT_PR_V_03 ); /* Pcr16 */ + RUN_CASE(UNIT_PE_V_03 ); /* pcr16, out != NULL */ + RUN_CASE(UNIT_PR_V_04 ); /* Pcr16 */ + RUN_CASE(UNIT_PR_V_05 ); /* Pcr17 */ + RUN_CASE(UNIT_PE_V_04 ); /* Pcr17, out != NULL */ + RUN_CASE(UNIT_PR_V_06 ); /* Pcr18 */ + RUN_CASE(UNIT_PE_V_05 ); /* Pcr18, out != NULL */ + RUN_CASE(UNIT_PR_V_07 ); /* Pcr19 */ + RUN_CASE(UNIT_PE_V_06 ); /* Pcr19, out != NULL */ + RUN_CASE(UNIT_PR_V_08 ); /* Pcr20 */ + RUN_CASE(UNIT_PE_V_07 ); /* Pcr20, out != NULL */ + RUN_CASE(UNIT_PS_V_03 ); /* Pcr20 */ + RUN_CASE(UNIT_PE_IV_05); /* locality = 1 */ + RUN_CASE(UNIT_PR_IV_04); /* locality = 1 */ + RUN_CASE(UNIT_PS_IV_05); /* Pcr17, Locality = 2 */ + RUN_CASE(UNIT_NW_V_04); /* LCP_OWN, off 0, 20 bytes */ + RUN_CASE(UNIT_NR_V_04); /* LCP_OWN, off 0, 20 bytes */ + //RUN_CASE(UNIT_OS_V_01 ); /* TPM_ET_SRK */ + //RUN_CASE(UNIT_OI_V_01 ); /* loc = 0 */ + RUN_CASE(UNIT_HMAC_V_01);/* */ + RUN_CASE(test_tpm_wrap_seal);/* */ + RUN_CASE(UNIT_SL_V_05 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_04 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_IV_01); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_04 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_04 ); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_03 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_03 ); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_02 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_02 ); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_01 ); /* loc = 0 */ + RUN_CASE(UNIT_USL_V_01 ); /* loc = 0 */ +} + +#endif /* TPM_UNIT_TEST */ + /* * Local variables: * mode: C diff -r 950fec11ef90 tboot/include/tpm.h --- a/tboot/include/tpm.h Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/include/tpm.h Tue Apr 17 10:13:40 2012 +0800 @@ -272,7 +272,18 @@ extern uint32_t tpm_get_random(uint32_t extern uint32_t tpm_get_random(uint32_t locality, uint8_t *random_data, uint32_t *data_size); +#define TPM_UNIT_TEST 1 + +#ifdef TPM_UNIT_TEST +void tpm_unit_test_before_senter(void); +void tpm_unit_test_after_senter(void); +#else +#define tpm_unit_test_before_senter() +#define tpm_unit_test_after_senter() +#endif /* TPM_UNIT_TEST */ + #endif /* __TPM_H__ */ + /* * Local variables: diff -r 950fec11ef90 tboot/txt/txt.c --- a/tboot/txt/txt.c Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/txt/txt.c Tue Apr 17 10:13:40 2012 +0800 @@ -741,6 +741,8 @@ void txt_post_launch(void) write_priv_config_reg(TXTCR_ERRORCODE, 0x00000000); write_priv_config_reg(TXTCR_ESTS, 0xffffffff); /* write 1's to clear */ + tpm_unit_test_after_senter(); + /* bring RLPs into environment (do this before restoring MTRRs to ensure */ /* SINIT area is mapped WB for MONITOR-based RLP wakeup) */ txt_wakeup_cpus(); tboot-1.10.5/test-patches/vsprintf-test.patch0000644000000000000000000000411414210363175017332 0ustar 00000000000000--- tboot/common/vsprintf.c 2010-06-22 15:41:16.000000000 -0700 +++ tboot/common/test_vsprintf.c 2010-06-22 15:42:26.000000000 -0700 @@ -33,12 +33,13 @@ * */ -#include +/* unit test code, should test it on i386 arch */ +#include #include #include -#include -#include -#include +#include +#include +#include "../include/div64.h" /* * write the character into the buffer @@ -421,6 +422,58 @@ int snprintf(char *buf, size_t size, con return count; } +void myprintf(const char *fmt, ...) +{ + char buf[256]; + int n; + va_list ap; + int i; + + memset(buf, '\0', sizeof(buf)); + va_start(ap, fmt); + n = vscnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + /* print */ + for ( i = 0; i < n; i++ ) + printf("%c", buf[i]); +} + +int main(void) +{ + int nums[] = {-20000, -1, 0, 200, 0xFFFE, 0xFFFFFFFE}; + int i, j; + + for ( j = 0; j < sizeof(nums); j++ ) { + i = nums[j]; + + printf("%c,%s,%d,%o,%x,%X,%u,%p\n", 'a', "abc", i, i, i, i, i, &i); + myprintf("%c,%s,%d,%o,%x,%X,%u,%p\n", 'a', "abc", i, i, i, i, i, &i); + printf("%-+ 10.4d,%-+ 10.3u\n", i, i); + myprintf("%-+ 10.4d,%-+ 10.3u\n", i, i); + printf("%-+ 10d,%-+ 10u\n", i, i); + myprintf("%-+ 10d,%-+ 10u\n", i, i); + printf("%-+.3d,%-+.3u\n", i, i); + myprintf("%-+.3d,%-+.3u\n", i, i); + printf("%.3-+d,%.3-+u\n", i, i); + myprintf("%.3-+d,%.3-+u\n", i, i); + printf("%d.3-+,%d.3-+u\n", i, i); + myprintf("%d.3-+,%d.3-+u\n", i, i); + printf("%+0d,%+0d\n", -i, i); + myprintf("%+0d,%+0d\n", -i, i); + printf("%#o,%#x,%#X\n", i, i, i); + myprintf("%#o,%#x,%#X\n", i, i, i); + printf("%lld,%Ld,%Lld,%llld\n", i, i, i, i); + myprintf("%lld,%Ld,%Lld,%llld\n", i, i, i, i); + printf("%d,%d\n", i); + myprintf("%d,%d\n", i); + printf("%%%%%%%%%%\n"); + myprintf("%%%%%%%%%%\n"); + } + + return 0; +} + /* * Local variables: * mode: C tboot-1.10.5/txt-test/Kbuild0000644000000000000000000000002314210363175014001 0ustar 00000000000000obj-m = txt-test.o tboot-1.10.5/txt-test/Makefile0000644000000000000000000000144614210363175014316 0ustar 00000000000000# Copyright (c) 2006-2007, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # txt-test makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk LINUX_BASE_DIR = $(ROOTDIR)/../ LINUX_BUILD_DIR = $(LINUX_BASE_DIR)/build-linux-2.6.18-xen_$(TARGET_ARCH) LINUX_SRC_DIR = $(LINUX_BASE_DIR)/linux-2.6.18-xen.hg # uncomment to build test kernel module #MOD_TARGET := txt-test.ko # # universal targets # dist : install build : $(MOD_TARGET) install : build clean : rm -f $(MOD_TARGET) *~ *.o *.mod.* *.symvers distclean : clean # # dependencies # BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile $(MOD_TARGET) : $(BUILD_DEPS) txt-test.c $(MAKE) -C $(LINUX_BUILD_DIR) M=$(CURDIR) modules %.o : %.c $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.10.5/txt-test/txt-test.c0000644000000000000000000002061514210363175014615 0ustar 00000000000000/* * txt-test: Linux kernel module that will display various information about * the status of TXT. It also indicates whether the various TXT * memory regions are protected from access by the kernel. * * Copyright (c) 2006-2007, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include "../include/config.h" #include "../include/uuid.h" #include "../include/tboot.h" #include "../tboot/include/tpm.h" #include "../tboot/include/txt/config_regs.h" /* device name for Intel(r) TXT device we create */ #define DEVICE_NAME "txt" static struct file_operations fops; static int dev_major; #define TBOOT_MEM_BASE (TBOOT_START - 4*PAGE_SIZE) /* 0x8c000 is Xen's start of trampoline code */ #define TBOOT_MEM_SIZE (0x4f000 + 3*PAGE_SIZE) #define TXT_CONFIG_REGS_SIZE (NR_TXT_CONFIG_PAGES*PAGE_SIZE) #define TPM_LOCALITY_SIZE (NR_TPM_LOCALITY_PAGES*PAGE_SIZE) #define TPM_REG_ACCESS 0x00000000 static inline uint64_t read_txt_config_reg(void *config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(config_regs_base + reg); } static inline const char * bit_to_str(uint64_t b) { return b ? "TRUE" : "FALSE"; } static bool test_access_txt_priv_config(void) { void *ptr = NULL; printk("testing for access to TXT private config space...\n"); /* try to get pointer to TXT private config space */ ptr = (void *)ioremap_nocache(TXT_PRIV_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE); if ( ptr == NULL ) printk(KERN_ALERT "ERROR: ioremap_nocache for private space failed\n"); else { printk(KERN_ALERT "ioremap_nocache for private space succeeded\n"); iounmap(ptr); } return (ptr == NULL); #if 0 /* try using hypercall */ { struct xen_domctl domctl = { 0 }; privcmd_hypercall_t hypercall = { 0 }; int ret = -1; domctl.cmd = XEN_DOMCTL_iomem_permission; domctl.domain = DOMID_DOM0; domctl.u.iomem_permission.first_mfn = 0xfed20; domctl.u.iomem_permission.nr_mfns = 0x10; domctl.u.iomem_permission.allow_access = 1; domctl->interface_version = XEN_DOMCTL_INTERFACE_VERSION; hypercall.op = __HYPERVISOR_domctl; hypercall.arg[0] = (unsigned long)domctl; ret = ioctl(xc_handle, IOCTL_PRIVCMD_HYPERCALL, (unsigned long)hypercall); if ( ret < 0 ) printk(KERN_ALERT "\nERROR: failed to set iomem permissions\n"); else { if ((PrivatePtr = (void *)ioremap_nocache(0xFED20000, 0x1000)) == NULL) printk(KERN_ALERT "\nERROR: ioremap_nocache for private space failed\n\n"); else { printk(KERN_ALERT "ioremap_nocache for private space succeeded\n"); iounmap(PrivatePtr); } } } #endif } static bool test_access_tpm_localities(void) { int locality; void *base, *ptr=NULL; int access; printk("testing for access to TPM localities " "(ff = locality unavailable):\n"); for ( locality = 0; locality < TPM_NR_LOCALITIES; locality++ ) { base = (void *)(unsigned long)TPM_LOCALITY_BASE_N(locality); ptr = (void *)ioremap_nocache((unsigned long)base, TPM_LOCALITY_SIZE); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for TPM locality %d failed\n", locality); return false; } access = readb(ptr + TPM_REG_ACCESS); printk(KERN_ALERT "TPM: Locality %d access = %x\n", locality, access); iounmap(ptr); } return true; } static bool test_access_txt_heap(void) { void *txt_pub, *ptr; uint64_t base, size; printk("testing for access to SINIT and TXT heap memory...\n"); /* get pointer to TXT public config space */ txt_pub = (void *)ioremap_nocache(TXT_PUB_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE); if ( txt_pub == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for public space failed\n"); return false; } /* SINIT */ base = read_txt_config_reg(txt_pub, TXTCR_SINIT_BASE); size = read_txt_config_reg(txt_pub, TXTCR_SINIT_SIZE); ptr = (void *)ioremap_nocache(base, size); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for SINIT failed\n"); } else { printk(KERN_ALERT "ioremap_nocache for SINIT succeeded\n"); iounmap(txt_pub); iounmap(ptr); return false; } /* TXT heap */ base = read_txt_config_reg(txt_pub, TXTCR_HEAP_BASE); size = read_txt_config_reg(txt_pub, TXTCR_HEAP_SIZE); ptr = (void *)ioremap_nocache(base, size); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for TXT heap failed\n"); iounmap(txt_pub); return true; } else { printk(KERN_ALERT "ioremap_nocache for TXT heap succeeded\n"); iounmap(txt_pub); iounmap(ptr); return false; } } static bool test_access_tboot(void) { void *ptr; printk("testing for access to tboot memory...\n"); ptr = (void *)ioremap_nocache(TBOOT_MEM_BASE, TBOOT_MEM_SIZE); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for tboot failed\n"); return true; } else { printk(KERN_ALERT "ioremap_nocache for tboot succeeded\n"); iounmap(ptr); return false; } } static bool is_txt_supported(void) { return true; } static __init int mod_init(void) { if ( !is_txt_supported() ) { printk(KERN_ALERT "Intel(r) TXT is not supported\n"); return 0; } /* make sure no one else has grabbed the public config space */ if ( check_mem_region(TXT_PUB_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE) ) { printk(KERN_ALERT "ERROR: TXT public config space is already reserved\n"); return -EBUSY; } /* register a TXT device (let kernel pick major #) */ dev_major = register_chrdev(0, DEVICE_NAME, &fops); if ( dev_major < 0 ) { printk (KERN_ALERT "ERROR: failed to create TXT device (%d)\n", dev_major); return 0; } /* * begin tests */ test_access_txt_priv_config(); test_access_tpm_localities(); test_access_txt_heap(); test_access_tboot(); unregister_chrdev(dev_major, DEVICE_NAME); return 0; } static __exit void mod_exit(void) { printk("txt-test module unloading\n"); } module_init(mod_init); module_exit(mod_exit); MODULE_LICENSE("BSD"); /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/uml/launch.plantuml0000644000000000000000000000206714210363175014707 0ustar 00000000000000@startuml Launch start :parse command line; if (load SINIT) then (false) -[#red]-> stop endif if (detect TPM) then (false) -[#red]-> stop endif :check SE_SVN; :read VLP; if (platform TXT capable?) then (no) -[#red]-> stop endif if (post-SINIT launch?) then (yes) :handle post-launch; if (S3 wakeup) then (yes) :verify integrity; :relinquish locality 2; :jump to kernel\nresume vecor; stop else (no) :protect memory; :verify modules against VLP; if (TPM1.2?) then (yes) :verify NV against VLP; else (no) endif :init MLE/kernel shared page; :relinquish locality 2; :launch kernel; stop endif else (no) :prepare CPU; :relinquish locality 0; if (S3 wakeup) then (no) :build MLE pagetable; :configure VTd; :set loader to MLE struct; :set loader to SINIT struct; else (yes) endif :init event log; :save & set MTRRs; :call GETSEC[SENTER]; stop endif @endumltboot-1.10.5/uml/load_sinit.plantuml0000644000000000000000000000071214210363175015555 0ustar 00000000000000@startuml load SINIT start if (already loaded?) then (yes) stop endif if (SINIT in MBI? && match platform?) then (yes) :load SINIT from MBI; endif if (SINIT in BIOS? && match platform?) then (yes) if (BIOS SINIT newer than MBI?) then (yes) :use BIOS SINIT; stop endif endif if (SINIT was loaded?) then (yes) :copy MBI SINIT to SINIT region; :use MBI SINIT; stop else (no) :no SINIT; stop endif @endumltboot-1.10.5/uml/prepare_cpu.plantuml0000644000000000000000000000032714210363175015737 0ustar 00000000000000@startuml prepare CPU start :verify if CPU in protected mode; :check & enable cache; :check & enable native FPU error reporting; :check & exit virtual-8086 mode; :check if no machine check in progress; stop @enduml tboot-1.10.5/uml/shutdown.plantuml0000644000000000000000000000102614210363175015302 0ustar 00000000000000@startuml Shutdown start if (CPU is AP?) then (true) :catch CPU in VMX; stop else (false) :wait until all APs in VMX/ :release locality 0 and 1; :request locality 2; if (S3 enter flow?) then (yes) :restore DMAR table; :seal state into TPM; endif :cap PCRs; :force APs to exit VMX; :prepare & call GETSEC[SEXIT]; if (S3 enter flow?) then (yes) :set resume entry; :enter S3; stop; else (no) :shutdown; stop endif endif @enduml tboot-1.10.5/utils/Makefile0000644000000000000000000000216114210363175013655 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # utils makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TARGETS := txt-stat txt-parse_err txt-acminfo CFLAGS += -D_LARGEFILE64_SOURCE LIBS += $(ROOTDIR)/safestringlib/libsafestring.a # # universal targets # build : $(TARGETS) dist : install install : @set -e; for i in $(TARGETS);\ do \ $(MAKE) DISTDIR=$(DISTDIR) INST_TARGET=$(DISTDIR)/usr/sbin/$$i do_install; \ done .PHONY: do_install do_install : $(INST_TARGET) $(INST_TARGET) : $(notdir $(INST_TARGET)) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $^ clean : rm -f $(TARGETS) *~ *.o *.mod.* *.symvers distclean : clean # # dependencies # BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile txt-stat : txt-stat.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ txt-parse_err : txt-parse_err.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ txt-acminfo : txt-acminfo.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ %.o : %.c $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.10.5/utils/txt-acminfo.c0000644000000000000000000001615714210363175014624 0ustar 00000000000000/* * acminfo.c: Linux app that will display header information for a TXT * Authenticated Code Module (ACM) and match it with the current * system * * Copyright (c) 2006-2011, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include typedef uint8_t mtrr_state_t; typedef uint8_t multiboot_info_t; #define printk printf #include "../include/config.h" #include "../include/uuid.h" #include "../include/mle.h" #include "../include/hash.h" #include "../tboot/include/compiler.h" #include "../tboot/include/processor.h" #include "../tboot/include/misc.h" #include "../tboot/include/io.h" #include "../tboot/include/txt/acmod.h" #include "../tboot/include/txt/config_regs.h" #include "../tboot/include/txt/heap.h" /* override of fn. that will be called by verify_acmod() */ typedef struct { uint32_t acm_max_size; } getsec_parameters_t; static bool get_parameters(getsec_parameters_t *params) { params->acm_max_size = 0x8000; return true; } static unsigned long long rdmsr(unsigned int msr) { unsigned long long val = 0; /* read MSRs in userspace by reading /dev/cpu/0/msr file */ int fd = open("/dev/cpu/0/msr", O_RDONLY); if ( fd == -1 ) { printf("Error: failed to open /dev/cpu/0/msr\n"); printf("Perhaps you should modprobe msr?\n"); exit(1); } /* lseek() to MSR # */ if ( lseek(fd, msr, SEEK_SET) == (off_t)-1 ) { printf("Error: failed to find MSR 0x%x\n", msr); exit(1); } else { if ( read(fd, &val, sizeof(val)) != sizeof(val) ) { printf("Error: failed to read MSR 0x%x value\n", msr); exit(1); } } close(fd); return val; } #define MSR_IA32_PLATFORM_ID 0x17 #define MSR_IA32_SE_SVN_STATUS 0x500 static void *pub_config_base; #define read_pub_config_reg(reg) *(volatile uint64_t *)(pub_config_base + \ reg); #define MIN_OS_SINIT_DATA_VER 4 #define IS_INCLUDED /* prevent acmod.c #include */ #include "../tboot/txt/acmod.c" static void *load_acm(const char *file_name, size_t *size) { int fd; struct stat sb; void *addr; fd = open(file_name, O_RDONLY); if ( fd == -1 ) { printf("Error: failed to open file %s\n", file_name); return NULL; } if ( fstat(fd, &sb) == -1 ) { printf("Error: failed to get file length\n"); close(fd); return NULL; } addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if ( addr == NULL ) { printf("Error: failed to map file %s of size %lu\n", file_name, sb.st_size); close(fd); return NULL; } if ( size != NULL ) *size = sb.st_size; close(fd); return addr; } void print_hex(const char* prefix, const void *start, size_t len) { const void *end = start + len; while ( start < end ) { printf("%s", prefix); for ( int i = 0; i < 16; i++ ) { if ( start < end ) printf("%02x ", *(uint8_t *)start); start++; } printf("\n"); } } static bool display_acm(void *acm_addr, size_t size, const char *file_name) { if ( !is_acmod(acm_addr, size, NULL, false) ) return false; acm_hdr_t *hdr = (acm_hdr_t *)acm_addr; print_acm_hdr(hdr, file_name); /* display signature info */ printf("signature information:\n"); printf("\t key size*4: 0x%x (%u)\n", hdr->key_size, hdr->key_size); printf("\t RSA public key:\n"); print_hex("\t ", hdr->rsa2048_pubkey, hdr->key_size*4); printf("\t RSA public key exponent: 0x%08x\n", hdr->pub_exp); printf("\t PKCS #1.5 RSA signature:\n"); print_hex("\t ", hdr->rsa2048_sig, 256); return true; } static bool is_txt_supported(void) { return true; } static bool match_platform(acm_hdr_t *hdr) { if ( !is_txt_supported() ) { printf("Intel(r) TXT is not supported\n"); return false; } int fd_mem = open("/dev/mem", O_RDONLY); if ( fd_mem == -1 ) { printf("ERROR: cannot open /dev/mem\n"); return false; } pub_config_base = mmap(NULL, TXT_CONFIG_REGS_SIZE, PROT_READ, MAP_PRIVATE, fd_mem, TXT_PUB_CONFIG_REGS_BASE); if ( pub_config_base == MAP_FAILED ) { printf("ERROR: cannot map config regs by mmap()\n"); close(fd_mem); return false; } else { if ( does_acmod_match_platform(hdr) ) printf("ACM matches platform\n"); else printf("ACM does not match platform\n"); munmap(pub_config_base, TXT_CONFIG_REGS_SIZE); } close(fd_mem); return true; } int main(int argc, char *argv[]) { void *acm_mem = NULL; char *acm_file; size_t size; bool valid; if ( argc != 2 ) { printf("usage: %s acm_file_name\n", argv[0]); return 1; } acm_file = argv[1]; /* load ACM file into memory */ acm_mem = load_acm(acm_file, &size); if ( acm_mem == NULL ) { printf("Error: failed to read ACM %s\n", acm_file); return 1; } /* display the ACM info */ valid = display_acm(acm_mem, size, acm_file); if ( valid ) match_platform((acm_hdr_t *)acm_mem); /* this allows us to use dump-acm return code to indicate valid ACM */ return valid ? 0 : 1; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/utils/txt-parse_err.c0000644000000000000000000001133514210363175015163 0ustar 00000000000000/* * parse_err.c: Linux app that will parse a TXT.ERRORCODE value * * Copyright (c) 2010-2011, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #define printk printf #include "../tboot/include/txt/config_regs.h" #include "../tboot/include/txt/errorcode.h" static inline uint64_t read_txt_config_reg(void *config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(config_regs_base + reg); } int main(int argc, char *argv[]) { txt_errorcode_t err; if ( argc > 2 ) { printf("usage: %s []\n", argv[0]); return 1; } if ( argc == 2 ) { err._raw = strtoul(argv[1], NULL, 0); if ( errno != 0 ) { printf("Error: TXT.ERRORCODE value is not a valid number\n"); return 1; } } else { int fd_mem = open("/dev/mem", O_RDONLY); if ( fd_mem == -1 ) { printf("ERROR: cannot open /dev/mem\n"); return 1; } void *txt_pub = mmap(NULL, TXT_CONFIG_REGS_SIZE, PROT_READ, MAP_PRIVATE, fd_mem, TXT_PUB_CONFIG_REGS_BASE); if ( txt_pub == MAP_FAILED ) { printf("ERROR: cannot map config regs\n"); close(fd_mem); return 1; } err._raw = read_txt_config_reg(txt_pub, TXTCR_ERRORCODE); munmap(txt_pub, TXT_CONFIG_REGS_SIZE); close(fd_mem); } printf("ERRORCODE: 0x%08jx\n", err._raw); /* AC module error (don't know how to parse other errors) */ if ( err.valid ) { if ( err.external == 0 ) /* processor error */ printk("\t processor error 0x%x\n", (uint32_t)err.type); else { /* external SW error */ txt_errorcode_sw_t sw_err; sw_err._raw = err.type; if ( sw_err.src == 1 ) /* unknown SW error */ printk("unknown SW error 0x%x:0x%x\n", sw_err.err1, sw_err.err2); else { /* ACM error */ acmod_error_t acmod_err; acmod_err._raw = sw_err._raw; printk("AC module error : acm_type=0x%x, progress=0x%02x, " "error=0x%x\n", acmod_err.acm_type, acmod_err.progress, acmod_err.error); /* error = 0x0a, progress = 0x0d => TPM error */ if ( acmod_err.error == 0x0a && acmod_err.progress == 0x0d ) printk("TPM error code = 0x%x\n", acmod_err.tpm_err); /* progress = 0x10 => LCP2 error */ else if ( acmod_err.progress == 0x10 && acmod_err.lcp_minor != 0 ) printk("LCP2 error: minor error = 0x%x, index = %u\n", acmod_err.lcp_minor, acmod_err.lcp_index); } } } else printk("no error\n"); return 0; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.10.5/utils/txt-stat.c0000644000000000000000000003542014210363175014155 0ustar 00000000000000/* * txt-stat: Linux app that will display various information about * the status of TXT. * * Copyright (c) 2006-2011, Intel Corporation * 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 Intel Corporation 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 OWNER 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define printk printf #include "../include/config.h" #include "../include/uuid.h" #include "../include/tboot.h" #define IS_INCLUDED /* disable some codes in included files */ static inline uint64_t read_config_reg(uint32_t config_regs_base, uint32_t reg); #include "../tboot/include/txt/config_regs.h" typedef uint8_t mtrr_state_t; typedef uint8_t txt_caps_t; typedef uint8_t multiboot_info_t; void print_hex(const char* prefix, const void *start, size_t len); #include "../include/hash.h" #include "../tboot/include/txt/heap.h" #include "../tboot/txt/heap.c" #include "../tboot/include/lz.h" #include "../tboot/common/lz.c" static inline uint64_t read_txt_config_reg(void *config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(config_regs_base + reg); } static inline const char * bit_to_str(uint64_t b) { return b ? "TRUE" : "FALSE"; } void print_hex(const char* prefix, const void *start, size_t len) { const void *end = start + len; while ( start < end ) { printf("%s", prefix); for ( int i = 0; i < 16; i++ ) { if ( start < end ) printf("%02x ", *(uint8_t *)start); start++; } printf("\n"); } } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { printk("NULL"); return; } if ( hash_alg == TB_HALG_SHA1 ) print_hex(NULL, (uint8_t *)hash->sha1, sizeof(hash->sha1)); else { printk("unsupported hash alg (%u)\n", hash_alg); return; } } void print_help(const char *usage_str, const char *option_string[]) { uint16_t i = 0; if ( usage_str == NULL || option_string == NULL ) return; printf("\nUsage: %s\n", usage_str); for ( ; option_string[i] != NULL; i++ ) printf("%s", option_string[i]); } static void display_config_regs(void *txt_config_base) { printf("Intel(r) TXT Configuration Registers:\n"); /* STS */ txt_sts_t sts; sts._raw = read_txt_config_reg(txt_config_base, TXTCR_STS); printf("\tSTS: 0x%08jx\n", sts._raw); printf("\t senter_done: %s\n", bit_to_str(sts.senter_done_sts)); printf("\t sexit_done: %s\n", bit_to_str(sts.sexit_done_sts)); printf("\t mem_config_lock: %s\n", bit_to_str(sts.mem_config_lock_sts)); printf("\t private_open: %s\n", bit_to_str(sts.private_open_sts)); printf("\t locality_1_open: %s\n", bit_to_str(sts.locality_1_open_sts)); printf("\t locality_2_open: %s\n", bit_to_str(sts.locality_2_open_sts)); /* ESTS */ txt_ests_t ests; ests._raw = read_txt_config_reg(txt_config_base, TXTCR_ESTS); printf("\tESTS: 0x%02jx\n", ests._raw); printf("\t txt_reset: %s\n", bit_to_str(ests.txt_reset_sts)); /* E2STS */ txt_e2sts_t e2sts; e2sts._raw = read_txt_config_reg(txt_config_base, TXTCR_E2STS); printf("\tE2STS: 0x%016jx\n", e2sts._raw); printf("\t secrets: %s\n", bit_to_str(e2sts.secrets_sts)); /* ERRORCODE */ printf("\tERRORCODE: 0x%08jx\n", read_txt_config_reg(txt_config_base, TXTCR_ERRORCODE)); /* DIDVID */ txt_didvid_t didvid; didvid._raw = read_txt_config_reg(txt_config_base, TXTCR_DIDVID); printf("\tDIDVID: 0x%016jx\n", didvid._raw); printf("\t vendor_id: 0x%x\n", didvid.vendor_id); printf("\t device_id: 0x%x\n", didvid.device_id); printf("\t revision_id: 0x%x\n", didvid.revision_id); /* FSBIF */ uint64_t fsbif; fsbif = read_txt_config_reg(txt_config_base, TXTCR_VER_FSBIF); printf("\tFSBIF: 0x%016jx\n", fsbif); /* QPIIF */ uint64_t qpiif; qpiif = read_txt_config_reg(txt_config_base, TXTCR_VER_QPIIF); printf("\tQPIIF: 0x%016jx\n", qpiif); /* SINIT.BASE/SIZE */ printf("\tSINIT.BASE: 0x%08jx\n", read_txt_config_reg(txt_config_base, TXTCR_SINIT_BASE)); printf("\tSINIT.SIZE: %juB (0x%jx)\n", read_txt_config_reg(txt_config_base, TXTCR_SINIT_SIZE), read_txt_config_reg(txt_config_base, TXTCR_SINIT_SIZE)); /* HEAP.BASE/SIZE */ printf("\tHEAP.BASE: 0x%08jx\n", read_txt_config_reg(txt_config_base, TXTCR_HEAP_BASE)); printf("\tHEAP.SIZE: %juB (0x%jx)\n", read_txt_config_reg(txt_config_base, TXTCR_HEAP_SIZE), read_txt_config_reg(txt_config_base, TXTCR_HEAP_SIZE)); /* DPR.BASE/SIZE */ txt_dpr_t dpr; dpr._raw = read_txt_config_reg(txt_config_base, TXTCR_DPR); printf("\tDPR: 0x%016jx\n", dpr._raw); printf("\t lock: %s\n", bit_to_str(dpr.lock)); printf("\t top: 0x%08x\n", (uint32_t)dpr.top << 20); printf("\t size: %uMB (%uB)\n", dpr.size, dpr.size*1024*1024); /* PUBLIC.KEY */ uint8_t key[256/8]; unsigned int i = 0; do { *(uint64_t *)&key[i] = read_txt_config_reg(txt_config_base, TXTCR_PUBLIC_KEY + i); i += sizeof(uint64_t); } while ( i < sizeof(key) ); printf("\tPUBLIC.KEY:\n"); print_hex("\t ", key, sizeof(key)); printf("\n"); /* easy-to-see status of TXT and secrets */ printf("***********************************************************\n"); printf("\t TXT measured launch: %s\n", bit_to_str(sts.senter_done_sts)); printf("\t secrets flag set: %s\n", bit_to_str(e2sts.secrets_sts)); printf("***********************************************************\n"); } static void display_heap(txt_heap_t *heap) { uint64_t size = get_bios_data_size(heap); bios_data_t *bios_data = get_bios_data_start(heap); print_bios_data(bios_data, size); } static void display_tboot_log(void *log_base) { static char buf[512]; char pbuf[32*1024]; char *out = pbuf; tboot_log_t *log = (tboot_log_t *)log_base; char *log_buf = log->buf; uint8_t i = 0; if ( !are_uuids_equal(&(log->uuid), &((uuid_t)TBOOT_LOG_UUID)) ) { printf("unable to find TBOOT log\n"); return; } printf("TBOOT log:\n"); printf("\t max_size=%d\n", log->max_size); printf("\t zip_count=%d\n", log->zip_count); while ( i < log->zip_count) { printf("\t zip_pos[%d] = %d\n", i, log->zip_pos[i]); printf("\t zip_size[%d] = %d\n", i, log->zip_size[i]); i++; } printf("\t curr_pos=%d\n", log->curr_pos); printf("\t buf:\n"); /* log->buf is phys addr of buf, which will not match where mmap has */ /* map'ed us, but since it is always just past end of struct, use that */ /* to uncompress tboot log */ if (log->zip_count > 0) { for ( i = 0; i< log->zip_count; i++) { int length = LZ_Uncompress(&log_buf[log->zip_pos[i]], out, log->zip_size[i], sizeof(pbuf)); if ( length < 0 ) continue; /* log is too big for single printk(), so break it up */ /* print out the uncompressed log */ for ( int curr_pos = 0; curr_pos < length; curr_pos += sizeof(buf)-1 ) { if ( length - curr_pos >= (int)sizeof(buf) - 1 ) { strncpy_s(buf, sizeof(buf), out + curr_pos, sizeof(buf)-1); } else { strncpy_s(buf, sizeof(buf), out + curr_pos, length - curr_pos); } printf("%s", buf); } } } for ( unsigned int curr_pos = log->zip_pos[log->zip_count]; curr_pos < log->curr_pos; curr_pos += sizeof(buf)-1 ) { strncpy_s(buf, sizeof(buf), log_buf + curr_pos, sizeof(buf)-1); printf("%s", buf); } printf("\n"); } static bool is_txt_supported(void) { return true; } static int fd_mem; static void *buf_config_regs_read; static void *buf_config_regs_mmap; static inline uint64_t read_config_reg(uint32_t config_regs_base, uint32_t reg) { uint64_t reg_val; void *buf; (void)config_regs_base; buf = buf_config_regs_read; if ( buf == NULL ) buf = buf_config_regs_mmap; if ( buf == NULL ) return 0; reg_val = read_txt_config_reg(buf, reg); return reg_val; } bool display_heap_optin = false; static const char *short_option = "h"; static struct option longopts[] = { {"heap", 0, 0, 'p'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; static const char *usage_string = "txt-stat [--heap] [-h]"; static const char *option_strings[] = { "--heap:\t\tprint out heap info.\n", "-h, --help:\tprint out this help message.\n", NULL }; int main(int argc, char *argv[]) { uint64_t heap = 0; uint64_t heap_size = 0; void *buf = NULL; off_t seek_ret = -1; size_t read_ret = 0; int c; while ( (c = getopt_long(argc, (char **const)argv, short_option, longopts, NULL)) != -1 ) switch ( c ) { case 'h': print_help(usage_string, option_strings); return 0; case 'p': display_heap_optin = true; break; default: return 1; } if ( !is_txt_supported() ) { printf("Intel(r) TXT is not supported\n"); return 1; } fd_mem = open("/dev/mem", O_RDONLY); if ( fd_mem == -1 ) { printf("ERROR: cannot open /dev/mem\n"); return 1; } /* * display public config regs */ seek_ret = lseek(fd_mem, TXT_PUB_CONFIG_REGS_BASE, SEEK_SET); if ( seek_ret == -1 ) printf("ERROR: seeking public config registers failed: %s, try mmap\n", strerror(errno)); else { buf = malloc(TXT_CONFIG_REGS_SIZE); if ( buf == NULL ) printf("ERROR: out of memory, try mmap\n"); else { read_ret = read(fd_mem, buf, TXT_CONFIG_REGS_SIZE); if ( read_ret != TXT_CONFIG_REGS_SIZE ) { printf("ERROR: reading public config registers failed: %s," "try mmap\n", strerror(errno)); free(buf); buf = NULL; } else buf_config_regs_read = buf; } } /* * try mmap to display public config regs, * since public config regs should be displayed always. */ if ( buf == NULL ) { buf = mmap(NULL, TXT_CONFIG_REGS_SIZE, PROT_READ, MAP_PRIVATE, fd_mem, TXT_PUB_CONFIG_REGS_BASE); if ( buf == MAP_FAILED ) { printf("ERROR: cannot map config regs by mmap()\n"); buf = NULL; } else buf_config_regs_mmap = buf; } if ( buf ) { display_config_regs(buf); heap = read_txt_config_reg(buf, TXTCR_HEAP_BASE); heap_size = read_txt_config_reg(buf, TXTCR_HEAP_SIZE); } /* * display heap */ if ( heap && heap_size && display_heap_optin ) { seek_ret = lseek(fd_mem, heap, SEEK_SET); if ( seek_ret == -1 ) { printf("ERROR: seeking TXT heap failed by lseek(): %s, try mmap\n", strerror(errno)); goto try_mmap_heap; } buf = malloc(heap_size); if ( buf == NULL ) { printf("ERROR: out of memory, try mmap\n"); goto try_mmap_heap; } read_ret = read(fd_mem, buf, heap_size); if ( read_ret != heap_size ) { printf("ERROR: reading TXT heap failed by read(): %s, try mmap\n", strerror(errno)); free(buf); goto try_mmap_heap; } display_heap((txt_heap_t *)buf); free(buf); goto try_display_log; try_mmap_heap: buf = mmap(NULL, heap_size, PROT_READ, MAP_PRIVATE, fd_mem, heap); if ( buf == MAP_FAILED ) printf("ERROR: cannot map TXT heap by mmap()\n"); else { display_heap((txt_heap_t *)buf); munmap(buf, heap_size); } } try_display_log: if ( buf_config_regs_read ) free(buf_config_regs_read); if ( buf_config_regs_mmap ) munmap(buf_config_regs_mmap, TXT_CONFIG_REGS_SIZE); /* * display serial log from tboot memory (if exists) */ seek_ret = lseek(fd_mem, TBOOT_SERIAL_LOG_ADDR, SEEK_SET); if ( seek_ret == -1 ) { printf("ERROR: seeking TBOOT log failed by lseek()\n"); close(fd_mem); return 1; } buf = malloc(TBOOT_SERIAL_LOG_SIZE); if ( buf == NULL ) { printf("ERROR: out of memory\n"); close(fd_mem); return 1; } read_ret = read(fd_mem, buf, TBOOT_SERIAL_LOG_SIZE); if ( read_ret != TBOOT_SERIAL_LOG_SIZE ) { printf("ERROR: reading TBOOT log failed by read()\n"); free(buf); close(fd_mem); return 1; } display_tboot_log(buf); free(buf); close(fd_mem); return 0; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */