tboot-1.8.2/0000755000175000017500000000000012365404267011066 5ustar rqwrqwtboot-1.8.2/tb_polgen/0000755000175000017500000000000012365404265013035 5ustar rqwrqwtboot-1.8.2/tb_polgen/param.c0000644000175000017500000003756512365404265014321 0ustar rqwrqw/* * 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 #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", " [--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'}, {"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 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 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)strlen(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 ( strlen(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->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 ( strlen(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 && strlen(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 && strlen(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 ( strlen(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 ( strlen(params->policy_file) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( strlen(params->elt_file) == 0 ) { msg = "Missing elt file\n"; goto error; } return true; case POLGEN_CMD_SHOW: if ( strlen(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->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: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 '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("Misssing filename for --image option\n"); return false; } strncpy(params->image_file, optarg, sizeof(params->image_file)); params->image_file[sizeof(params->image_file)-1] = '\0'; break; case 'l': /* --cmdline */ if ( optarg == NULL ) { error_msg("Misssing string for --cmdline option\n"); return false; } if (strlen(optarg) > sizeof(params->cmdline) - 1) { error_msg("Command line length of %lu exceeds %d " "character maximum\n", (unsigned long int)strlen(optarg), TBOOT_KERNEL_CMDLINE_SIZE-1); return false; } strncpy(params->cmdline, optarg, sizeof(params->cmdline)); params->cmdline[sizeof(params->cmdline)-1] = '\0'; break; case 'e': /* --elt */ if ( optarg == NULL ) { error_msg("Missing filename for --elt option\n"); return false; } strncpy(params->elt_file, optarg, sizeof(params->elt_file)); params->elt_file[sizeof(params->elt_file)-1] = '\0'; break; default: break; } } /* last argument is policy file */ if ( optind >= argc ){ error_msg("Missing filename for policy file\n"); return false; } strncpy(params->policy_file, argv[optind], sizeof(params->policy_file)); params->policy_file[sizeof(params->policy_file)-1] = '\0'; 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.8.2/tb_polgen/commands.c0000644000175000017500000002300612365404265015003 0ustar rqwrqw/* * commands.c: handlers for commands * * 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/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) { FILE *f; static char buf[1024]; EVP_MD_CTX ctx; const EVP_MD *md; 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; } md = EVP_sha1(); 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->sha1, NULL); if ( unzip ) gzclose((gzFile)f); else fclose(f); 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); else 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 ) { EVP_MD_CTX ctx; const EVP_MD *md; tb_hash_t final_hash, hash; /* hash command line */ info_msg("hashing command line \"%s\"...\n", params->cmdline); md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, (unsigned char *)params->cmdline, strlen(params->cmdline)); EVP_DigestFinal(&ctx, (unsigned char *)&final_hash, NULL); if ( verbose ) { info_msg("hash is..."); print_hash(&final_hash, TB_HALG_SHA1); } /* hash file */ info_msg("hashing image file %s...\n", params->image_file); if ( !hash_file(params->image_file, true, &hash) ) return false; if ( verbose ) { info_msg("hash is..."); print_hash(&hash, TB_HALG_SHA1); } if ( !extend_hash(&final_hash, &hash, TB_HALG_SHA1) ) return false; if ( verbose ) { info_msg("cummulative hash is..."); print_hash(&final_hash, TB_HALG_SHA1); } 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(g_policy, 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.8.2/tb_polgen/tb_polgen.c0000644000175000017500000000553112365404265015156 0ustar rqwrqw/* * 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.8.2/tb_polgen/policy.c0000644000175000017500000001707612365404265014513 0ustar rqwrqw/* * 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 #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); 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(_policy_buf, 0, sizeof(_policy_buf)); 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) { /* current version is 2 */ g_policy->version = 2; g_policy->hash_alg = TB_HALG_SHA1; 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(entry_end + hash_size, 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(start, 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(start, 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.8.2/tb_polgen/hash.c0000644000175000017500000001147012365404265014127 0ustar rqwrqw/* * 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 #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) { if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) { error_msg("Error: hash pointer is zero.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) return (memcmp(hash1, hash2, SHA1_LENGTH) == 0); else { 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; } if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha1, NULL); return true; } else { error_msg("unsupported hash alg (%d)\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*sizeof(tb_hash_t)]; if ( hash1 == NULL || hash2 == NULL ) { error_msg("Error: There is no space for output hash.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX ctx; const EVP_MD *md; memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); memcpy(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); return true; } else { error_msg("unsupported hash alg (%d)\n", hash_alg); return false; } } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { error_msg("NULL"); return; } if ( hash_alg == TB_HALG_SHA1 ) { for ( unsigned int i = 0; i < sizeof(hash->sha1); i++ ) printf("%02x ", hash->sha1[i]); printf("\n"); } else { error_msg("unsupported hash alg (%d)\n", hash_alg); return; } } 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; } if ( hash_alg == TB_HALG_SHA1 ) memcpy(dest_hash, src_hash, SHA1_LENGTH); else 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.8.2/tb_polgen/Makefile0000644000175000017500000000166312365404265014503 0ustar rqwrqw# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tb_polgen makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TARGET = tb_polgen # libraries LIBS += -lcrypto -lz # # universal rules # build : $(TARGET) dist : install install : $(DISTDIR)/usr/sbin/$(TARGET) $(DISTDIR)/usr/sbin/$(TARGET) : $(TARGET) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $(TARGET) clean : rm -f *~ *.a *.so *.o *.rpm $(DEP_FILES) $(TARGET) mrproper : clean distclean : clean # # dependencies # $(TARGET) : tb_polgen.o commands.o policy.o param.o hash.o $(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.8.2/tb_polgen/tb_polgen.h0000644000175000017500000000752412365404265015167 0ustar rqwrqw/* * 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; 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); 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.8.2/lcptools-v2/0000755000175000017500000000000012365404264013247 5ustar rqwrqwtboot-1.8.2/lcptools-v2/polelt.c0000644000175000017500000000744512365404264014724 0ustar rqwrqw/* * 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 #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[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", 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.8.2/lcptools-v2/stm_elt.c0000644000175000017500000001155112365404264015065 0ustar rqwrqw/* * 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 #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(elt, 0, sizeof(*elt) + data_size); 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(hash, &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 = { "mle", opts, " mle\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.8.2/lcptools-v2/pollist1.c0000644000175000017500000003322012365404264015162 0ustar rqwrqw/* * 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 #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 "pollist1.h" #include "polelt.h" #include "lcputils.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_DEFAULT_POLICY_LIST_VERSION || MAJOR_VER(pollist->version) != MAJOR_VER(LCP_DEFAULT_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: %s\n", prefix, 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[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", 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); if ( verify_tpm12_pollist_sig(pollist) ) DISPLAY("%s signature verifies\n", prefix); else DISPLAY("%s signature fails to verify\n", prefix); } } 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((void *)&new_pollist->policy_elements + elt->size, &new_pollist->policy_elements, old_size - offsetof(lcp_policy_list_t, policy_elements)); memcpy(&new_pollist->policy_elements, 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(elt, (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) { lcp_signature_t *sig = get_tpm12_signature(pollist); if ( sig == NULL ) return true; return verify_signature((const unsigned char *)pollist, get_tpm12_policy_list_size(pollist) - sig->pubkey_size, sig->pubkey_value, sig->pubkey_size, get_tpm12_sig_block(pollist), true); } void display_tpm12_signature(const char *prefix, const lcp_signature_t *sig, bool brief) { char new_prefix[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s\t", prefix); 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((void *)new_pollist + sig_begin, 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); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools-v2/mle_elt.c0000644000175000017500000001250612365404264015040 0ustar rqwrqw/* * 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 #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(elt, 0, sizeof(*elt) + data_size); 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(hash, &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 = { "mle", opts, " mle\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.8.2/lcptools-v2/crtpolelt.c0000644000175000017500000002105512365404264015426 0ustar rqwrqw/* * 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 #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 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" "types :\n"; bool verbose = false; #define MAX_CMDLINE_OPTS 256 static struct option long_opts[MAX_CMDLINE_OPTS] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"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 */ strncat(help, plugin->help_txt, MAX_HELP_TEXT - strlen(help) - 1); } } 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 */ 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 ouput 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; } 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.8.2/lcptools-v2/mlehash.c0000644000175000017500000003364512365404264015047 0ustar rqwrqw/* * 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 #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp3.h" #include "lcputils.h" #include "../include/elf_defns.h" #include "../include/mle.h" #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"; bool verbose = false; char alg_name[32] = "sha1"; uint16_t alg_type = TPM_ALG_SHA1; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"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(base, (void *)elf + ph->p_offset, ph->p_filesz); memset(base + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz); 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 ) { LOG(": succeeded!\n"); /* uncompression succeeded */ fseek(fdecompressed, 0, SEEK_SET); } else { LOG(": failed!\n"); goto error; } /* read file into buffer */ LOG("reading the decompressed file ... "); *buffer = malloc(*length); if ( *buffer == NULL ) goto error; memset(*buffer, 0, *length); if ( fread(*buffer, 1, *length, fdecompressed) != *length ) goto error; fclose(fdecompressed); LOG(": succeeded!\n"); return true; error: LOG(": failed!\n"); if ( fcompressed ) gzclose(fcompressed); if ( fdecompressed ) fclose(fdecompressed); free(*buffer); 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; unsigned int i = 0; 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': 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(strlen(optarg) + 1); if ( cmdline == NULL ) { printf("Out of memory\n"); return 1; } strlcpy(cmdline, optarg, sizeof(cmdline)); 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("Unknonw 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 ouput 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(exp_start + mle_hdr->cmdline_start_off, '\0', mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off); strncpy(exp_start + mle_hdr->cmdline_start_off, cmdline, mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off - 1); } /* 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); while( i #include #include #include #include #include #define _GNU_SOURCE #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(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_custom_element_t2 *custom = (lcp_custom_element_t2 *)&elt->data; custom->uuid = uuid; memcpy(custom->data, 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.8.2/lcptools-v2/poldata.h0000644000175000017500000000501712365404264015047 0ustar rqwrqw/* * 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 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 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.8.2/lcptools-v2/hash.c0000644000175000017500000001242112365404264014336 0ustar rqwrqw/* * hash.c: support functions for tb_hash_t type * * 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 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) { if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) return false; if ( hash_alg == TB_HALG_SHA1 ) return (memcmp(hash1, hash2, SHA1_LENGTH) == 0); else if ( hash_alg == TB_HALG_SHA256 ) return (memcmp(hash1, hash2, SHA256_LENGTH) == 0); else if ( hash_alg == TB_HALG_SM3 ) return (memcmp(hash1, hash2, SM3_LENGTH) == 0); else if ( hash_alg == TB_HALG_SHA384 ) return (memcmp(hash1, hash2, SHA384_LENGTH) == 0); else if ( hash_alg == TB_HALG_SHA512 ) return (memcmp(hash1, hash2, SHA512_LENGTH) == 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 ) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha1, NULL); return true; } else if (hash_alg == TB_HALG_SHA256) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha256(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha256, NULL); return true; } else if (hash_alg == TB_HALG_SHA384) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha384(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha384, NULL); 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; const EVP_MD *md; memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); memcpy(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); 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 < sizeof(hash->sha1); i++ ) fprintf(stderr, "%02x ", hash->sha1[i]); fprintf(stderr, "\n"); } else if ( hash_alg == TB_HALG_SHA256 ) { for ( unsigned int i = 0; i < sizeof(hash->sha256); i++ ) fprintf(stderr, "%02x ", hash->sha256[i]); fprintf(stderr, "\n"); } else return; } void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg) { if ( dest_hash == NULL || dest_hash == NULL ) return; if ( hash_alg == TB_HALG_SHA1 ) memcpy(dest_hash, 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.8.2/lcptools-v2/sbios_elt.c0000644000175000017500000001407212365404264015402 0ustar rqwrqw/* * 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 #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(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_sbios_element_t2 *sbios = (lcp_sbios_element_t2 *)&elt->data; sbios->hash_alg = alg_type; memcpy(&sbios->fallback_hash, &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(hash, &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.8.2/lcptools-v2/pollist2.h0000644000175000017500000000642412365404264015176 0ustar rqwrqw/* * 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 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 *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.8.2/lcptools-v2/poldata.c0000644000175000017500000002354512365404264015050 0ustar rqwrqw/* * 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 #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 "pollist2.h" #include "lcputils.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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if ( version == LCP_TPM12_POLICY_LIST_VERSION ) { 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 ( version == LCP_TPM20_POLICY_LIST_VERSION ) { 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)); } } 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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if ( version == 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 ( version == 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)); } } 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[strlen(prefix)+8]; sprintf(new_prefix, "%s ", 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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if ( version == 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 ( version == 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)); } } } 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((void *)new_poldata + old_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_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((void *)new_poldata + old_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]; memset(hash_list, 0, sizeof(hash_list)); /* 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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if ( version == 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 ( version == 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; } } /* hash list */ hash_buffer(hash_list, hash_size * poldata->num_lists, (tb_hash_t *)hash, hash_alg); LOG("policy_data_hash:"); print_hex("", hash, get_lcp_hash_size(hash_alg)); return; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools-v2/Makefile0000644000175000017500000000362612365404264014716 0ustar rqwrqw# 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 : $(TPMNV_TARGETS) $(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) 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 v2 POLELT_PLUGINS := mle_elt.o custom_elt.o sbios_elt.o stm_elt.o LCP2_LIB := liblcp.a $(LCP2_LIB) : pol.o poldata.o pollist2.o polelt.o lcputils.o hash.o pollist1.o $(AR) rc $@ $^ lcp2_crtpolelt : crtpolelt.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp2_crtpollist : crtpollist.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp2_crtpol : crtpol.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp2_mlehash : mlehash.o $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -lz -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.8.2/lcptools-v2/pol.c0000644000175000017500000001157012365404264014211 0ustar rqwrqw/* * 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 #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_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_policy(const char *prefix, const lcp_policy_t2 *pol, bool brief) { (void)brief; /* quiet compiler warning portbly */ if ( pol == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pol->version); DISPLAY("%s hash_alg: %s\n", prefix, 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); DISPLAY("%s max_biosac_min_ver: 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); DISPLAY("%s aux_hash_alg_mask: 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(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.8.2/lcptools-v2/polelt.h0000644000175000017500000000422212365404264014717 0ustar rqwrqw/* * 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.8.2/lcptools-v2/pollist1.h0000644000175000017500000000567412365404264015203 0ustar rqwrqw/* * 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); #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.8.2/lcptools-v2/lcputils.c0000644000175000017500000003321612365404264015257 0ustar rqwrqw/* * 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 #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" 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) { strncpy(dst, src, siz-1); if ( siz != 0 ) *(dst + siz-1) = '\0'; return strlen(src); } 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); } if ( nr == *nr_ints ) ERROR("Error: too many items in list\n"); *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); 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 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", 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 "sha1"; case TPM_ALG_SHA256: return "sha256"; case TPM_ALG_SHA384: return "sha384"; case TPM_ALG_SHA512: return "sha512"; case TPM_ALG_SM3_256: return "sm3"; default: snprintf(buf, sizeof(buf), "unknown (%u)", alg); return buf; } } const char *sig_alg_to_str(uint16_t alg) { static char buf[32]; switch(alg){ case TPM_ALG_RSASSA: return "rsa"; case TPM_ALG_ECDSA: return "ecdsa"; case TPM_ALG_SM2: return "sm2"; default: snprintf(buf, sizeof(buf), "unknown (%u)", alg); return buf; } } extern 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; } extern uint16_t str_to_sig_alg(const char *str, const uint16_t version) { LOG("str_to_sig_alg:version=%x\n",version); if( version == LCP_TPM12_POLICY_LIST_VERSION) { if (strcmp(str,"rsa") == 0) return LCP_POLSALG_RSA_PKCS_15; else return LCP_POLSALG_NONE; } else if( version == LCP_TPM20_POLICY_LIST_VERSION) { if( strcmp(str,"rsa") == 0) return TPM_ALG_RSASSA; else if ( strcmp(str,"ecdsa") == 0) { LOG("str_to_sig_alg: sig_alg == ecdsa\n"); return TPM_ALG_ECDSA; } else if ( strcmp(str,"sm2") == 0) return TPM_ALG_SM2; else return TPM_ALG_NULL; } else return TPM_ALG_NULL; } 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; default: return 0; } return 0; } bool verify_signature(const uint8_t *data, size_t data_size, const uint8_t *pubkey, size_t pubkey_size, const uint8_t *sig, bool is_sig_little_endian) { LOG("[verify_signature]\n"); unsigned int i; /* policy key is little-endian and openssl wants big-endian, so reverse */ uint8_t key[pubkey_size]; for ( i = 0; i < pubkey_size; i++ ) key[i] = *(pubkey + (pubkey_size - i - 1)); /* create RSA public key struct */ RSA *rsa_pubkey = RSA_new(); if ( rsa_pubkey == NULL ) { ERROR("Error: failed to allocate key\n"); return false; } rsa_pubkey->n = BN_bin2bn(key, pubkey_size, NULL); /* uses fixed exponent (LCP_SIG_EXPONENT) */ char exp[32]; snprintf(exp, sizeof(exp), "%u", LCP_SIG_EXPONENT); rsa_pubkey->e = NULL; BN_dec2bn(&rsa_pubkey->e, exp); rsa_pubkey->d = rsa_pubkey->p = rsa_pubkey->q = NULL; uint16_t hashalg = TPM_ALG_SHA1; lcp_mle_element_t2 *mle; const lcp_policy_element_t *elt = ((lcp_policy_list_t2 *)data)->policy_elements; uint32_t type = elt->type; switch(type){ case LCP_POLELT_TYPE_MLE2: mle = (lcp_mle_element_t2 *)elt->data; hashalg = mle->hash_alg; LOG("mle_hashalg = 0x%x\n",hashalg); break; default: LOG("unknown element type\n"); } /* first create digest of data */ tb_hash_t digest; if ( !hash_buffer(data, data_size, &digest, hashalg) ) { ERROR("Error: failed to hash list\n"); RSA_free(rsa_pubkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(hashalg)); } /* sigblock is little-endian and openssl wants big-endian, so reverse */ uint8_t sigblock[pubkey_size]; if ( is_sig_little_endian ) { for ( i = 0; i < pubkey_size; i++ ) sigblock[i] = *(sig + (pubkey_size - i - 1)); sig = sigblock; } if ( verbose ) { /* raw decryption of sigblock */ uint8_t unsig[pubkey_size]; if ( RSA_public_decrypt(pubkey_size, sig, unsig, rsa_pubkey, RSA_NO_PADDING) == -1 ) { ERR_load_crypto_strings(); ERROR("Error: failed to decrypt sig: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); } else { LOG("decrypted sig:\n"); print_hex("", unsig, pubkey_size); } } switch(hashalg){ case TPM_ALG_SHA1: /* verify digest */ if ( !RSA_verify(NID_sha1, (const unsigned char *)&digest, get_hash_size(hashalg), (uint8_t *)sig, pubkey_size, rsa_pubkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to verify list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(rsa_pubkey); return false; } break; case TPM_ALG_SHA256: /* verify digest */ if ( !RSA_verify(NID_sha256, (const unsigned char *)&digest, get_hash_size(hashalg), (uint8_t *)sig, pubkey_size, rsa_pubkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to verify list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(rsa_pubkey); return false; } break; case TPM_ALG_SHA384: /* verify digest */ if ( !RSA_verify(NID_sha384, (const unsigned char *)&digest, get_hash_size(hashalg), (uint8_t *)sig, pubkey_size, rsa_pubkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to verify list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(rsa_pubkey); return false; } break; case TPM_ALG_SHA512: /* verify digest */ if ( !RSA_verify(NID_sha512, (const unsigned char *)&digest, get_hash_size(hashalg), (uint8_t *)sig, pubkey_size, rsa_pubkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to verify list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(rsa_pubkey); return false; } break; default : LOG("unknown hash alg\n"); return false; } RSA_free(rsa_pubkey); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools-v2/pollist2.c0000644000175000017500000005657612365404264015206 0ustar rqwrqw/* * 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 #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 "pollist2.h" #include "polelt.h" #include "lcputils.h" #include "pollist1.h" 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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if ( version == LCP_TPM12_POLICY_LIST_VERSION ){ 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((void *)pollist + len, 0, keysize); } *no_sigblock_ok = no_sigblock; LOG("read policy list file succeed!\n"); return pollist; } else if ( version == LCP_TPM20_POLICY_LIST_VERSION ) { 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((void *)pollist + len, 0, keysize); } *no_sigblock_ok = no_sigblock; LOG("read policy list file succeed!\n"); return pollist; } return NULL; } 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 ( pollist->version < LCP_TPM20_POLICY_LIST_VERSION || MAJOR_VER(pollist->version) != MAJOR_VER( LCP_TPM20_POLICY_LIST_VERSION ) ) { 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) { 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_rsa_signature_t) + pollist->policy_elements_size, size); return false; } } else if ( pollist->sig_alg == TPM_ALG_SM2 ) { LOG ("verify_tpm20_policy_list: sig_alg == TPM_ALG_SM2\n"); 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: %s\n", prefix, 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[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", 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); if ( verify_tpm20_pollist_sig(pollist) ) DISPLAY("%s signature verifies\n", prefix); else DISPLAY("%s signature fails to verify\n", prefix); } } 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((void *)&new_pollist->policy_elements + elt->size, &new_pollist->policy_elements, old_size - offsetof(lcp_policy_list_t2, policy_elements)); memcpy(&new_pollist->policy_elements, 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(elt, (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_pollist_sig(const lcp_policy_list_t2 *pollist) { LOG("[verify_tpm20_pollist_sig]\n"); lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return true; if ( pollist->sig_alg == TPM_ALG_RSASSA ) { return verify_signature((const unsigned char *)pollist, get_tpm20_policy_list_size(pollist) - sig->rsa_signature.pubkey_size, sig->rsa_signature.pubkey_value, sig->rsa_signature.pubkey_size, get_tpm20_sig_block(pollist), true); } else if ( pollist->sig_alg == TPM_ALG_ECDSA ) { LOG("verify_tpm20_pollist_sig: sig_alg == TPM_ALG_ECDSA\n"); return false; } else if ( pollist->sig_alg == TPM_ALG_SM2 ) { LOG("verify_tpm20_pollist_sig: sig_alg == TPM_ALG_SM2\n"); return false; } 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[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s\t", prefix); 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 ) { char new_prefix[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s\t", prefix); 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/2); DISPLAY("%s qy:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx + sig->ecc_signature.pubkey_size/2, sig->ecc_signature.pubkey_size/2); DISPLAY("%s r:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx + sig->ecc_signature.pubkey_size, sig->ecc_signature.pubkey_size/2); DISPLAY("%s s:\n", prefix); print_hex(new_prefix, (void *)&sig->ecc_signature.qx + sig->ecc_signature.pubkey_size + sig->ecc_signature.pubkey_size/2, sig->ecc_signature.pubkey_size/2); } else if ( sig_alg == TPM_ALG_SM2 ) { LOG("display_tpm20_signature: sig_alg == TPM_ALG_SM2\n"); } } 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((void *)new_pollist + sig_begin, sig, sig_size); return new_pollist; } else if ( sig_alg == TPM_ALG_ECDSA ) { LOG("add_tpm20_signature: sig_alg == TPM_ALG_ECDSA\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_ecc_signature_t) + 2*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((void *)new_pollist + sig_begin, sig, sig_size); LOG("add tpm20 signature succeed!\n"); return new_pollist; } else if ( sig_alg == TPM_ALG_SM2 ) { LOG("add_tpm20_signature: sig_alg == TPM_ALG_SM2\n"); return NULL; } 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) { 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 ) { LOG("calc_tpm20_policy_list_hash: sig_alg == TPM_ALG_ECDSA\n"); lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return; buf_start = sig->ecc_signature.qx + sig->ecc_signature.pubkey_size; len = 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); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools-v2/crtpollist.c0000644000175000017500000006552612365404264015630 0ustar rqwrqw/* * 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 #define _GNU_SOURCE #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 "pollist2.h" #include "polelt.h" #include "lcputils.h" #include "pollist1.h" static const char help[] = "Usage: lcp_crtpollist [OPTION]\n" "Create an Intel(R) TXT policy list.\n\n" "--create\n" " --out policy list file\n" " [FILE]... policy element files\n" "--sign\n" " --sigalg signature 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\n" "--addsig\n" " --sig file containing signature (big-endian)\n" " --out policy list file\n" "--show\n" " policy list file\n" "--help\n" "--verbose enable verbose output; can be\n" " specified with any command\n\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'}, /* options */ {"out", required_argument, NULL, 'o'}, {"sigalg", required_argument, NULL, 'a'}, {"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'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; #define MAX_FILES 32 static uint16_t version = LCP_DEFAULT_POLICY_LIST_VERSION; static char pollist_file[MAX_PATH] = ""; static char sigalg_name[32] = ""; static uint16_t sigalg_type = TPM_ALG_RSASSA; 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 lcp_signature_t2 *read_rsa_pubkey_file(const char *file) { LOG("read_rsa_pubkey_file\n"); FILE *fp = fopen(file, "r"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", file, strerror(errno)); return NULL; } RSA *pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); 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(); return NULL; } unsigned int keysize = RSA_size(pubkey); if ( keysize == 0 ) { ERROR("Error: public key size is 0\n"); RSA_free(pubkey); return NULL; } lcp_signature_t2 *sig = malloc(sizeof(lcp_rsa_signature_t) + 2*keysize); if ( sig == NULL ) { ERROR("Error: failed to allocate sig\n"); RSA_free(pubkey); return NULL; } memset(sig, 0, sizeof(lcp_rsa_signature_t) + 2*keysize); sig->rsa_signature.pubkey_size = keysize; if ( (unsigned int)BN_num_bytes(pubkey->n) != keysize ) { ERROR("Error: modulus size not match key size\n"); free(sig); RSA_free(pubkey); return NULL; } unsigned char key[keysize]; BN_bn2bin(pubkey->n, 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"); RSA_free(pubkey); return sig; } static lcp_signature_t2 *read_ecdsa_pubkey(const EC_POINT *pubkey, const EC_GROUP *ecgroup) { LOG("[read_ecdsa_pubkey]\n"); BIGNUM *x = BN_new(); BIGNUM *y = BN_new(); BN_CTX *ctx = BN_CTX_new(); EC_POINT_get_affine_coordinates_GFp((const EC_GROUP*)ecgroup, (const EC_POINT *)pubkey, x, y, ctx); unsigned int keysize = BN_num_bytes(x) + BN_num_bytes(y); lcp_signature_t2 *sig = malloc(sizeof(lcp_ecc_signature_t) + 2*keysize); if ( sig == NULL) { ERROR("Error: failed to allocate sig\n"); return NULL; } memset(sig, 0, sizeof(lcp_ecc_signature_t) + 2*keysize); sig->ecc_signature.pubkey_size = keysize; unsigned int BN_X_size = BN_num_bytes(x); unsigned int BN_Y_size = BN_num_bytes(y); unsigned char key_X[BN_X_size]; unsigned char key_Y[BN_Y_size]; BN_bn2bin(x,key_X); BN_bn2bin(y,key_Y); for ( unsigned int i = 0; i < BN_X_size; i++ ) { sig->ecc_signature.qx[i] = *(key_X + (BN_X_size -i - 1)); } for ( unsigned int i = 0; i < BN_Y_size; i++ ) { *(sig->ecc_signature.qx + BN_X_size + i) = *(key_Y + (BN_Y_size -i - 1)); } if ( verbose ) { LOG("read_ecdsa_pubkey_file: signature:\n"); display_tpm20_signature(" ", sig, TPM_ALG_ECDSA, false); } LOG("read ecdsa pubkey succeed!\n"); return sig; } static bool rsa_sign_list_data(lcp_policy_list_t2 *pollist, const char *privkey_file) { LOG("rsa_sign_list_data\n"); if ( pollist == NULL || privkey_file == NULL ) return false; lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return false; if ( pollist->sig_alg == TPM_ALG_RSASSA) { LOG("sign_tpm20_list_data: sig_alg == TPM_ALG_RSASSA\n"); /* read private key */ FILE *fp = fopen(privkey_file, "r"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", privkey_file, strerror(errno)); return false; } RSA *privkey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); if ( privkey == NULL ) { ERR_load_crypto_strings(); ERROR("Error: failed to read .pem file %s: %s\n", privkey_file, ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); return false; } if ( RSA_size(privkey) != sig->rsa_signature.pubkey_size ) { ERROR("Error: private and public key sizes don't match\n"); RSA_free(privkey); return false; } uint16_t hashalg = TPM_ALG_SHA1; lcp_mle_element_t2 *mle; const lcp_policy_element_t *elt = pollist->policy_elements; uint32_t type = elt->type; switch(type){ case LCP_POLELT_TYPE_MLE2 : mle = (lcp_mle_element_t2 *)elt->data; hashalg = mle->hash_alg; LOG("mle hashalg= 0x%x\n", hashalg); break; default: LOG("unknown element type\n"); } /* first create digest of list (all except sig_block) */ tb_hash_t digest; if ( !hash_buffer((const unsigned char *)pollist, get_tpm20_policy_list_size(pollist) - sig->rsa_signature.pubkey_size, &digest, hashalg) ) { ERROR("Error: failed to hash list\n"); RSA_free(privkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(hashalg)); } /* sign digest */ /* work on buffer because we need to byte swap before putting in policy */ uint8_t sigblock[sig->rsa_signature.pubkey_size]; unsigned int sig_len = sig->rsa_signature.pubkey_size; int result = 0; switch(hashalg){ case TPM_ALG_SHA1: result = RSA_sign(NID_sha1, (const unsigned char *)&digest, get_hash_size(hashalg), sigblock, &sig_len, privkey); break; case TPM_ALG_SHA256: result = RSA_sign(NID_sha256, (const unsigned char *)&digest, get_hash_size(hashalg), sigblock, &sig_len, privkey); break; case TPM_ALG_SHA384: result = RSA_sign(NID_sha384, (const unsigned char *)&digest, get_hash_size(hashalg), sigblock, &sig_len, privkey); break; case TPM_ALG_SHA512: result = RSA_sign(NID_sha512, (const unsigned char *)&digest, get_hash_size(hashalg), sigblock, &sig_len, privkey); break; default: break; } if ( !result ) { ERR_load_crypto_strings(); ERROR("Error: failed to sign list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(privkey); return false; } if ( sig_len != sig->rsa_signature.pubkey_size ) { ERROR("Error: signature length mismatch\n"); RSA_free(privkey); return false; } RSA_free(privkey); /* sigblock is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->rsa_signature.pubkey_size; i++ ) *(get_tpm20_sig_block(pollist) + i) = *(sigblock + (sig->rsa_signature.pubkey_size - i - 1)); if ( verbose ) { LOG("signature:\n"); display_tpm20_signature(" ", sig, pollist->sig_alg, false); } return true; } return false; } static bool ecdsa_sign_tpm20_list_data(lcp_policy_list_t2 *pollist, EC_KEY *eckey) { LOG("[ecdsa_sign_tpm20_list_data]\n"); if ( pollist == NULL || eckey == NULL ) return false; lcp_signature_t2 *sig = get_tpm20_signature(pollist); if ( sig == NULL ) return false; if (pollist->sig_alg == TPM_ALG_ECDSA) { LOG("ecdsa_sign_tpm20_list_data: sig_alg == TPM_ALG_ECDSA\n"); /* first create digest of list (all except sig_block) */ tb_hash_t digest; if ( !hash_buffer((const unsigned char *)pollist, get_tpm20_policy_list_size(pollist) - sig->ecc_signature.pubkey_size, &digest, TB_HALG_SHA256) ) { ERROR("Error: failed to hash list\n"); // RSA_free(privkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(TB_HALG_SHA1)); } /* sign digest */ /* work on buffer because we need to byte swap before putting in policy */ ECDSA_SIG *ecdsasig; ecdsasig = ECDSA_do_sign((const unsigned char *)&digest, get_hash_size(TB_HALG_SHA256),eckey ); if ( ecdsasig == NULL) { ERROR("Error: ECDSA_do_sign error\n"); return false; } BIGNUM *r = BN_new(); BIGNUM *s = BN_new(); r = ecdsasig->r; s = ecdsasig->s; unsigned int BN_r_size = BN_num_bytes(r); unsigned int BN_s_size = BN_num_bytes(s); unsigned char key_r[BN_r_size]; unsigned char key_s[BN_s_size]; BN_bn2bin(r,key_r); BN_bn2bin(s,key_s); for ( unsigned int i = 0; i < BN_r_size; i++ ) { *(get_tpm20_sig_block(pollist) + i) = *(key_r + (BN_r_size -i - 1)); } for ( unsigned int i = 0; i < BN_s_size; i++ ) { *(get_tpm20_sig_block(pollist) + BN_r_size + i) = *(key_s + (BN_s_size -i - 1)); } if ( verbose ) { display_tpm20_signature(" ", sig, pollist->sig_alg, false); } return true; } return false; } static int create(void) { LOG("[create]\n"); if ( version != LCP_TPM20_POLICY_LIST_VERSION ) return 1; LOG("create:version=0x0200\n"); lcp_policy_list_t2 *pollist = create_empty_tpm20_policy_list(); if ( pollist == NULL ) 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; } pollist = add_tpm20_policy_element(pollist, elt); if ( pollist == NULL ) return 1; } bool write_ok = write_tpm20_policy_list_file(pollist_file, pollist); free(pollist); return write_ok ? 0 : 1; } static int sign(void) { LOG("[sign]\n"); /* 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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if ( version != LCP_TPM20_POLICY_LIST_VERSION ) return 1; pollist->tpm20_policy_list.sig_alg = sigalg_type; LOG("sign: version==0x0200,sig_alg=0x%x\n",pollist->tpm20_policy_list.sig_alg); if ( pollist->tpm20_policy_list.sig_alg == TPM_ALG_RSASSA ) { /* read public key file */ lcp_signature_t2 *sig = read_rsa_pubkey_file(pubkey_file); if ( sig == NULL ) { ERROR("Error: sign: version == 0x0200, sig == NULL\n"); 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(sig); free(pollist); return 1; } sig->rsa_signature.revocation_counter = rev_ctr; pollist = (lcp_list_t *)add_tpm20_signature(&(pollist->tpm20_policy_list), sig, TPM_ALG_RSASSA); if ( pollist == NULL ) { free(sig); return 1; } if ( no_sigblock ) { memset(get_tpm20_sig_block(&(pollist->tpm20_policy_list)), 0, sig->rsa_signature.pubkey_size); } else { if ( !rsa_sign_list_data(&(pollist->tpm20_policy_list), privkey_file) ) { free(sig); free(pollist); return 1; } } bool write_ok = write_tpm20_policy_list_file(pollist_file, &(pollist->tpm20_policy_list)); free(sig); free(pollist); return write_ok ? 0 : 1; } else if ( pollist->tpm20_policy_list.sig_alg == TPM_ALG_ECDSA ) { LOG("sign: sig_alg == TPM_ALG_ECDSA\n"); EC_KEY *eckey = EC_KEY_new(); EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); EC_KEY_set_group(eckey,ecgroup); if ( !EC_KEY_generate_key(eckey) ) { ERROR("Error: EC_KEY_generate_key error\n"); return 1; } const EC_POINT *pubkey = EC_KEY_get0_public_key(eckey); if( pubkey == NULL) { ERROR("Error: EC_KEY_get0_public_key error\n"); return 1; } lcp_signature_t2 *sig = read_ecdsa_pubkey(pubkey, ecgroup); sig->ecc_signature.revocation_counter = rev_ctr; pollist = (lcp_list_t *)add_tpm20_signature(&(pollist->tpm20_policy_list), sig, TPM_ALG_ECDSA); if ( pollist == NULL ) { free(sig); return 1; } if ( no_sigblock ) { memset(get_tpm20_sig_block(&(pollist->tpm20_policy_list)), 0, sig->ecc_signature.pubkey_size); } else { if ( !ecdsa_sign_tpm20_list_data(&(pollist->tpm20_policy_list), eckey) ) { free(sig); free(pollist); return 1; } } bool write_ok = write_tpm20_policy_list_file(pollist_file, &(pollist->tpm20_policy_list)); free(sig); free(pollist); return write_ok ? 0 : 1; } else if ( pollist->tpm20_policy_list.sig_alg == TPM_ALG_SM2 ) { LOG("sign: sig_alg == TPM_ALG_SM2\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((void*)&version,(const void *)pollist,sizeof(uint16_t)); if (version != LCP_TPM20_POLICY_LIST_VERSION ) return 1; LOG("signature: version == 0x0200\n"); 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_signature((const unsigned char *)&(pollist->tpm20_policy_list), get_tpm20_policy_list_size(&(pollist->tpm20_policy_list)) - sig->rsa_signature.pubkey_size, sig->rsa_signature.pubkey_value, sig->rsa_signature.pubkey_size, data, false) ) { ERROR("Error: signature file does not match policy list\n"); free(pollist); free(data); return 1; } LOG("signature file verified\n"); /* data is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->rsa_signature.pubkey_size; i++ ) *(get_tpm20_sig_block(&(pollist->tpm20_policy_list)) + 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; lcp_list_t *pollist = read_policy_list_file(files[0], false, &no_sigblock_ok); if ( pollist == NULL ) return 1; uint16_t version ; memcpy((void*)&version,(const void *)pollist,sizeof(uint16_t)); if (version != LCP_TPM20_POLICY_LIST_VERSION ) 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 == LCP_POLSALG_RSA_PKCS_15 && !no_sigblock_ok ) { if ( verify_tpm20_pollist_sig(&(pollist->tpm20_policy_list)) ) DISPLAY("signature verified\n"); else DISPLAY("failed to verify signature\n"); } return 0; } 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 */ 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 'a': strlcpy(sigalg_name, optarg, sizeof(sigalg_name)); LOG("cmdline opt: sigalg: %s\n", sigalg_name); sigalg_type = str_to_sig_alg(sigalg_name, version); 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 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; } 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_RSASSA || sigalg_type == LCP_POLSALG_RSA_PKCS_15 ) { 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; } } } 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(); } 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.8.2/lcptools-v2/crtpol.c0000644000175000017500000003237112365404264014724 0ustar rqwrqw/* * 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 #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 "pollist2.h" #include "lcputils.h" #include "pollist1.h" static const char help[] = "Usage: lcp_crtpol2 [OPTION]\n" "Create an Intel(R) TXT policy (and policy data file)\n\n" "--create\n" " --alg hash_alg\n" " --type type\n" " [--minver ] SINITMinVersion\n" " [--rev [,ctrN] revocation values (comma separated,\n" " no spaces\n" " [--ctrl policy file\n" " [--data policy data file\n" " [FILE]... policy list files\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\n"; bool verbose = false; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"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'}, {"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'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; uint16_t version = LCP_DEFAULT_POLICY_VERSION; char policy_file[MAX_PATH] = ""; char poldata_file[MAX_PATH] = ""; char alg_name[32] = ""; uint16_t alg_type = TPM_ALG_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; bool brief = false; unsigned int nr_files = 0; char files[LCP_MAX_LISTS][MAX_PATH]; static 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(pol, 0, sizeof(*pol)); pol->version = version; pol->hash_alg = alg_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; if ( strcmp(type, "any") == 0 ) { pol->policy_type = LCP_POLTYPE_ANY; } else if ( strcmp(type, "list") == 0 ) { pol->policy_type = LCP_POLTYPE_LIST; poldata = malloc(sizeof(*poldata)); if ( poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pol); return 1; } memset(poldata, 0, sizeof(*poldata)); 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; lcp_list_t *pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(pol); free(poldata); return 1; } uint16_t version; memcpy((void*)&version, (const void *)pollist, sizeof(uint16_t)); if ( version == LCP_TPM12_POLICY_LIST_VERSION ) poldata = add_tpm12_policy_list(poldata, (lcp_policy_list_t *)pollist); if( version == LCP_TPM20_POLICY_LIST_VERSION ) poldata = add_tpm20_policy_list(poldata, (lcp_policy_list_t2 *)pollist); if ( poldata == NULL ) { free(pol); free(pollist); return 1; } free(pollist); } calc_policy_data_hash(poldata, &pol->policy_hash, pol->hash_alg); } 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; } static 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_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, false) ) { poldata = (lcp_policy_data_t2 *)data; poldata_len = len; poldata_file = files[0]; } else { pol = data; pol_len = len; pol_file = files[0]; } if ( nr_files == 2 ) { data = read_file(files[1], &len, false); if ( data == NULL ) goto done; if ( pol == 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); } if ( poldata != NULL ) { DISPLAY("\npolicy data file: %s\n", poldata_file); if ( verify_policy_data(poldata, poldata_len) ) { display_policy_data(" ", poldata, brief); if ( pol && pol->policy_type == LCP_POLTYPE_LIST ) { lcp_hash_t2 hash; calc_policy_data_hash(poldata, &hash, pol->hash_alg); if ( memcmp(&hash, &pol->policy_hash, get_lcp_hash_size(pol->hash_alg)) == 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; } else goto done; } err = 0; done: if (pol) free(pol); 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); switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* show */ 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(alg_name, optarg, sizeof(alg_name)); LOG("cmdline opt: alg: %s\n", 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); 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 '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 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 */ alg_type = str_to_hash_alg(alg_name); if ( alg_type == TPM_ALG_NULL) { ERROR("Error: alg not supported\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; } return create(); } 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(); } 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.8.2/lcptools-v2/lcputils.h0000644000175000017500000000624012365404264015261 0ustar rqwrqw/* * 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 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 *sig_alg_to_str(uint16_t alg); extern uint16_t str_to_hash_alg(const char *str); extern uint16_t str_to_sig_alg(const char *str, const uint16_t version); extern size_t get_lcp_hash_size(uint16_t hash_alg); extern bool verify_signature(const uint8_t *data, size_t data_size, const uint8_t *pubkey, size_t pubkey_size, const uint8_t *sig, bool is_sig_little_endian); #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.8.2/lcptools-v2/pol.h0000644000175000017500000000411012365404264014206 0ustar rqwrqw/* * 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 void display_policy(const char *prefix, const lcp_policy_t2 *pol, bool brief); 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.8.2/lcptools-v2/lcptools.txt0000644000175000017500000000540012365404264015646 0ustar rqwrqwThese 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 -c --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 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.8.2/lcptools-v2/polelt_plugin.h0000644000175000017500000000554312365404264016304 0ustar rqwrqw/* * 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.8.2/tboot/0000755000175000017500000000000012365404266012214 5ustar rqwrqwtboot-1.8.2/tboot/20_linux_tboot0000644000175000017500000001462412365404265015014 0ustar rqwrqw#! /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 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 fi 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 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="multiboot" mb_mod_directive="module" mb_extra_kernel="" fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${tboot_version}" "${version}" if ! ${recovery} ; then save_default_entry | sed -e "s/^/\t/" fi if [ -d /sys/firmware/efi ] ; then printf "\tinsmod multiboot2\n" fi 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})" cat << EOF echo '$xmessage' ${mb_directive} ${rel_tboot_dirname}/${tboot_basename} ${rel_tboot_dirname}/${tboot_basename} ${tboot_args} echo '$lmessage' ${mb_mod_directive} ${rel_dirname}/${basename} ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} ${iommu_args} ${mb_extra_kernel} EOF if test -n "${initrd}" ; then message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF echo '$message' ${mb_mod_directive} ${rel_dirname}/${initrd} ${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} ${rel_dirname}/${i} EOF done 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` 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.8.1" 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 if [ -d /sys/firmware/efi ] ; then # there's no vga console available under EFI tboot_log="logging=serial,memory" else tboot_log="logging=serial,vga,memory" fi linux_entry "${OS}" "${version}" "${tboot_version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ${tboot_log} "intel_iommu=on" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${tboot_version}" true \ "single ${GRUB_CMDLINE_LINUX}" ${tboot_log} "intel_iommu=on" 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.8.2/tboot/20_linux_xen_tboot0000644000175000017500000002005112365404265015655 0ustar rqwrqw#! /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 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 fi 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 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 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})" cat << EOF echo '$tmessage' multiboot ${rel_tboot_dirname}/${tboot_basename} ${rel_tboot_dirname}/${tboot_basename} ${tboot_args} echo '$xmessage' module ${rel_xen_dirname}/${xen_basename} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} ${iommu_args} echo '$lmessage' module ${rel_dirname}/${basename} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} EOF if test -n "${initrd}" ; then message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF echo '$message' module ${rel_dirname}/${initrd} ${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' module ${rel_dirname}/${i} ${rel_dirname}/${i} EOF done 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` 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.8.1" 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_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" "${tboot_version}" "logging=serial,vga,memory" "iommu=force" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${xen_version}" true \ "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}" "${tboot_version}" "logging=serial,vga,memory" "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.8.2/tboot/include/0000755000175000017500000000000012365404266013637 5ustar rqwrqwtboot-1.8.2/tboot/include/vmac.h0000644000175000017500000001641512365404266014745 0ustar rqwrqw#ifndef HEADER_VMAC_H #define HEADER_VMAC_H /* -------------------------------------------------------------------------- * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. * This implementation is herby placed in the public domain. * The authors offers no warranty. Use at your own risk. * Please send bug reports to the authors. * Last modified: 17 APR 08, 1700 PDT * ----------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- * User definable settings. * ----------------------------------------------------------------------- */ #define VMAC_TAG_LEN 64 /* Must be 64 or 128 - 64 sufficient for most */ #define VMAC_KEY_LEN 128 /* Must be 128, 192 or 256 */ #define VMAC_NHBYTES 4096/* Must 2^i for any 3 < i < 13. Standard = 128 */ #define VMAC_PREFER_BIG_ENDIAN 0 /* Prefer non-x86 */ #define VMAC_USE_OPENSSL 0 /* Set to non-zero to use OpenSSL's AES */ #define VMAC_CACHE_NONCES 1 /* Set to non-zero to cause caching */ /* of consecutive nonces on 64-bit tags */ #define VMAC_RUN_TESTS 0 /* Set to non-zero to check vectors and speed */ #define VMAC_HZ (448e6) /* Set to hz of host machine to get speed */ #define VMAC_HASH_ONLY 0 /* Set to non-zero to time hash only (not-mac) */ /* Speeds of cpus I have access to #define hz (2400e6) glyme Core 2 "Conroe" #define hz (2000e6) jupiter G5 #define hz (1592e6) titan #define hz (2793e6) athena/gaia #define hz (1250e6) isis G4 #define hz (2160e6) imac Core 2 "Merom" #define hz (266e6) ppc/arm #define hz (400e6) mips */ /* -------------------------------------------------------------------------- * This implementation uses uint32_t and uint64_t as names for unsigned 32- * and 64-bit integer types. These are defined in C99 stdint.h. The * following may need adaptation if you are not running a C99 or * Microsoft C environment. * ----------------------------------------------------------------------- */ #define VMAC_USE_STDINT 1 /* Set to zero if system has no stdint.h */ #if VMAC_USE_STDINT && !_MSC_VER /* Try stdint.h if non-Microsoft */ #ifdef __cplusplus #define __STDC_CONSTANT_MACROS #endif //#include #elif (_MSC_VER) /* Microsoft C does not have stdint.h */ typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #define UINT64_C(v) v ## UI64 #else /* Guess sensibly - may need adaptation */ typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #define UINT64_C(v) v ## ULL #endif /* -------------------------------------------------------------------------- * This implementation supports two free AES implementations: OpenSSL's and * Paulo Barreto's. To use OpenSSL's, you will need to include the OpenSSL * crypto library (eg, gcc -lcrypto foo.c). For Barreto's, you will need * to compile rijndael-alg-fst.c, last seen at http://www.iaik.tu-graz.ac.at/ * research/krypto/AES/old/~rijmen/rijndael/rijndael-fst-3.0.zip and * http://homes.esat.kuleuven.be/~rijmen/rijndael/rijndael-fst-3.0.zip. * To use a different implementation, use these definitions as a model. * ----------------------------------------------------------------------- */ #if VMAC_USE_OPENSSL #include typedef AES_KEY aes_int_key; #define aes_encryption(in,out,int_key) \ AES_encrypt((unsigned char *)(in),(unsigned char *)(out),(int_key)) #define aes_key_setup(key,int_key) \ AES_set_encrypt_key((key),VMAC_KEY_LEN,(int_key)) #else //#include "rijndael-alg-fst.h" typedef uint64_t vmac_t; #include "rijndael.h" typedef u32 aes_int_key[4*(VMAC_KEY_LEN/32+7)]; #define aes_encryption(in,out,int_key) \ rijndaelEncrypt((u32 *)(int_key), \ ((VMAC_KEY_LEN/32)+6), \ (u8 *)(in), (u8 *)(out)) #define aes_key_setup(user_key,int_key) \ rijndaelKeySetupEnc((u32 *)(int_key), \ (u8 *)(user_key), \ VMAC_KEY_LEN) #endif /* --------------------------------------------------------------------- */ typedef struct { uint64_t nhkey [(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; uint64_t polykey[2*VMAC_TAG_LEN/64]; uint64_t l3key [2*VMAC_TAG_LEN/64]; uint64_t polytmp[2*VMAC_TAG_LEN/64]; aes_int_key cipher_key; #if (VMAC_TAG_LEN == 64) && (VMAC_CACHE_NONCES) uint64_t cached_nonce[2]; uint64_t cached_aes[2]; #endif int first_block_processed; } vmac_ctx_t; /* --------------------------------------------------------------------- */ #ifdef __cplusplus extern "C" { #endif /* -------------------------------------------------------------------------- * <<<<< USAGE NOTES >>>>> * * Given msg m (mbytes in length) and nonce buffer n * this function returns a tag as its output. The tag is returned as * a number. When VMAC_TAG_LEN == 64, the 'return'ed integer is the tag, * and *tagl is meaningless. When VMAC_TAG_LEN == 128 the tag is the * number y * 2^64 + *tagl where y is the function's return value. * If you want to consider tags to be strings, then you must do so with * an agreed upon endian orientation for interoperability, and convert * the results appropriately. VHASH hashes m without creating any tag. * Consecutive substrings forming a prefix of a message may be passed * to vhash_update, with vhash or vmac being called with the remainder * to produce the output. * * Requirements: * - On 32-bit architectures with SSE2 instructions, ctx and m MUST be * begin on 16-byte memory boundaries. * - m MUST be your message followed by zeroes to the nearest 16-byte * boundary. If m is a length multiple of 16 bytes, then it is already * at a 16-byte boundary and needs no padding. mbytes should be your * message length without any padding. * - The first bit of the nonce buffer n must be 0. An i byte nonce, is made * as the first 16-i bytes of n being zero, and the final i the nonce. * - vhash_update MUST have mbytes be a positive multiple of VMAC_NHBYTES * ----------------------------------------------------------------------- */ #define vmac_update vhash_update void vhash_update(unsigned char m[], unsigned int mbytes, vmac_ctx_t *ctx); uint64_t vmac(unsigned char m[], unsigned int mbytes, unsigned char n[16], uint64_t *tagl, vmac_ctx_t *ctx); uint64_t vhash(unsigned char m[], unsigned int mbytes, uint64_t *tagl, vmac_ctx_t *ctx); /* -------------------------------------------------------------------------- * When passed a VMAC_KEY_LEN bit user_key, this function initialazies ctx. * ----------------------------------------------------------------------- */ void vmac_set_key(unsigned char user_key[], vmac_ctx_t *ctx); /* -------------------------------------------------------------------------- * This function aborts current hash and resets ctx, ready for a new message. * ----------------------------------------------------------------------- */ void vhash_abort(vmac_ctx_t *ctx); /* --------------------------------------------------------------------- */ #ifdef __cplusplus } #endif #endif /* HEADER_AES_H */ tboot-1.8.2/tboot/include/tpm.h0000644000175000017500000002361412365404266014616 0ustar rqwrqw/* * 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_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) /* * 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) /* * 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[]; 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 { #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; 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 (*cap_pcrs)(struct tpm_if *ti, u32 locality, int pcr); bool (*check)(void); }; extern struct tpm_if tpm_12_if; extern struct tpm_if tpm_20_if; extern struct tpm_if *g_tpm; extern bool tpm_validate_locality(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); //#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.8.2/tboot/include/sha1.h0000644000175000017500000000550712365404266014653 0ustar rqwrqw/*$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.8.2/tboot/include/tpm_20.h0000644000175000017500000014475512365404266015131 0ustar rqwrqw/* * 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) // 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 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 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; #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.8.2/tboot/include/printk.h0000644000175000017500000000470412365404266015324 0ustar rqwrqw/* * 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(void); extern void printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); #endif tboot-1.8.2/tboot/include/rijndael.h0000644000175000017500000000437312365404266015607 0ustar rqwrqw/* $OpenBSD: rijndael.h,v 1.13 2008/06/09 07:49:45 djm Exp $ */ /** * rijndael-alg-fst.h * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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 __RIJNDAEL_H #define __RIJNDAEL_H #define AES_MAXKEYBITS (256) #define AES_MAXKEYBYTES (AES_MAXKEYBITS/8) /* for 256-bit keys, fewer for less */ #define AES_MAXROUNDS 14 //typedef unsigned char u8; //typedef unsigned short u16; //typedef unsigned int u32; /* The structure for key information */ typedef struct { int enc_only; /* context contains only encrypt schedule */ int Nr; /* key-length-dependent number of rounds */ u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */ u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */ } rijndael_ctx; int rijndael_set_key(rijndael_ctx *, const u_char *, int); int rijndael_set_key_enc_only(rijndael_ctx *, const u_char *, int); void rijndael_decrypt(rijndael_ctx *, const u_char *, u_char *); void rijndael_encrypt(rijndael_ctx *, const u_char *, u_char *); int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int); int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int); void rijndaelEncrypt(const unsigned int [], int, const unsigned char [], unsigned char []); #endif /* __RIJNDAEL_H */ tboot-1.8.2/tboot/include/misc.h0000644000175000017500000000607112365404266014747 0ustar rqwrqw/* * 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.8.2/tboot/include/e820.h0000644000175000017500000001110012365404266014457 0ustar rqwrqw/* * 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 void get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size); /* EFI memory map support */ extern efi_memory_desc_t *get_efi_memmap(uint32_t *memmap_size); /* * Memory map descriptor: */ /* 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) /* range requires runtime mapping */ #define EFI_MEMORY_DESCRIPTOR_VERSION 1 #define EFI_PAGE_SHIFT 12 #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.8.2/tboot/include/loader.h0000644000175000017500000001033112365404266015254 0ustar rqwrqw/* * 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 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 void load_framebuffer_info(loader_ctx *lctx, void *vscr); extern char *get_first_module_cmd(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.8.2/tboot/include/sha256.h0000644000175000017500000000233112365404266015017 0ustar rqwrqw#ifndef __SHA256_H__ #define __SHA256_H__ #define STORE64H(x, y) \ { (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); } #define STORE32H(x, y) \ { (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); } #define LOAD32H(x, y) \ { x = ((unsigned long)((y)[0] & 255)<<24) | \ ((unsigned long)((y)[1] & 255)<<16) | \ ((unsigned long)((y)[2] & 255)<<8) | \ ((unsigned long)((y)[3] & 255)); } typedef struct { u64 length; u32 state[8], curlen; unsigned char buf[64]; }sha256_state; void sha256_buffer(const unsigned char *buffer, size_t len, unsigned char hash[32]); #endif /* __SHA256_H__ */ tboot-1.8.2/tboot/include/types.h0000644000175000017500000000552412365404266015162 0ustar rqwrqw/* * 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.8.2/tboot/include/multiboot.h0000644000175000017500000002260612365404266016034 0ustar rqwrqw/* * 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 /* 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_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 #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_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.8.2/tboot/include/integrity.h0000644000175000017500000000644112365404266016033 0ustar rqwrqw/* * 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 #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; vmac_t kernel_integ; } 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.8.2/tboot/include/atomic.h0000644000175000017500000001306612365404266015272 0ustar rqwrqw/*- * 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.8.2/tboot/include/ctype.h0000644000175000017500000000614712365404266015144 0ustar rqwrqw/* * 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.8.2/tboot/include/string.h0000644000175000017500000000523512365404266015323 0ustar rqwrqw/*- * 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, Intel Corporation */ #ifndef __STRING_H__ #define __STRING_H__ #include #include int memcmp(const void *b1, const void *b2, size_t len); char *index(const char *, int); int strcmp(const char *, const char *); size_t strlen(const char *); int strncmp(const char *, const char *, size_t); char *strncpy(char * __restrict, const char * __restrict, size_t); void *memcpy(void *dst, const void *src, size_t len); int snprintf(char *buf, size_t size, const char *fmt, ...); int vscnprintf(char *buf, size_t size, const char *fmt, va_list ap); unsigned long strtoul(const char *nptr, char **endptr, int base); static inline void *memset(void *b, int c, size_t len) { char *bb; for (bb = (char *)b; len--; ) *bb++ = c; return (b); } static inline void *memmove(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } static __inline char *strchr(const char *p, int ch) { return index(p, ch); } #endif /* __STRING_H__ */ tboot-1.8.2/tboot/include/com.h0000644000175000017500000002343112365404266014571 0ustar rqwrqw/*- * 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.8.2/tboot/include/vga.h0000755000175000017500000000610512365404266014572 0ustar rqwrqw/* * 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__ #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) 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.8.2/tboot/include/mutex.h0000644000175000017500000000410412365404266015151 0ustar rqwrqw/* $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.8.2/tboot/include/page.h0000644000175000017500000000462412365404266014732 0ustar rqwrqw/* * 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.8.2/tboot/include/processor.h0000644000175000017500000001722012365404266016031 0ustar rqwrqw/* 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 */ #ifndef __ASSEMBLY__ /* 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 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_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]; } #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_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_ebx(1) >> 24; } 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.8.2/tboot/include/paging.h0000644000175000017500000001030112365404266015250 0ustar rqwrqw/* * 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.8.2/tboot/include/cmdline.h0000644000175000017500000000535412365404266015432 0ustar rqwrqw/* * 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_measure_nv(void); extern void get_tboot_extpol(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 const char *skip_filename(const char *cmdline); 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.8.2/tboot/include/txt/0000755000175000017500000000000012365404266014456 5ustar rqwrqwtboot-1.8.2/tboot/include/txt/acmod.h0000644000175000017500000001366112365404266015721 0ustar rqwrqw/* * 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; uint32_t reserved1; 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 typedef union { uint32_t _raw; struct { uint32_t ext_policy : 2; uint32_t tpm_family : 4; uint32_t reserved : 26; }; } 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 4 */ 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 reserved[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); #endif /* __TXT_ACMOD_H__ */ /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/include/txt/mtrrs.h0000644000175000017500000001130012365404266015771 0ustar rqwrqw/* * 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.8.2/tboot/include/txt/heap.h0000644000175000017500000002572712365404266015561 0ustar rqwrqw/* * 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; #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 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; /* * data-passing structures contained in TXT heap: * - BIOS * - OS/loader to MLE * - OS/loader to SINIT * - SINIT to MLE */ /* * BIOS structure */ typedef struct __packed { uint32_t version; /* currently 2-4 */ uint32_t bios_sinit_size; uint64_t lcp_pd_base; uint64_t lcp_pd_size; uint32_t num_logical_procs; /* versions >= 3 */ uint64_t flags; /* For TPM2, it is divided into sinit_flag and mle_flag */ /* 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); #endif /* __TXT_HEAP_H__ */ /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/include/txt/config_regs.h0000644000175000017500000001543412365404266017123 0ustar rqwrqw/* * 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 */ #ifndef IS_INCLUDED static inline uint64_t read_config_reg(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); } #endif static inline void write_config_reg(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 uint64_t read_pub_config_reg(uint32_t reg) { return read_config_reg(TXT_PUB_CONFIG_REGS_BASE, reg); } static inline void write_pub_config_reg(uint32_t reg, uint64_t val) { write_config_reg(TXT_PUB_CONFIG_REGS_BASE, reg, val); } static inline uint64_t read_priv_config_reg(uint32_t reg) { return read_config_reg(TXT_PRIV_CONFIG_REGS_BASE, reg); } static inline void write_priv_config_reg(uint32_t reg, uint64_t val) { write_config_reg(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.8.2/tboot/include/txt/txt.h0000644000175000017500000000500512365404266015446 0ustar rqwrqw/* * 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 extern bool txt_is_launched(void); extern bool txt_get_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 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.8.2/tboot/include/txt/verify.h0000644000175000017500000000427712365404266016145 0ustar rqwrqw/* * 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.8.2/tboot/include/txt/smx.h0000644000175000017500000001203112365404266015433 0ustar rqwrqw/* * 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.8.2/tboot/include/txt/errorcode.h0000644000175000017500000000744112365404266016621 0ustar rqwrqw/* * 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.8.2/tboot/include/txt/vmcs.h0000644000175000017500000003144312365404266015604 0ustar rqwrqw/* * 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.8.2/tboot/include/acpi.h0000644000175000017500000003516712365404266014740 0ustar rqwrqw/* $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_int8_t register_base_address[8]; struct device_scope deviec_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 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 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.8.2/tboot/include/io.h0000644000175000017500000000557412365404266014432 0ustar rqwrqw/*- * 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.8.2/tboot/include/pci_cfgreg.h0000755000175000017500000000527612365404266016115 0ustar rqwrqw/* * 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.8.2/tboot/include/linux_defns.h0000644000175000017500000002527212365404266016336 0ustar rqwrqw/* * 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 */ uint16_t pad1; /* Unused */ 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 pad2[3]; /* Unused */ 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; } 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 */ /* 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 0x9000 #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.8.2/tboot/include/msr.h0000644000175000017500000000751012365404266014614 0ustar rqwrqw/*- * 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 /* * 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.8.2/tboot/include/compiler.h0000644000175000017500000000367112365404266015631 0ustar rqwrqw/* * 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.8.2/tboot/Makefile0000644000175000017500000000662512365404265013664 0ustar rqwrqw# 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 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/rijndael.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/vmac.o common/vsprintf.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 OBJS := $(obj-y) TARGET_LDS := $(CURDIR)/common/tboot.lds $(TARGET).gz : $(TARGET) gzip -f -9 < $< > $@ $(TARGET) : $(OBJS) $(TARGET_LDS) $(LD) $(LDFLAGS) -T $(TARGET_LDS) -N $(OBJS) -o $(@D)/.$(@F).0 $(NM) -n $(@D)/.$(@F).0 >$(TARGET)-syms $(LD) $(LDFLAGS) -T $(TARGET_LDS) $(LDFLAGS_STRIP) $(@D)/.$(@F).0 -o $(TARGET) rm -f $(@D)/.$(@F).0 $(TARGET_LDS) : $(TARGET_LDS).x $(HDRS) $(CPP) -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 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 $@ tboot-1.8.2/tboot/common/0000755000175000017500000000000012365404266013504 5ustar rqwrqwtboot-1.8.2/tboot/common/linux.c0000644000175000017500000003765712365404265015030 0ustar rqwrqw/* * 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 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 = strlen(what); const char *cptr = what; char cmdchunk[CHUNK_SIZE+1]; while (cmdlen > 0) { 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 - 0x8FFF Stack and heap 0x9000 - 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; /* 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, max_ram_size; get_highest_sized_ram(initrd_size, mem_limit, &max_ram_base, &max_ram_size); if ( max_ram_size == 0 ) { 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; } 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)); 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; /* load protected-mode part */ 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 */ 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 = skip_filename(get_cmdline(g_ldr_ctx)); printk(TBOOT_INFO"Linux cmdline placed in header: "); printk_long(kernel_cmdline); printk(TBOOT_INFO"\n"); memcpy((void *)hdr->cmd_line_ptr, kernel_cmdline, strlen(kernel_cmdline)); /* need to put boot_params in real mode area so it gets mapped */ boot_params = (boot_params_t *)(real_mode_base + real_mode_size); memset(boot_params, 0, sizeof(*boot_params)); 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); struct screen_info_t *scr = (struct screen_info_t *)(boot_params->screen_info); uint32_t address = 0; uint64_t long_address = 0UL; /* loader signature */ 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 memmap descriptor size */ efi->efi_memdescr_size = 0x30; /* EFI memmap descriptor version */ efi->efi_memdescr_ver = 1; #if 1 /* EFI memmap addr */ { uint32_t length; efi->efi_memmap = (uint32_t) get_efi_memmap(&length); /* EFI memmap size */ efi->efi_memmap_size = length; } #else efi->efi_memmap = 0; efi->efi_memmap_size = 0x70; #endif /* EFI memmap high--since we're consing our own, we know this == 0 */ efi->efi_memmap_hi = 0; /* if we're here, GRUB2 probably threw a framebuffer tag at us */ load_framebuffer_info(g_ldr_ctx, (void *)scr); } /* detect e820 table */ if (have_loader_memmap(g_ldr_ctx)) { int i; memory_map_t *p = get_loader_memmap(g_ldr_ctx); 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 + p->size + sizeof(p->size); } 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, 0x00c09b000000ffff, /* cs */ 0x00c093000000ffff /* 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.8.2/tboot/common/rijndael.c0000644000175000017500000016340412365404266015450 0ustar rqwrqw/* $OpenBSD: rijndael.c,v 1.19 2008/06/09 07:49:45 djm Exp $ */ /** * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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 #undef FULL_UNROLL /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Te4[x] = S [x].[01, 01, 01, 01]; Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; static const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; static const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; static const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; static const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; static const u32 Td4[256] = { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, }; static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) #define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); if (keyBits == 128) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { return 10; } rk += 4; } } rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); if (keyBits == 192) { for (;;) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { return 12; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { return 14; } temp = rk[11]; rk[12] = rk[ 4] ^ (Te4[(temp >> 24) ] & 0xff000000) ^ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(temp ) & 0xff] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } return 0; } /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i, j; u32 temp; /* expand the cipher key: */ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the first and the last: */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[0] ) & 0xff] & 0xff]; rk[1] = Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[1] ) & 0xff] & 0xff]; rk[2] = Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[2] ) & 0xff] & 0xff]; rk[3] = Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[3] ) & 0xff] & 0xff]; } return Nr; } void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; /* round 5: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; /* round 6: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; /* round 7: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; /* round 8: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; /* round 9: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; /* round 11: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; /* round 13: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3 ) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0 ) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1 ) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Te4[(t0 >> 24) ] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(ct , s0); s1 = (Te4[(t1 >> 24) ] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24) ] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24) ] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); } static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct ) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; /* round 3: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; /* round 4: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; /* round 5: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; /* round 6: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; /* round 7: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; /* round 8: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; /* round 9: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; /* round 11: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; /* round 13: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td0[(t0 >> 24) ] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[(t1 ) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24) ] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[(t2 ) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24) ] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[(t3 ) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24) ] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[(t0 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Td4[(t0 >> 24) ] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t1 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(pt , s0); s1 = (Td4[(t1 >> 24) ] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t2 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(pt + 4, s1); s2 = (Td4[(t2 >> 24) ] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t3 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(pt + 8, s2); s3 = (Td4[(t3 >> 24) ] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t0 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(pt + 12, s3); } /* setup key context for encryption only */ int rijndael_set_key_enc_only(rijndael_ctx *ctx, const u_char *key, int bits) { int rounds; rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); if (rounds == 0) return -1; ctx->Nr = rounds; ctx->enc_only = 1; return 0; } /* setup key context for both encryption and decryption */ int rijndael_set_key(rijndael_ctx *ctx, const u_char *key, int bits) { int rounds; rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); if (rounds == 0) return -1; if (rijndaelKeySetupDec(ctx->dk, key, bits) != rounds) return -1; ctx->Nr = rounds; ctx->enc_only = 0; return 0; } void rijndael_decrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst) { rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); } void rijndael_encrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst) { rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); } tboot-1.8.2/tboot/common/strncpy.c0000644000175000017500000000416412365404266015357 0ustar rqwrqw/*- * 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 *strncpy(char * __restrict dst, const char * __restrict src, size_t n) { 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.8.2/tboot/common/memcpy.c0000644000175000017500000000715112365404265015145 0ustar rqwrqw/*- * 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 *memcpy(void *dst0, const void *src0, size_t length) { char *dst; const char *src; size_t t; dst = dst0; src = src0; 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.8.2/tboot/common/index.c0000644000175000017500000000372612365404265014766 0ustar rqwrqw/*- * 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 *index(p, ch) const char *p; int ch; { union { const char *cp; char *p; } u; u.cp = p; for (;; ++u.p) { if (*u.p == ch) return(u.p); if (*u.p == '\0') return(NULL); } /* NOTREACHED */ } tboot-1.8.2/tboot/common/vga.c0000644000175000017500000000736412365404266014437 0ustar rqwrqw/* * 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 static uint16_t * const 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 inline void reset_screen(void) { memset(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 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 __putc(uint8_t x, uint8_t y, int c) { screen[(y * MAX_COLS) + x] = (COLOR << 8) | c; } static void vga_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: __putc(cursor_x, cursor_y, 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 ) { 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); } } void vga_init(void) { reset_screen(); } void vga_puts(const char *s, unsigned int cnt) { while ( *s && cnt-- ) { vga_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.8.2/tboot/common/policy.c0000644000175000017500000007224312365404265015156 0ustar rqwrqw/* * 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 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_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_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_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_SHA1, 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; if ( policy_index_size == NULL ) { printk(TBOOT_ERR"size is NULL\n"); return false; } ret = g_tpm->get_nvindex_size(g_tpm, 0, 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 = g_tpm->nv_read(g_tpm, 0, 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; } /* * 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; uint32_t lcp_size; // 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 ( memcmp((void *)lcp_base, LCP_POLICY_DATA_FILE_SIGNATURE, LCP_FILE_SIG_LENGTH) == 0 ) { lcp_policy_data_t *poldata = (lcp_policy_data_t *)lcp_base; lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( int i = 0; i < poldata->num_lists; i++ ) { lcp_policy_element_t *elt = pollist->policy_elements; uint32_t elts_size = 0; 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)) ) { 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 >= pollist->policy_elements_size ) break; elt = (void *)elt + elt->size; } if ( pollist->version == LCP_TPM12_POLICY_LIST_VERSION ) pollist = (void *)pollist + get_tpm12_policy_list_size(pollist); else if ( pollist->version == LCP_TPM20_POLICY_LIST_VERSION ) pollist = (void *)pollist + get_tpm20_policy_list_size( (lcp_policy_list_t2 *)pollist); } } return false; } /* * set_policy * * load policy from TPM NV and validate it, else use default * */ tb_error_t set_policy(void) { /* 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(g_tpm->tb_policy_index, _policy_index_buf, &policy_index_size) ) { 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(g_tpm->lcp_own_index, _policy_index_buf, &policy_index_size) ) { 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 ( pol->version == 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; if ( pol2->version == 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"); 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) { 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 (g_tpm->extpol) { case TB_EXTPOL_FIXED: hl->count = 1; hl->entries[0].alg = g_tpm->cur_alg; if ( !hash_buffer((const unsigned char *)cmdline, strlen(cmdline), &hl->entries[0].hash, g_tpm->cur_alg) ) return false; /* hash image and extend into cmdline hash */ tb_hash_t img_hash; if ( !hash_buffer(base, size, &img_hash, g_tpm->cur_alg) ) return false; if ( !extend_hash(&hl->entries[0].hash, &img_hash, g_tpm->cur_alg) ) return false; break; case TB_EXTPOL_AGILE: { hash_list_t img_hl; if ( !g_tpm->hash(g_tpm, 2, (const unsigned char *)cmdline, strlen(cmdline), hl) ) { if ( !g_tpm->hash(g_tpm, 2, base, size, hl) ) return false; return true; } uint8_t buf[128]; if ( !g_tpm->hash(g_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 ( !g_tpm->hash(g_tpm, 2, buf, 2*get_hash_size(hl->entries[i].alg), hl) ) return false; break; } } } break; } case TB_EXTPOL_EMBEDDED: { tb_hash_t img_hash; hl->count = g_tpm->alg_count; for (unsigned int i=0; icount; i++) { hl->entries[i].alg = g_tpm->algs[i]; if ( !hash_buffer((const unsigned char *)cmdline, strlen(cmdline), &hl->entries[i].hash, g_tpm->algs[i]) ) return false; if ( !hash_buffer(base, size, &img_hash, g_tpm->algs[i]) ) return false; if ( !extend_hash(&hl->entries[i].hash, &img_hash, g_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 ( pol_entry != NULL ) { /* chunk the command line into 80 byte chunks */ #define CHUNK_SIZE 80 int cmdlen = strlen(cmdline); char *cptr = cmdline; char cmdchunk[CHUNK_SIZE+1]; printk(TBOOT_INFO"verifying module \""); while (cmdlen > 0) { 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 ( g_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) { /* 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)]; memset(buf, 0, sizeof(buf)); 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)], g_tpm->cur_alg) ) { printk(TBOOT_ERR"policy hash failed\n"); apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); } } u32 size = get_hash_size(g_tpm->cur_alg) + sizeof(g_policy->policy_control); switch (g_tpm->extpol) { case TB_EXTPOL_FIXED: VL_ENTRIES(NUM_VL_ENTRIES).hl.count = 1; VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].alg = g_tpm->cur_alg; if ( !hash_buffer(buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].hash, g_tpm->cur_alg) ) apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); break; case TB_EXTPOL_AGILE: if ( !g_tpm->hash(g_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 = g_tpm->alg_count; for (int i=0; ialg_count; i++) { VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[i].alg = g_tpm->algs[i]; if ( !hash_buffer(buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[i].hash, g_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) { /* 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; 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 ( !g_tpm->get_nvindex_permission(g_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 */ 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; } 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; 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.8.2/tboot/common/sha1.c0000644000175000017500000002236612365404266014515 0ustar rqwrqw/*$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; 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; memset(&ctxt->m.b8[0],0, 64); } /*------------------------------------------------------------*/ void sha1_init(struct sha1_ctxt *ctxt) { 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) { 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 */ } 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; 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 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.8.2/tboot/common/wakeup.S0000644000175000017500000000524612365404266015133 0ustar rqwrqw/* * 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.8.2/tboot/common/integrity.c0000644000175000017500000004306212365404265015672 0ustar rqwrqw/* * 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 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[VMAC_KEY_LEN/8]; uint8_t shared_key[sizeof(_tboot_shared.s3_key)]; } sealed_secrets_t; static bool extend_pcrs(void) { for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { if ( !g_tpm->pcr_extend(g_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) { 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, g_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 { tb_hash_t data_hash; uint8_t secrets[secrets_size]; } blob; uint32_t err; memset(&blob, 0, sizeof(blob)); if ( !hash_buffer(data, data_size, &blob.data_hash, g_tpm->cur_alg) ) { printk(TBOOT_ERR"failed to hash data\n"); return false; } if ( secrets != NULL && secrets_size > 0 ) memcpy(blob.secrets, secrets, secrets_size); err = g_tpm->seal(g_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 */ 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 { tb_hash_t data_hash; uint8_t secrets[secrets_size]; } blob; bool err = true; uint32_t data_size = sizeof(blob); if ( !g_tpm->unseal(g_tpm, 2, 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 maches sealed hash */ tb_hash_t curr_data_hash; memset(&curr_data_hash, 0, sizeof(curr_data_hash)); if ( !hash_buffer(curr_data, curr_data_size, &curr_data_hash, g_tpm->cur_alg) ) { printk(TBOOT_WARN"failed to hash state data\n"); goto done; } if ( !are_hashes_equal(&blob.data_hash, &curr_data_hash, g_tpm->cur_alg) ) { printk(TBOOT_WARN"sealed hash does not match current hash\n"); goto done; } if ( secrets != NULL && secrets_size > 0 ) memcpy(secrets, &blob.secrets, secrets_size); err = false; done: /* clear secret from local memory */ 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) { /* save hash of current policy into g_pre_k_s3_state */ 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, g_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 ( g_tpm->major == TPM12_VER_MAJOR ) { if ( !g_tpm->pcr_read(g_tpm, 2, 17, &post_launch_pcr17) || !g_tpm->pcr_read(g_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(vmac_t *mac, uint8_t key[VMAC_KEY_LEN/8]) { vmac_ctx_t ctx; uint8_t nonce[16] = {}; 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 % VMAC_NHBYTES == 0); /* enable paging */ if ( !enable_paging() ) return false; vmac_set_key(key, &ctx); 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) ) { vmac_update((uint8_t *)(uintptr_t)vstart, MAC_PAGE_SIZE, &ctx); vstart += MAC_PAGE_SIZE; } /* MAC the rest */ if ( vend > vstart ) vmac_update((uint8_t *)(uintptr_t)vstart, vend - vstart, &ctx); /* destroy the mapping */ if ( virt == MAC_VIRT_START ) destroy_tboot_mapping(MAC_VIRT_START, MAC_VIRT_END); } while ( start < end ); } *mac = vmac(NULL, 0, nonce, NULL, &ctx); /* wipe ctx to ensure key not left in memory */ memset(&ctx, 0, sizeof(ctx)); /* 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; /* read PCR 17/18, only for tpm1.2 */ if ( g_tpm->major == TPM12_VER_MAJOR ) { if ( !g_tpm->pcr_read(g_tpm, 2, 17, &pcr17) || !g_tpm->pcr_read(g_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 ( !g_tpm->verify_creation(g_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 */ vmac_t mac; if ( !measure_memory_integrity(&mac, secrets.mac_key) ) goto error; if ( 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 */ memcpy(_tboot_shared.s3_key, secrets.shared_key, sizeof(_tboot_shared.s3_key)); /* wipe secrets from memory */ 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 ( !g_tpm->cap_pcrs(g_tpm, 2, 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; /* 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 ( !g_tpm->get_random(g_tpm, 2, 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 */ 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 */ 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.8.2/tboot/common/shutdown.S0000644000175000017500000000741312365404266015510 0ustar rqwrqw/* * 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 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.8.2/tboot/common/sha256.c0000644000175000017500000002145712365404266014671 0ustar rqwrqw#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(sha256_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->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->state[i] = md->state[i] + S[i]; } return 0; } #define SHA256_BLOCK_SIZE 64 #define MIN(x, y) ( ((x)<(y))?(x):(y) ) int sha256_process(sha256_state * md, const unsigned char *in, unsigned long inlen) { unsigned long n; int err; if (md == NULL || in == NULL) return -1; if (md->curlen > sizeof(md->buf)) return -1; while (inlen > 0) { if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { if ((err = sha256_compress(md, (unsigned char *)in)) != 0) { return err; } md->length += SHA256_BLOCK_SIZE * 8; in += SHA256_BLOCK_SIZE; inlen -= SHA256_BLOCK_SIZE; } else { n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen)); memcpy(md->buf + md->curlen, in, (size_t)n); md->curlen += n; in += n; inlen -= n; if (md->curlen == SHA256_BLOCK_SIZE) { if ((err = sha256_compress(md, md->buf)) != 0) { return err; } md->length += 8*SHA256_BLOCK_SIZE; md->curlen = 0; } } } return 0; } /** Initialize the hash state @param md The hash state you wish to initialize @return CRYPT_OK if successful */ void sha256_init(sha256_state * md) { if (md == NULL) return; md->curlen = 0; md->length = 0; md->state[0] = 0x6A09E667UL; md->state[1] = 0xBB67AE85UL; md->state[2] = 0x3C6EF372UL; md->state[3] = 0xA54FF53AUL; md->state[4] = 0x510E527FUL; md->state[5] = 0x9B05688CUL; md->state[6] = 0x1F83D9ABUL; md->state[7] = 0x5BE0CD19UL; } /** 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(sha256_state * md, unsigned char *out) { int i; if (md == NULL || out == NULL) return -1; if (md->curlen >= sizeof(md->buf)) return -1; /* increase the length of the message */ md->length += md->curlen * 8; /* append the '1' bit */ md->buf[md->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->curlen > 56) { while (md->curlen < 64) { md->buf[md->curlen++] = (unsigned char)0; } sha256_compress(md, md->buf); md->curlen = 0; } /* pad upto 56 bytes of zeroes */ while (md->curlen < 56) { md->buf[md->curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->length, md->buf+56); sha256_compress(md, md->buf); /* copy output */ for (i = 0; i < 8; i++) { STORE32H(md->state[i], out+(4*i)); } return 0; } void sha256_buffer(const unsigned char *buffer, size_t len, unsigned char hash[32]) { sha256_state md; sha256_init(&md); sha256_process(&md, buffer, len); sha256_done(&md, hash); } tboot-1.8.2/tboot/common/tboot.c0000644000175000017500000004722112365404266015005 0ustar rqwrqw/* * 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 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); void s3_launch(void); /* 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) { return txt_is_launched(); } 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 */ memcpy(g_saved_s3_wakeup_page, (void *)TBOOT_S3_WAKEUP_ADDR, s3_wakeup_end - s3_wakeup_16); /* copy s3 entry into target mem */ 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 */ memcpy((void *)TBOOT_S3_WAKEUP_ADDR, g_saved_s3_wakeup_page, s3_wakeup_end - s3_wakeup_16); } static void post_launch(void) { uint64_t base, size; tb_error_t err; 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 */ save_vtd_dmar_table(); if ( s3_flag ) s3_launch(); /* remove all TXT modules before verifying modules */ remove_txt_modules(g_ldr_ctx); /* * verify e820 table and adjust it to protect our memory regions */ /* ensure all modules are in RAM */ if ( !verify_modules(g_ldr_ctx) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* marked mem regions used by TXT (heap, SINIT, etc.) as E820_RESERVED */ err = txt_protect_mem_regions(); apply_policy(err); /* 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 using memory logging, reserve log area */ if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY ) { base = TBOOT_SERIAL_LOG_ADDR; 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); } /* replace map in loader context with copy */ replace_e820_map(g_ldr_ctx); printk(TBOOT_DETA"adjusted e820 map:\n"); print_e820_map(); /* * verify modules against policy */ verify_all_modules(g_ldr_ctx); /* * verify nv indices against policy */ if ( (g_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); /* * init MLE/kernel shared data page */ 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 ( !g_tpm->get_random(g_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); } memset(g_cmdline, '\0', sizeof(g_cmdline)); if (cmdline) strncpy(g_cmdline, cmdline, sizeof(g_cmdline)-1); } /* always parse cmdline */ tboot_parse_cmdline(); /* initialize all logging targets */ printk_init(); 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 ( 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); } /* 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 */ /* make TPM ready for measured launch */ if ( !tpm_detect() ) apply_policy(TB_ERR_TPM_NOT_READY); /* read tboot 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_get_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() ) 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) { /* restore backed-up s3 wakeup page */ restore_saved_s3_wakeup_page(); /* remove DMAR table if necessary */ remove_vtd_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); /* (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) ) snprintf(type, sizeof(type), "unknown: %u", shutdown_type); else strncpy(type, types[shutdown_type], sizeof(type)); 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 */ case TB_SHUTDOWN_S4: case TB_SHUTDOWN_S5: machine_sleep(&_tboot_shared.acpi_sinfo); /* if machine_sleep() fails, fall through to reset */ 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); } case TB_SHUTDOWN_HALT: default: while ( true ) halt(); } } void shutdown(void) { /* 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) */ release_locality(0); release_locality(1); if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_S3 ) { /* restore DMAR table if needed */ restore_vtd_dmar_table(); /* 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 */ 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 */ g_tpm->cap_pcrs(g_tpm, 2, -1); /* 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 ) g_tpm->save_state(g_tpm, 2); /* 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.8.2/tboot/common/hash.c0000644000175000017500000001275412365404265014603 0ustar rqwrqw/* * 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 (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_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 ) { memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); 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 ) { memcpy(buf, &(hash1->sha256), sizeof(hash1->sha256)); 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_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 ) 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.8.2/tboot/common/pci_cfgreg.c0000755000175000017500000001012012365404265015734 0ustar rqwrqw/* * 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.8.2/tboot/common/tpm_12.c0000644000175000017500000017762412365404266014773 0ustar rqwrqw/* * 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); 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; tpm12_digest_t * out = NULL; if ( ti == NULL ) return false; if ( in == NULL || pcr >= TPM_NR_PCRS){ ti->error = TPM_BAD_PARAMETER; return false; } if ( out == NULL ) out_size = 0; else out_size = sizeof(*out); /* copy pcr into buf in reversed byte order, then copy in data */ reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr)); in_size += sizeof(pcr); 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; } if ( out != NULL && out_size > 0 ) { out_size = (out_size > sizeof(*out)) ? sizeof(*out) : out_size; memcpy((void *)out, WRAPPER_OUT_BUF, out_size); } #ifdef TPM_TRACE { printk(TBOOT_INFO"TPM: "); print_hex(NULL, out->digest, out_size); } #endif 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); 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 ) 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); 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) {\ 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) {\ 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) {\ LOAD_INTEGER(buf, offset, (sel)->size_of_select);\ LOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\ } #define LOAD_PCR_INFO_LONG(buf, offset, info) {\ 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);\ LOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection);\ LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\ LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\ } #define LOAD_STORED_DATA12(buf, offset, hdr) {\ 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);\ LOAD_BLOB(buf, offset,\ ((tpm_stored_data12_short_t *)hdr)->enc_data,\ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\ }\ else {\ LOAD_PCR_INFO_LONG(buf, offset,\ &((tpm_stored_data12_t *)hdr)->seal_info);\ LOAD_INTEGER(buf, offset,\ ((tpm_stored_data12_t *)hdr)->enc_data_size);\ LOAD_BLOB(buf, offset,\ ((tpm_stored_data12_t *)hdr)->enc_data,\ ((tpm_stored_data12_t *)hdr)->enc_data_size);\ }\ } 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; 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; LOAD_STORED_DATA12(WRAPPER_OUT_BUF, offset, sealed_data); *sealed_data_size = offset; 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; 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 if ( *secret_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; } offset = 0; LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *secret_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); 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) { 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; } 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; } 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 ( 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; 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, *resp_size); if ( out_size < sizeof(*resp_size) + *resp_size ) { printk(TBOOT_WARN"TPM: capability response too small\n"); return TPM_FAIL; } 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; 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 */ 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; } 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; 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 > 0 ) memcpy(random_data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size); /* data might be used as key, so clear from buffer memory */ 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) { 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 */ 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; } 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 ); } struct tpm_if tpm_12_if = { .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, .cur_loc = 0, .timeout.timeout_a = TIMEOUT_A, .timeout.timeout_b = TIMEOUT_B, .timeout.timeout_c = TIMEOUT_C, .timeout.timeout_d = TIMEOUT_D, }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/common/strncmp.c0000644000175000017500000000362012365404266015337 0ustar rqwrqw/*- * 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 strncmp(s1, s2, n) register const char *s1, *s2; register size_t n; { if (n == 0) 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.8.2/tboot/common/memcmp.c0000644000175000017500000000375312365404265015135 0ustar rqwrqw/*- * 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 $ */ #include /* * Compare memory regions. */ int memcmp(const void *s1, const void *s2, size_t n) { if (n != 0) { const unsigned char *p1 = s1, *p2 = s2; do { if (*p1++ != *p2++) return (*--p1 - *--p2); } while (--n != 0); } return (0); } tboot-1.8.2/tboot/common/tb_error.c0000644000175000017500000001334312365404266015472 0ustar rqwrqw/* * 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 #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_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; 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); if ( error == NULL ) { printk(TBOOT_ERR"Error: error pointer is zero.\n"); return false; } memset(error, 0, size); /* read! */ if ( !g_tpm->nv_read(g_tpm, 0, g_tpm->tb_err_index, 0, (uint8_t *)error, &size) ) { printk(TBOOT_WARN"Error: read TPM error: 0x%x.\n", g_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) { if ( !g_tpm || no_err_idx ) return false; if ( !g_tpm->nv_write(g_tpm, 0, g_tpm->tb_err_index, 0, (uint8_t *)&error, sizeof(tb_error_t)) ) { printk(TBOOT_WARN"Error: write TPM error: 0x%x.\n", g_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 ) 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.8.2/tboot/common/com.c0000644000175000017500000001005012365404265014421 0ustar rqwrqw/*- * 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.8.2/tboot/common/strtoul.c0000644000175000017500000000612212365404266015365 0ustar rqwrqw/*- * 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 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; /* * 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.8.2/tboot/common/misc.c0000644000175000017500000002340312365404265014604 0ustar rqwrqw/* * 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.8.2/tboot/common/mutex.S0000644000175000017500000000372112365404265014774 0ustar rqwrqw/* $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.8.2/tboot/common/acpi.c0000644000175000017500000003453212365404265014572 0ustar rqwrqw/* * 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 struct acpi_table_header *g_dmar_table; static __data bool g_hide_dmar; 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 ( 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 ( 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 ( memcmp(table->signature, table_name, sizeof(table->signature)) == 0 ) return table; } } printk(TBOOT_ERR"cann't find %s table.\n", table_name); return NULL; } static struct acpi_dmar *get_vtd_dmar_table(void) { return (struct acpi_dmar *)find_table(DMAR_SIG); } bool save_vtd_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 restore_vtd_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 */ 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 remove_vtd_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; } 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); } 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.8.2/tboot/common/strlen.c0000644000175000017500000000335512365404266015165 0ustar rqwrqw/*- * 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 strlen(str) const char *str; { register const char *s; for (s = str; *s; ++s); return(s - str); } tboot-1.8.2/tboot/common/tpm.c0000644000175000017500000003635712365404266014466 0ustar rqwrqw/* * 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 struct tpm_if *g_tpm = NULL; u16 tboot_alg_list[] = {TB_HALG_SHA1, TB_HALG_SHA256}; /* * 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 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 */ #define TPM_REG_STS 0x18 typedef union { u8 _raw[4]; /* 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 */ /* version >= 2 */ u8 command_cancel : 1; u8 reset_establishment : 1; u8 tpm_family : 2; u8 reserved2 : 4; }; } tpm_reg_sts_t; /* TPM_DATA_FIFO_x */ #define TPM_REG_DATA_FIFO 0x24 typedef union { uint8_t _raw[1]; /* 1-byte reg */ } tpm_reg_data_fifo_t; #define TPM_ACTIVE_LOCALITY_TIME_OUT \ (TIMEOUT_UNIT * g_tpm->timeout.timeout_a) /* according to spec */ #define TPM_CMD_READY_TIME_OUT \ (TIMEOUT_UNIT * g_tpm->timeout.timeout_b) /* according to spec */ #define TPM_CMD_WRITE_TIME_OUT \ (TIMEOUT_UNIT * g_tpm->timeout.timeout_d) /* let it long enough */ #define TPM_DATA_AVAIL_TIME_OUT \ (TIMEOUT_UNIT * g_tpm->timeout.timeout_c) /* let it long enough */ #define TPM_RSP_READ_TIME_OUT \ (TIMEOUT_UNIT * g_tpm->timeout.timeout_d) /* let it long enough */ #define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 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; } static bool tpm_wait_cmd_ready(uint32_t locality) { uint32_t i; tpm_reg_access_t reg_acc; tpm_reg_sts_t reg_sts; /* 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; } /* 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: 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 "); #endif i = 0; do { /* write 1 to TPM_STS_x.commandReady to let TPM enter ready state */ memset((void *)®_sts, 0, sizeof(reg_sts)); reg_sts.command_ready = 1; write_tpm_reg(locality, TPM_REG_STS, ®_sts); cpu_relax(); /* then see if it has */ read_tpm_reg(locality, TPM_REG_STS, ®_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"."); #endif if ( reg_sts.command_ready == 1 ) 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 ) { printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x\n", (uint32_t)reg_sts._raw[0], (uint32_t)reg_sts._raw[1], (uint32_t)reg_sts._raw[2]); 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; } 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; tpm_reg_sts_t reg_sts; 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 = %d\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 { read_tpm_reg(locality, TPM_REG_STS, ®_sts); /* find out how many bytes the TPM can accept in a row */ row_size = reg_sts.burst_count; 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 { read_tpm_reg(locality,TPM_REG_STS, ®_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"Wait on Expect = 0, Status register %02x\n", reg_sts._raw[0]); #endif if ( reg_sts.sts_valid == 1 && reg_sts.expect == 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 expect becoming 0 timeout\n"); ret = false; goto RelinquishControl; } /* command has been written to the TPM, it is time to execute it. */ memset(®_sts, 0, sizeof(reg_sts)); reg_sts.tpm_go = 1; write_tpm_reg(locality, TPM_REG_STS, ®_sts); /* check for data available */ i = 0; do { read_tpm_reg(locality,TPM_REG_STS, ®_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"Waiting for DA Flag, Status register %02x\n", reg_sts._raw[0]); #endif if ( reg_sts.sts_valid == 1 && reg_sts.data_avail == 1 ) 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 { read_tpm_reg(locality, TPM_REG_STS, ®_sts); row_size = reg_sts.burst_count; 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 memset(®_sts, 0, sizeof(reg_sts)); reg_sts.command_ready = 1; write_tpm_reg(locality, TPM_REG_STS, ®_sts); 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 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 prepare_tpm(void) { /* * must ensure TPM_ACCESS_0.activeLocality bit is clear * (: locality is not active) */ return release_locality(0); } bool tpm_detect(void) { tpm_reg_sts_t reg_sts; g_tpm = &tpm_12_if; /* Don't leave g_tpm as NULL*/ if ( !tpm_validate_locality(0) ) { printk(TBOOT_ERR"TPM: Locality 0 is not open\n"); return false; } /* get TPM family from TPM status register */ memset((void *)®_sts, 0, sizeof(reg_sts)); /* write_tpm_reg(0, TPM_REG_STS, ®_sts); */ /* read_tpm_reg(0, TPM_REG_STS, ®_sts); */ if ( g_tpm->check() ) reg_sts.tpm_family = 0; else reg_sts.tpm_family = 1; printk(TBOOT_INFO"TPM: TPM Family 0x%d\n", reg_sts.tpm_family); if (reg_sts.tpm_family == 1) g_tpm = &tpm_20_if; else g_tpm = &tpm_12_if; g_tpm->cur_loc = 0; g_tpm->timeout.timeout_a = TIMEOUT_A; g_tpm->timeout.timeout_b = TIMEOUT_B; g_tpm->timeout.timeout_c = TIMEOUT_C; g_tpm->timeout.timeout_d = TIMEOUT_D; return g_tpm->init(g_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); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/common/elf.c0000644000175000017500000001363312365404265014423 0ustar rqwrqw/* * 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 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"Error: ELF magic number is not matched.\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 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 ) { 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 0 static 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; } } #endif bool expand_elf_image(const elf_header_t *elf, void **entry_point) { if ( elf == 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 */ /* 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 ) { memcpy((void *)ph->p_paddr, (void *)elf + ph->p_offset, ph->p_filesz); 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.8.2/tboot/common/tboot.lds.x0000644000175000017500000000173412365404266015612 0ustar rqwrqw/* 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) _stext = .; /* text */ _mle_start = .; /* beginning of MLE pages */ *(.text) *(.fixup) *(.gnu.warning) } :text = 0x9090 _etext = .; /* end of text section */ .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.8.2/tboot/common/tpm_20.c0000644000175000017500000022061512365404266014757 0ustar rqwrqw/* * 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 #include static u8 cmd_buf[MAX_COMMAND_SIZE]; static u8 rsp_buf[MAX_RESPONSE_SIZE]; #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 void reverse_copy_pcr_selection_out(TPML_PCR_SELECTION *pcr_selection, void **other) { u32 i, k; if (pcr_selection == NULL) return; /* Copy count of pcrs to be read. */ reverse_copy_out(pcr_selection->count, *other); 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); /* 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); } } /* * 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; } static u16 reverse_copy_sized_buf_out(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) + dest->size; } static void reverse_copy_digest_out(TPML_DIGEST *tpml_digest, void **other) { u32 i; if (tpml_digest == NULL) return; reverse_copy_out(tpml_digest->count, *other); for (i=0; icount; i++) *other += reverse_copy_sized_buf_out((TPM2B *)&(tpml_digest->digests[i]), (TPM2B *)*other); } 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 void reverse_copy_session_data_out(TPM_CMD_SESSION_DATA_OUT *session_data, void **other) { if (session_data == NULL) return; /* Copy nonce */ *other += reverse_copy_sized_buf_out((TPM2B *)&(session_data->nonce), (TPM2B *)*other); /* Copy sessionAttributes */ *(u8 *)(void *)&(session_data->session_attr) = *((u8 *)*other); *other += sizeof(u8); /* Copy hmac */ *other += reverse_copy_sized_buf_out((TPM2B *)&(session_data->hmac), (TPM2B *)*other); } static void 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; sessions_out->num_sessions = sessions_in->num_sessions; for (i=0; inum_sessions; i++) reverse_copy_session_data_out(&sessions_out->sessions[i], &other); } 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 void reverse_copy_digest_values_out(TPML_DIGEST_VALUES *tpml_digest, void **other) { unsigned int i, k, num_bytes; if (tpml_digest == NULL) return; reverse_copy_out(tpml_digest->count, *other); 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); } } } /* * 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 void 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); if (public == NULL) return; 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 */ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.auth_policy, (TPM2B *)*other); /* 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 */ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.keyed_hash, (TPM2B *)*other); 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 */ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.sym, (TPM2B *)*other); 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 */ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.rsa, (TPM2B *)*other); 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 */ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.ecc, (TPM2B *)*other); 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; } } static void reverse_copy_creation_data_out(TPM2B_CREATION_DATA *data, void **other) { if (data == NULL) return; reverse_copy_out(data->t.size, *other); reverse_copy_pcr_selection_out(&data->t.data.pcr_select, other); *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.pcr_digest), (TPM2B *)*other); *((u8 *)(void *)&data->t.data.locality) = *((u8 *)*other); *other += sizeof(u8); reverse_copy_out(data->t.data.parent_name_alg, *other); *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_name), (TPM2B *)*other); *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_qualified_name), (TPM2B *)*other); *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.outside_info), (TPM2B *)*other); } static void reverse_copy_ticket_out(TPMT_TK_CREATION *ticket, void **other) { if (ticket == NULL) return; reverse_copy_out(ticket->tag, *other); reverse_copy_out(ticket->hierarchy, *other); *other += reverse_copy_sized_buf_out((TPM2B *)&(ticket->digest), (TPM2B *)*other); } 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 ( !tpm_submit_cmd(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); reverse_copy_pcr_selection_out(&out->pcr_selection, &other); reverse_copy_digest_out(&out->pcr_values, &other); 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 ( !tpm_submit_cmd(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_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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 ( !tpm_submit_cmd(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_digest_values_out(&out->digests, &other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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 ( !tpm_submit_cmd(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_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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 ( !tpm_submit_cmd(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_digest_values_out(&out->results, &other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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; 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(*out); if ( !tpm_submit_cmd(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); other += reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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 ( !tpm_submit_cmd(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_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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; 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 ( !tpm_submit_cmd(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); other += reverse_copy_sized_buf_out((TPM2B *)&(out->nv_public.t.nv_public.auth_policy), (TPM2B *)other); reverse_copy_out(out->nv_public.t.nv_public.data_size, other); other += reverse_copy_sized_buf_out((TPM2B *)&(out->nv_name), (TPM2B *)other); 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; 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 ( !tpm_submit_cmd(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); other += reverse_copy_sized_buf_out((TPM2B *)&(out->random_bytes), (TPM2B *)other); 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 ( !tpm_submit_cmd(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; } static __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; 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 ( !tpm_submit_cmd(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 */ reverse_copy_public_out(&out->public, &other); /* Save creationData */ reverse_copy_creation_data_out(&(out->creation_data), &other); /* Save creationHash */ other += reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), (TPM2B *)other); /* Save creationTicket */ reverse_copy_ticket_out(&(out->creation_ticket), &other); other += reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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; 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(*out); if ( !tpm_submit_cmd(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 */ other += reverse_copy_sized_buf_out((TPM2B *)&(out->private), (TPM2B *)other); /* Save outPublic */ reverse_copy_public_out(&out->public, &other); /* Save creationData */ reverse_copy_creation_data_out(&(out->creation_data), &other); /* Save creationHash */ other += reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash), (TPM2B *)other); /* Save creationTicket */ reverse_copy_ticket_out(&(out->creation_ticket), &other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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; 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 ( !tpm_submit_cmd(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); other += reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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; 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 ( !tpm_submit_cmd(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); other += reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other); reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions); 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 || data_size == 0 ) 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 = 1024; } else { chunk_size = data_size - i; } buffer.t.size = chunk_size; memcpy( &(buffer.t.buffer[0]), &(data[i] ), chunk_size ); if( chunk_size == 1024 ) { 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; } } else { 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; for ( j=0; jcount; j++ ) { hl->entries[j].alg = complete_out.results.digests[j].hash_alg; 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; } *data_size = read_out.data.t.size; if( *data_size > 0 ) 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; 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) { if ( ti == NULL || locality >= TPM_NR_LOCALITIES || index == 0 || attribute == NULL ) return false; 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; create_in.sensitive.t.sensitive.user_auth.t.size = sizeof(auth_str) - 1; memcpy(&(create_in.sensitive.t.sensitive.user_auth.t.buffer[0]), auth_str, sizeof(auth_str)-1); create_in.sensitive.t.sensitive.data.t.size = in_data_size; 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; 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); 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; 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; 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 %u 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) 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 %x random bytes but only got %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 %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 %u 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) 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 */ 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<2; i++) { if (alg == tboot_alg_list[i]) return true; } return false; } static bool tpm20_init(struct tpm_if *ti) { u32 ret; unsigned int i; if ( ti == NULL ) return false; /* 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(); /* init NV index */ ti->tb_policy_index = 0x1200001; ti->lcp_own_index = 0x1400001; ti->tb_err_index = 0x1200002; /* 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(0, &event_in, &event_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: PcrEvent 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"TPM: supported alg cout = %08X\n", ti->alg_count); for (unsigned int i=0; ialg_count; i++) printk(TBOOT_INFO"\t\t %08X\n", ti->algs[i]); 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_PLATFORM; 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; ret = _tpm20_create_primary(0, &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; out: tpm_print(ti); return true; } struct tpm_if tpm_20_if = { .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, }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/common/loader.c0000644000175000017500000017066412365404265015133 0ustar rqwrqw/* * loader.c: support functions for manipulating ELF/Linux kernel * 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. * */ #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 *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 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 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 = strlen(what); char *cptr = what; char cmdchunk[CHUNK_SIZE+1]; while (cmdlen > 0) { 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 = 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) { 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 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); } /* 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 */ 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 ((strlen(mod_string)) > (strlen(cmdline))){ if (strlen(mod_string) >= TBOOT_KERNEL_CMDLINE_SIZE){ printk(TBOOT_ERR"No room to copy MB2 cmdline [%d < %d]\n", (int)(strlen(cmdline)), (int)(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, strlen(cmdbuf) - 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 = ""; 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; } if (false == grow_mb2_tag(lctx, cur, strlen(new_cmdline) - strlen(cmd->string))) 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); cmd->size = 2 * sizeof(uint32_t) + strlen(cmd->string) + 1; } 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 ( 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 + 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 + 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 + 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); } 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(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 ) 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(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); 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 const char *get_boot_loader_name(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY ){ if (((multiboot_info_t *)lctx->addr)->flags & MBI_BTLDNAME) return (char *)((multiboot_info_t *)lctx->addr)->boot_loader_name; return NULL; } /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_LOADER_NAME); if (start) return &((struct mb2_tag_string *)start)->string[0]; return NULL; } static void remove_filename_from_modules_cmdline(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return; for ( unsigned int i = 0; i < get_module_count(lctx); i++ ) { module_t *m = get_module(lctx, i); char *cmdline = get_module_cmd(lctx, m); const char *adjusted_cmdline = skip_filename(cmdline); if ( adjusted_cmdline != NULL && cmdline != adjusted_cmdline ) strncpy(cmdline, adjusted_cmdline, strlen(cmdline)); } } 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) - 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; 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); /* for GRUB 2, remove the filename in mods' cmdline */ const char *loader_name = get_boot_loader_name(g_ldr_ctx); if ( loader_name != NULL && strncmp(loader_name, "GNU GRUB 0", 10) ) remove_filename_from_modules_cmdline(g_ldr_ctx); } 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; 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 ) { m = get_module(g_ldr_ctx,0); void *initrd_image = (void *)m->mod_start; size_t 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, 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); for (i = 0; i < (get_nr_map()); i++){ *old = *new; old++, new++; } } /* printk(TBOOT_INFO"AFTER replace_e820_map, loader context:\n"); print_loader_ctx(lctx); */ printk(TBOOT_INFO"replaced memory map:\n"); print_e820_map(); 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, size %d\n", *(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_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; } 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)); } void load_framebuffer_info(loader_ctx *lctx, void *vscr) { screen_info_t *scr = (screen_info_t *) vscr; struct mb2_tag *start; if (scr == NULL) return; if (LOADER_CTX_BAD(lctx)) return; start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_FRAMEBUFFER); if (start != NULL){ struct mb2_fb *mbf = (struct mb2_fb *) start; scr->lfb_base = (uint32_t) mbf->common.fb_addr; 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; scr->orig_video_isVGA = 0x70; /* EFI FB */ scr->orig_y = 24; } } 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.8.2/tboot/common/paging.c0000644000175000017500000001604112365404265015116 0ustar rqwrqw/* * 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; 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; memset(pdptr_table, 0, sizeof(pdptr_table)); memset(pd_table, 0, sizeof(pd_table)); for ( i = 0; i < sizeof(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.8.2/tboot/common/printk.c0000644000175000017500000001177612365404265015172 0ustar rqwrqw/* * 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 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; /* * memory logging */ /* memory-based serial log (ensure in .data section so that not cleared) */ __data tboot_log_t *g_log = NULL; static void memlog_init(void) { if ( g_log == NULL ) { g_log = (tboot_log_t *)TBOOT_SERIAL_LOG_ADDR; g_log->uuid = (uuid_t)TBOOT_LOG_UUID; g_log->curr_pos = 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->curr_pos > g_log->max_size ) g_log->curr_pos = 0; } static void memlog_write(const char *str, unsigned int count) { if ( g_log == NULL || count > g_log->max_size ) return; /* wrap to beginning if too big to fit */ if ( g_log->curr_pos + count > g_log->max_size ) g_log->curr_pos = 0; 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 printk_init(void) { 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 ( g_log_targets & TBOOT_LOG_TARGET_VGA ) { vga_init(); get_tboot_vga_delay(); /* parse vga delay time */ } } #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; memset(buf, '\0', sizeof(buf)); va_start(ap, fmt); n = 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.8.2/tboot/common/cmdline.c0000644000175000017500000004233412365404265015270 0ustar rqwrqw/* * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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", "sha1" }, /* agile|embedded|sha1|sha256|sm3|... */ { 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 ( 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++ ) { 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 = strchr(opt_start, ' '); if ( opt_end == NULL ) opt_end = opt_start + strlen(opt_start); p = opt_end; /* find value part; if no value found, use default and continue */ const char *val_start = 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 ( strncmp(options[i].name, opt_start, opt_name_size ) == 0 ) { 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 ( strncmp(loglvl, g_loglvl_map[i].log_name, strlen(g_loglvl_map[i].log_name)) == 0 ) { loglvl += 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 ( 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 ( strncmp(targets, "memory", 6) == 0 ) { g_log_targets |= TBOOT_LOG_TARGET_MEMORY; targets += 6; } else if ( strncmp(targets, "serial", 6) == 0 ) { g_log_targets |= TBOOT_LOG_TARGET_SERIAL; targets += 6; } else if ( 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 = strtoul(*bdf, (char **)bdf, 16); if ( **bdf != ':' ) return false; (*bdf)++; *slot = strtoul(*bdf, (char **)bdf, 16); if ( **bdf != '.' ) return false; (*bdf)++; *func = 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 ( 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 = 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 = 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 = 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 = 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 = 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 && 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 = 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 || 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 || 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 || 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 || 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"); if ( extpol == NULL ) { g_tpm->extpol = TB_EXTPOL_FIXED; g_tpm->cur_alg = TB_HALG_SHA256; return; } if ( strcmp(extpol, "agile") == 0 ) { g_tpm->extpol = TB_EXTPOL_AGILE; g_tpm->cur_alg = TB_HALG_SHA256; } else if ( strcmp(extpol, "embedded") == 0 ) { g_tpm->extpol = TB_EXTPOL_EMBEDDED; g_tpm->cur_alg = TB_HALG_SHA256; } else if ( strcmp(extpol, "sha256") == 0 ) { g_tpm->extpol = TB_EXTPOL_FIXED; g_tpm->cur_alg = TB_HALG_SHA256; } else if ( strcmp(extpol, "sha1") == 0 ) { g_tpm->extpol = TB_EXTPOL_FIXED; g_tpm->cur_alg = TB_HALG_SHA1; } else if ( strcmp(extpol, "sm3") == 0 ) { g_tpm->extpol = TB_EXTPOL_FIXED; g_tpm->cur_alg = TB_HALG_SM3; } } /* * 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 ( strcmp(vga, "normal") == 0 ) *vid_mode = 0xFFFF; else if ( strcmp(vga, "ext") == 0 ) *vid_mode = 0xFFFE; else if ( strcmp(vga, "ask") == 0 ) *vid_mode = 0xFFFD; else *vid_mode = 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 = 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; } const char *skip_filename(const char *cmdline) { if ( cmdline == NULL || *cmdline == '\0' ) return cmdline; /* strip leading spaces, file name, then any spaces until the next non-space char (e.g. " /foo/bar baz" -> "baz"; "/foo/bar" -> "")*/ while ( *cmdline != '\0' && isspace(*cmdline) ) cmdline++; while ( *cmdline != '\0' && !isspace(*cmdline) ) cmdline++; while ( *cmdline != '\0' && isspace(*cmdline) ) cmdline++; return cmdline; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/common/vmac.c0000644000175000017500000012321612365404266014603 0ustar rqwrqw/* -------------------------------------------------------------------------- * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. * This implementation is herby placed in the public domain. * The authors offers no warranty. Use at your own risk. * Please send bug reports to the authors. * Last modified: 17 APR 08, 1700 PDT * ----------------------------------------------------------------------- */ /* * Portions copyright (c) 2010, Intel Corporation */ //#include "vmac.h" //#include //#include /* start for tboot */ #include #include #include #define UINT64_C(x) x##ULL /* end for tboot */ /* Enable code tuned for 64-bit registers; otherwise tuned for 32-bit */ #ifndef VMAC_ARCH_64 #define VMAC_ARCH_64 (__x86_64__ || __ppc64__ || _M_X64) #endif /* Enable code tuned for Intel SSE2 instruction set */ #if ((__SSE2__ || (_M_IX86_FP >= 2)) && ( ! VMAC_ARCH_64)) #define VMAC_USE_SSE2 1 #include #endif /* Native word reads. Update (or define via compiler) if incorrect */ #ifndef VMAC_ARCH_BIG_ENDIAN /* Assume big-endian unless on the list */ #define VMAC_ARCH_BIG_ENDIAN \ (!(__x86_64__ || __i386__ || _M_IX86 || \ _M_X64 || __ARMEL__ || __MIPSEL__)) #endif /* ----------------------------------------------------------------------- */ /* Constants and masks */ const uint64_t p64 = UINT64_C(0xfffffffffffffeff); /* 2^64 - 257 prime */ const uint64_t m62 = UINT64_C(0x3fffffffffffffff); /* 62-bit mask */ const uint64_t m63 = UINT64_C(0x7fffffffffffffff); /* 63-bit mask */ const uint64_t m64 = UINT64_C(0xffffffffffffffff); /* 64-bit mask */ const uint64_t mpoly = UINT64_C(0x1fffffff1fffffff); /* Poly key mask */ /* ----------------------------------------------------------------------- * * The following routines are used in this implementation. They are * written via macros to simulate zero-overhead call-by-reference. * All have default implemantations for when they are not defined in an * architecture-specific manner. * * MUL64: 64x64->128-bit multiplication * PMUL64: assumes top bits cleared on inputs * ADD128: 128x128->128-bit addition * GET_REVERSED_64: load and byte-reverse 64-bit word * ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ #if (__GNUC__ && (__x86_64__ || __amd64__)) /* ----------------------------------------------------------------------- */ #define ADD128(rh,rl,ih,il) \ asm ("addq %3, %1 \n\t" \ "adcq %2, %0" \ : "+r"(rh),"+r"(rl) \ : "r"(ih),"r"(il) : "cc"); #define MUL64(rh,rl,i1,i2) \ asm ("mulq %3" : "=a"(rl), "=d"(rh) : "a"(i1), "r"(i2) : "cc") #define PMUL64 MUL64 #define GET_REVERSED_64(p) \ ({uint64_t x; \ asm ("bswapq %0" : "=r" (x) : "0"(*(uint64_t *)(p))); x;}) /* ----------------------------------------------------------------------- */ #elif (__GNUC__ && __i386__) /* ----------------------------------------------------------------------- */ #define GET_REVERSED_64(p) \ ({ uint64_t x; \ uint32_t *tp = (uint32_t *)(p); \ asm ("bswap %%edx\n\t" \ "bswap %%eax" \ : "=A"(x) \ : "a"(tp[1]), "d"(tp[0])); \ x; }) /* ----------------------------------------------------------------------- */ #elif (__GNUC__ && __ppc64__) /* ----------------------------------------------------------------------- */ #define ADD128(rh,rl,ih,il) \ asm volatile ( "addc %1, %1, %3 \n\t" \ "adde %0, %0, %2" \ : "+r"(rh),"+r"(rl) \ : "r"(ih),"r"(il)); #define MUL64(rh,rl,i1,i2) \ { uint64_t _i1 = (i1), _i2 = (i2); \ rl = _i1 * _i2; \ asm volatile ("mulhdu %0, %1, %2" : "=r" (rh) : "r" (_i1), "r" (_i2));\ } #define PMUL64 MUL64 #define GET_REVERSED_64(p) \ ({ uint32_t hi, lo, *_p = (uint32_t *)(p); \ asm volatile ("lwbrx %0, %1, %2" : "=r"(lo) : "b%"(0), "r"(_p) ); \ asm volatile ("lwbrx %0, %1, %2" : "=r"(hi) : "b%"(4), "r"(_p) ); \ ((uint64_t)hi << 32) | (uint64_t)lo; } ) /* ----------------------------------------------------------------------- */ #elif (__GNUC__ && (__ppc__ || __PPC__)) /* ----------------------------------------------------------------------- */ #define GET_REVERSED_64(p) \ ({ uint32_t hi, lo, *_p = (uint32_t *)(p); \ asm volatile ("lwbrx %0, %1, %2" : "=r"(lo) : "b%"(0), "r"(_p) ); \ asm volatile ("lwbrx %0, %1, %2" : "=r"(hi) : "b%"(4), "r"(_p) ); \ ((uint64_t)hi << 32) | (uint64_t)lo; } ) /* ----------------------------------------------------------------------- */ #elif (__GNUC__ && (__ARMEL__ || __ARM__)) /* ----------------------------------------------------------------------- */ #define bswap32(v) \ ({ uint32_t tmp,out; \ asm volatile( \ "eor %1, %2, %2, ror #16\n" \ "bic %1, %1, #0x00ff0000\n" \ "mov %0, %2, ror #8\n" \ "eor %0, %0, %1, lsr #8" \ : "=r" (out), "=&r" (tmp) \ : "r" (v)); \ out;}) /* ----------------------------------------------------------------------- */ #elif _MSC_VER /* ----------------------------------------------------------------------- */ #include #if (_M_IA64 || _M_X64) && \ (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) #define MUL64(rh,rl,i1,i2) (rl) = _umul128(i1,i2,&(rh)); #pragma intrinsic(_umul128) #define PMUL64 MUL64 #endif /* MSVC uses add, adc in this version */ #define ADD128(rh,rl,ih,il) \ { uint64_t _il = (il); \ (rl) += (_il); \ (rh) += (ih) + ((rl) < (_il)); \ } #if _MSC_VER >= 1300 #define GET_REVERSED_64(p) _byteswap_uint64(*(uint64_t *)(p)) #pragma intrinsic(_byteswap_uint64) #endif #if _MSC_VER >= 1400 && \ (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) #define MUL32(i1,i2) (__emulu((uint32_t)(i1),(uint32_t)(i2))) #pragma intrinsic(__emulu) #endif /* ----------------------------------------------------------------------- */ #endif /* ----------------------------------------------------------------------- */ #if __GNUC__ #define ALIGN(n) __attribute__ ((aligned(n))) #define NOINLINE __attribute__ ((noinline)) #define FASTCALL #elif _MSC_VER #define ALIGN(n) __declspec(align(n)) #define NOINLINE __declspec(noinline) #define FASTCALL __fastcall #else #define ALIGN(n) #define NOINLINE #define FASTCALL #endif /* ----------------------------------------------------------------------- */ /* Default implementations, if not defined above */ /* ----------------------------------------------------------------------- */ #ifndef ADD128 #define ADD128(rh,rl,ih,il) \ { uint64_t _il = (il); \ (rl) += (_il); \ if ((rl) < (_il)) (rh)++; \ (rh) += (ih); \ } #endif #ifndef MUL32 #define MUL32(i1,i2) ((uint64_t)(uint32_t)(i1)*(uint32_t)(i2)) #endif #ifndef PMUL64 /* rh may not be same as i1 or i2 */ #define PMUL64(rh,rl,i1,i2) /* Assumes m doesn't overflow */ \ { uint64_t _i1 = (i1), _i2 = (i2); \ uint64_t m = MUL32(_i1,_i2>>32) + MUL32(_i1>>32,_i2); \ rh = MUL32(_i1>>32,_i2>>32); \ rl = MUL32(_i1,_i2); \ ADD128(rh,rl,(m >> 32),(m << 32)); \ } #endif #ifndef MUL64 #define MUL64(rh,rl,i1,i2) \ { uint64_t _i1 = (i1), _i2 = (i2); \ uint64_t m1= MUL32(_i1,_i2>>32); \ uint64_t m2= MUL32(_i1>>32,_i2); \ rh = MUL32(_i1>>32,_i2>>32); \ rl = MUL32(_i1,_i2); \ ADD128(rh,rl,(m1 >> 32),(m1 << 32)); \ ADD128(rh,rl,(m2 >> 32),(m2 << 32)); \ } #endif #ifndef GET_REVERSED_64 #ifndef bswap64 #ifndef bswap32 #define bswap32(x) \ ({ uint32_t bsx = (x); \ ((((bsx) & 0xff000000u) >> 24) | (((bsx) & 0x00ff0000u) >> 8) | \ (((bsx) & 0x0000ff00u) << 8) | (((bsx) & 0x000000ffu) << 24)); }) #endif #define bswap64(x) \ ({ union { uint64_t ll; uint32_t l[2]; } w, r; \ w.ll = (x); \ r.l[0] = bswap32 (w.l[1]); \ r.l[1] = bswap32 (w.l[0]); \ r.ll; }) #endif #define GET_REVERSED_64(p) bswap64(*(uint64_t *)(p)) #endif /* ----------------------------------------------------------------------- */ #if (VMAC_PREFER_BIG_ENDIAN) # define get64PE get64BE #else # define get64PE get64LE #endif #if (VMAC_ARCH_BIG_ENDIAN) # define get64BE(ptr) (*(uint64_t *)(ptr)) # define get64LE(ptr) GET_REVERSED_64(ptr) #else /* assume little-endian */ # define get64BE(ptr) GET_REVERSED_64(ptr) # define get64LE(ptr) (*(uint64_t *)(ptr)) #endif /* --------------------------------------------------------------------- * * For highest performance the L1 NH and L2 polynomial hashes should be * carefully implemented to take advantage of one's target architechture. * Here these two hash functions are defined multiple time; once for * 64-bit architectures, once for 32-bit SSE2 architectures, and once * for the rest (32-bit) architectures. * For each, nh_16 *must* be defined (works on multiples of 16 bytes). * Optionally, nh_vmac_nhbytes can be defined (for multiples of * VMAC_NHBYTES), and nh_16_2 and nh_vmac_nhbytes_2 (versions that do two * NH computations at once). * --------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ #if VMAC_ARCH_64 /* ----------------------------------------------------------------------- */ #define nh_16(mp, kp, nw, rh, rl) \ { int i; uint64_t th, tl; \ rh = rl = 0; \ for (i = 0; i < nw; i+= 2) { \ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\ ADD128(rh,rl,th,tl); \ } \ } #define nh_16_2(mp, kp, nw, rh, rl, rh1, rl1) \ { int i; uint64_t th, tl; \ rh1 = rl1 = rh = rl = 0; \ for (i = 0; i < nw; i+= 2) { \ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i )+(kp)[i+2],get64PE((mp)+i+1)+(kp)[i+3]);\ ADD128(rh1,rl1,th,tl); \ } \ } #if (VMAC_NHBYTES >= 64) /* These versions do 64-bytes of message at a time */ #define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \ { int i; uint64_t th, tl; \ rh = rl = 0; \ for (i = 0; i < nw; i+= 8) { \ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i+2)+(kp)[i+2],get64PE((mp)+i+3)+(kp)[i+3]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i+4)+(kp)[i+4],get64PE((mp)+i+5)+(kp)[i+5]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i+6)+(kp)[i+6],get64PE((mp)+i+7)+(kp)[i+7]);\ ADD128(rh,rl,th,tl); \ } \ } #define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh1, rl1) \ { int i; uint64_t th, tl; \ rh1 = rl1 = rh = rl = 0; \ for (i = 0; i < nw; i+= 8) { \ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i )+(kp)[i+2],get64PE((mp)+i+1)+(kp)[i+3]);\ ADD128(rh1,rl1,th,tl); \ MUL64(th,tl,get64PE((mp)+i+2)+(kp)[i+2],get64PE((mp)+i+3)+(kp)[i+3]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i+2)+(kp)[i+4],get64PE((mp)+i+3)+(kp)[i+5]);\ ADD128(rh1,rl1,th,tl); \ MUL64(th,tl,get64PE((mp)+i+4)+(kp)[i+4],get64PE((mp)+i+5)+(kp)[i+5]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i+4)+(kp)[i+6],get64PE((mp)+i+5)+(kp)[i+7]);\ ADD128(rh1,rl1,th,tl); \ MUL64(th,tl,get64PE((mp)+i+6)+(kp)[i+6],get64PE((mp)+i+7)+(kp)[i+7]);\ ADD128(rh,rl,th,tl); \ MUL64(th,tl,get64PE((mp)+i+6)+(kp)[i+8],get64PE((mp)+i+7)+(kp)[i+9]);\ ADD128(rh1,rl1,th,tl); \ } \ } #endif #define poly_step(ah, al, kh, kl, mh, ml) \ { uint64_t t1h, t1l, t2h, t2l, t3h, t3l, z=0; \ /* compute ab*cd, put bd into result registers */ \ PMUL64(t3h,t3l,al,kh); \ PMUL64(t2h,t2l,ah,kl); \ PMUL64(t1h,t1l,ah,2*kh); \ PMUL64(ah,al,al,kl); \ /* add 2 * ac to result */ \ ADD128(ah,al,t1h,t1l); \ /* add together ad + bc */ \ ADD128(t2h,t2l,t3h,t3l); \ /* now (ah,al), (t2l,2*t2h) need summing */ \ /* first add the high registers, carrying into t2h */ \ ADD128(t2h,ah,z,t2l); \ /* double t2h and add top bit of ah */ \ t2h = 2 * t2h + (ah >> 63); \ ah &= m63; \ /* now add the low registers */ \ ADD128(ah,al,mh,ml); \ ADD128(ah,al,z,t2h); \ } /* ----------------------------------------------------------------------- */ #elif VMAC_USE_SSE2 /* ----------------------------------------------------------------------- */ // macros from Crypto++ for sharing inline assembly code between MSVC and GNU C #if defined(__GNUC__) // define these in two steps to allow arguments to be expanded #define GNU_AS2(x, y) #x ", " #y ";" #define GNU_AS3(x, y, z) #x ", " #y ", " #z ";" #define GNU_ASL(x) "\n" #x ":" #define GNU_ASJ(x, y, z) #x " " #y #z ";" #define AS2(x, y) GNU_AS2(x, y) #define AS3(x, y, z) GNU_AS3(x, y, z) #define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";" #define ASL(x) GNU_ASL(x) #define ASJ(x, y, z) GNU_ASJ(x, y, z) #else #define AS2(x, y) __asm {x, y} #define AS3(x, y, z) __asm {x, y, z} #define ASS(x, y, a, b, c, d) __asm {x, y, _MM_SHUFFLE(a, b, c, d)} #define ASL(x) __asm {label##x:} #define ASJ(x, y, z) __asm {x label##y} #endif static void NOINLINE nh_16_func(const uint64_t *mp, const uint64_t *kp, size_t nw, uint64_t *rh, uint64_t *rl) { // This assembly version, using MMX registers, is just as fast as the // intrinsics version (which uses XMM registers) on the Intel Core 2, // but is much faster on the Pentium 4. In order to schedule multiplies // as early as possible, the loop interleaves operations for the current // block and the next block. To mask out high 32-bits, we use "movd" // to move the lower 32-bits to the stack and then back. Surprisingly, // this is faster than any other method. #ifdef __GNUC__ __asm__ __volatile__ ( ".intel_syntax noprefix;" #else AS2( mov esi, mp) AS2( mov edi, kp) AS2( mov ecx, nw) AS2( mov eax, rl) AS2( mov edx, rh) #endif AS2( sub esp, 12) AS2( movq mm6, [esi]) AS2( paddq mm6, [edi]) AS2( movq mm5, [esi+8]) AS2( paddq mm5, [edi+8]) AS2( add esi, 16) AS2( add edi, 16) AS2( movq mm4, mm6) ASS( pshufw mm2, mm6, 1, 0, 3, 2) AS2( pmuludq mm6, mm5) ASS( pshufw mm3, mm5, 1, 0, 3, 2) AS2( pmuludq mm5, mm2) AS2( pmuludq mm2, mm3) AS2( pmuludq mm3, mm4) AS2( pxor mm7, mm7) AS2( movd [esp], mm6) AS2( psrlq mm6, 32) AS2( movd [esp+4], mm5) AS2( psrlq mm5, 32) AS2( sub ecx, 2) ASJ( jz, 1, f) ASL(0) AS2( movq mm0, [esi]) AS2( paddq mm0, [edi]) AS2( movq mm1, [esi+8]) AS2( paddq mm1, [edi+8]) AS2( add esi, 16) AS2( add edi, 16) AS2( movq mm4, mm0) AS2( paddq mm5, mm2) ASS( pshufw mm2, mm0, 1, 0, 3, 2) AS2( pmuludq mm0, mm1) AS2( movd [esp+8], mm3) AS2( psrlq mm3, 32) AS2( paddq mm5, mm3) ASS( pshufw mm3, mm1, 1, 0, 3, 2) AS2( pmuludq mm1, mm2) AS2( pmuludq mm2, mm3) AS2( pmuludq mm3, mm4) AS2( movd mm4, [esp]) AS2( paddq mm7, mm4) AS2( movd mm4, [esp+4]) AS2( paddq mm6, mm4) AS2( movd mm4, [esp+8]) AS2( paddq mm6, mm4) AS2( movd [esp], mm0) AS2( psrlq mm0, 32) AS2( paddq mm6, mm0) AS2( movd [esp+4], mm1) AS2( psrlq mm1, 32) AS2( paddq mm5, mm1) AS2( sub ecx, 2) ASJ( jnz, 0, b) ASL(1) AS2( paddq mm5, mm2) AS2( movd [esp+8], mm3) AS2( psrlq mm3, 32) AS2( paddq mm5, mm3) AS2( movd mm4, [esp]) AS2( paddq mm7, mm4) AS2( movd mm4, [esp+4]) AS2( paddq mm6, mm4) AS2( movd mm4, [esp+8]) AS2( paddq mm6, mm4) ASS( pshufw mm0, mm7, 3, 2, 1, 0) AS2( psrlq mm7, 32) AS2( paddq mm6, mm7) AS2( punpckldq mm0, mm6) AS2( psrlq mm6, 32) AS2( paddq mm5, mm6) AS2( movq [eax], mm0) AS2( movq [edx], mm5) AS2( add esp, 12) #ifdef __GNUC__ ".att_syntax prefix;" : : "S" (mp), "D" (kp), "c" (nw), "a" (rl), "d" (rh) : "memory", "cc" ); #endif } #define nh_16(mp, kp, nw, rh, rl) nh_16_func(mp, kp, nw, &(rh), &(rl)); static void poly_step_func(uint64_t *ahi, uint64_t *alo, const uint64_t *kh, const uint64_t *kl, const uint64_t *mh, const uint64_t *ml) { // This code tries to schedule the multiplies as early as possible to overcome // the long latencies on the Pentium 4. It also minimizes "movq" instructions // which are very expensive on the P4. #define a0 [eax+0] #define a1 [eax+4] #define a2 [ebx+0] #define a3 [ebx+4] #define k0 [ecx+0] #define k1 [ecx+4] #define k2 [edx+0] #define k3 [edx+4] #ifdef __GNUC__ uint32_t temp; __asm__ __volatile__ ( "mov %%ebx, %0;" "mov %1, %%ebx;" ".intel_syntax noprefix;" #else AS2( mov ebx, ahi) AS2( mov edx, kh) AS2( mov eax, alo) AS2( mov ecx, kl) AS2( mov esi, mh) AS2( mov edi, ml) #endif AS2( movd mm0, a3) AS2( movq mm4, mm0) AS2( pmuludq mm0, k3) // a3*k3 AS2( movd mm1, a0) AS2( pmuludq mm1, k2) // a0*k2 AS2( movd mm2, a1) AS2( movd mm6, k1) AS2( pmuludq mm2, mm6) // a1*k1 AS2( movd mm3, a2) AS2( movq mm5, mm3) AS2( movd mm7, k0) AS2( pmuludq mm3, mm7) // a2*k0 AS2( pmuludq mm4, mm7) // a3*k0 AS2( pmuludq mm5, mm6) // a2*k1 AS2( psllq mm0, 1) AS2( paddq mm0, [esi]) AS2( paddq mm0, mm1) AS2( movd mm1, a1) AS2( paddq mm4, mm5) AS2( movq mm5, mm1) AS2( pmuludq mm1, k2) // a1*k2 AS2( paddq mm0, mm2) AS2( movd mm2, a0) AS2( paddq mm0, mm3) AS2( movq mm3, mm2) AS2( pmuludq mm2, k3) // a0*k3 AS2( pmuludq mm3, mm7) // a0*k0 AS2( movd esi, mm0) AS2( psrlq mm0, 32) AS2( pmuludq mm7, mm5) // a1*k0 AS2( pmuludq mm5, k3) // a1*k3 AS2( paddq mm0, mm1) AS2( movd mm1, a2) AS2( pmuludq mm1, k2) // a2*k2 AS2( paddq mm0, mm2) AS2( paddq mm0, mm4) AS2( movq mm4, mm0) AS2( movd mm2, a3) AS2( pmuludq mm2, mm6) // a3*k1 AS2( pmuludq mm6, a0) // a0*k1 AS2( psrlq mm0, 31) AS2( paddq mm0, mm3) AS2( movd mm3, [edi]) AS2( paddq mm0, mm3) AS2( movd mm3, a2) AS2( pmuludq mm3, k3) // a2*k3 AS2( paddq mm5, mm1) AS2( movd mm1, a3) AS2( pmuludq mm1, k2) // a3*k2 AS2( paddq mm5, mm2) AS2( movd mm2, [edi+4]) AS2( psllq mm5, 1) AS2( paddq mm0, mm5) AS2( movq mm5, mm0) AS2( psllq mm4, 33) AS2( psrlq mm0, 32) AS2( paddq mm6, mm7) AS2( movd mm7, esi) AS2( paddq mm0, mm6) AS2( paddq mm0, mm2) AS2( paddq mm3, mm1) AS2( psllq mm3, 1) AS2( paddq mm0, mm3) AS2( psrlq mm4, 1) AS2( punpckldq mm5, mm0) AS2( psrlq mm0, 32) AS2( por mm4, mm7) AS2( paddq mm0, mm4) AS2( movq a0, mm5) AS2( movq a2, mm0) #ifdef __GNUC__ ".att_syntax prefix;" "mov %0, %%ebx;" : "=m" (temp) : "m" (ahi), "D" (ml), "d" (kh), "a" (alo), "S" (mh), "c" (kl) : "memory", "cc" ); #endif #undef a0 #undef a1 #undef a2 #undef a3 #undef k0 #undef k1 #undef k2 #undef k3 } #define poly_step(ah, al, kh, kl, mh, ml) \ poly_step_func(&(ah), &(al), &(kh), &(kl), &(mh), &(ml)) /* ----------------------------------------------------------------------- */ #else /* not VMAC_ARCH_64 and not SSE2 */ /* ----------------------------------------------------------------------- */ #ifndef nh_16 #define nh_16(mp, kp, nw, rh, rl) \ { uint64_t t1,t2,m1,m2,t; \ int i; \ rh = rl = t = 0; \ for (i = 0; i < nw; i+=2) { \ t1 = get64PE(mp+i) + kp[i]; \ t2 = get64PE(mp+i+1) + kp[i+1]; \ m2 = MUL32(t1 >> 32, t2); \ m1 = MUL32(t1, t2 >> 32); \ ADD128(rh,rl,MUL32(t1 >> 32,t2 >> 32),MUL32(t1,t2)); \ rh += (uint64_t)(uint32_t)(m1 >> 32) + (uint32_t)(m2 >> 32); \ t += (uint64_t)(uint32_t)m1 + (uint32_t)m2; \ } \ ADD128(rh,rl,(t >> 32),(t << 32)); \ } #endif static void poly_step_func(uint64_t *ahi, uint64_t *alo, const uint64_t *kh, const uint64_t *kl, const uint64_t *mh, const uint64_t *ml) { #if VMAC_ARCH_BIG_ENDIAN #define INDEX_HIGH 0 #define INDEX_LOW 1 #else #define INDEX_HIGH 1 #define INDEX_LOW 0 #endif #define a0 *(((uint32_t*)alo)+INDEX_LOW) #define a1 *(((uint32_t*)alo)+INDEX_HIGH) #define a2 *(((uint32_t*)ahi)+INDEX_LOW) #define a3 *(((uint32_t*)ahi)+INDEX_HIGH) #define k0 *(((uint32_t*)kl)+INDEX_LOW) #define k1 *(((uint32_t*)kl)+INDEX_HIGH) #define k2 *(((uint32_t*)kh)+INDEX_LOW) #define k3 *(((uint32_t*)kh)+INDEX_HIGH) uint64_t p, q, t; uint32_t t2; p = MUL32(a3, k3); p += p; p += *(uint64_t *)mh; p += MUL32(a0, k2); p += MUL32(a1, k1); p += MUL32(a2, k0); t = (uint32_t)(p); p >>= 32; p += MUL32(a0, k3); p += MUL32(a1, k2); p += MUL32(a2, k1); p += MUL32(a3, k0); t |= ((uint64_t)((uint32_t)p & 0x7fffffff)) << 32; p >>= 31; p += (uint64_t)(((uint32_t*)ml)[INDEX_LOW]); p += MUL32(a0, k0); q = MUL32(a1, k3); q += MUL32(a2, k2); q += MUL32(a3, k1); q += q; p += q; t2 = (uint32_t)(p); p >>= 32; p += (uint64_t)(((uint32_t*)ml)[INDEX_HIGH]); p += MUL32(a0, k1); p += MUL32(a1, k0); q = MUL32(a2, k3); q += MUL32(a3, k2); q += q; p += q; *(uint64_t *)(alo) = (p << 32) | t2; p >>= 32; *(uint64_t *)(ahi) = p + t; #undef a0 #undef a1 #undef a2 #undef a3 #undef k0 #undef k1 #undef k2 #undef k3 } #define poly_step(ah, al, kh, kl, mh, ml) \ poly_step_func(&(ah), &(al), &(kh), &(kl), &(mh), &(ml)) /* ----------------------------------------------------------------------- */ #endif /* end of specialized NH and poly definitions */ /* ----------------------------------------------------------------------- */ /* At least nh_16 is defined. Defined others as needed here */ #ifndef nh_16_2 #define nh_16_2(mp, kp, nw, rh, rl, rh2, rl2) \ nh_16(mp, kp, nw, rh, rl); \ nh_16(mp, ((kp)+2), nw, rh2, rl2); #endif #ifndef nh_vmac_nhbytes #define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \ nh_16(mp, kp, nw, rh, rl) #endif #ifndef nh_vmac_nhbytes_2 #define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh2, rl2) \ nh_vmac_nhbytes(mp, kp, nw, rh, rl); \ nh_vmac_nhbytes(mp, ((kp)+2), nw, rh2, rl2); #endif /* ----------------------------------------------------------------------- */ void vhash_abort(vmac_ctx_t *ctx) { ctx->polytmp[0] = ctx->polykey[0] ; ctx->polytmp[1] = ctx->polykey[1] ; #if (VMAC_TAG_LEN == 128) ctx->polytmp[2] = ctx->polykey[2] ; ctx->polytmp[3] = ctx->polykey[3] ; #endif ctx->first_block_processed = 0; } /* ----------------------------------------------------------------------- */ static uint64_t l3hash(uint64_t p1, uint64_t p2, uint64_t k1, uint64_t k2, uint64_t len) { uint64_t rh, rl, t, z=0; /* fully reduce (p1,p2)+(len,0) mod p127 */ t = p1 >> 63; p1 &= m63; ADD128(p1, p2, len, t); /* At this point, (p1,p2) is at most 2^127+(len<<64) */ t = (p1 > m63) + ((p1 == m63) && (p2 == m64)); ADD128(p1, p2, z, t); p1 &= m63; /* compute (p1,p2)/(2^64-2^32) and (p1,p2)%(2^64-2^32) */ t = p1 + (p2 >> 32); t += (t >> 32); t += (uint32_t)t > 0xfffffffeu; p1 += (t >> 32); p2 += (p1 << 32); /* compute (p1+k1)%p64 and (p2+k2)%p64 */ p1 += k1; p1 += (0 - (p1 < k1)) & 257; p2 += k2; p2 += (0 - (p2 < k2)) & 257; /* compute (p1+k1)*(p2+k2)%p64 */ MUL64(rh, rl, p1, p2); t = rh >> 56; ADD128(t, rl, z, rh); rh <<= 8; ADD128(t, rl, z, rh); t += t << 8; rl += t; rl += (0 - (rl < t)) & 257; rl += (0 - (rl > p64-1)) & 257; return rl; } /* ----------------------------------------------------------------------- */ void vhash_update(unsigned char *m, unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */ vmac_ctx_t *ctx) { uint64_t rh, rl, *mptr; const uint64_t *kptr = (uint64_t *)ctx->nhkey; int i; uint64_t ch, cl; uint64_t pkh = ctx->polykey[0]; uint64_t pkl = ctx->polykey[1]; #if (VMAC_TAG_LEN == 128) uint64_t ch2, cl2, rh2, rl2; uint64_t pkh2 = ctx->polykey[2]; uint64_t pkl2 = ctx->polykey[3]; #endif mptr = (uint64_t *)m; i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ ch = ctx->polytmp[0]; cl = ctx->polytmp[1]; #if (VMAC_TAG_LEN == 128) ch2 = ctx->polytmp[2]; cl2 = ctx->polytmp[3]; #endif if ( ! ctx->first_block_processed) { ctx->first_block_processed = 1; #if (VMAC_TAG_LEN == 64) nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl); #else nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,rh,rl,rh2,rl2); rh2 &= m62; ADD128(ch2,cl2,rh2,rl2); #endif rh &= m62; ADD128(ch,cl,rh,rl); mptr += (VMAC_NHBYTES/sizeof(uint64_t)); i--; } while (i--) { #if (VMAC_TAG_LEN == 64) nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl); #else nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,rh,rl,rh2,rl2); rh2 &= m62; poly_step(ch2,cl2,pkh2,pkl2,rh2,rl2); #endif rh &= m62; poly_step(ch,cl,pkh,pkl,rh,rl); mptr += (VMAC_NHBYTES/sizeof(uint64_t)); } ctx->polytmp[0] = ch; ctx->polytmp[1] = cl; #if (VMAC_TAG_LEN == 128) ctx->polytmp[2] = ch2; ctx->polytmp[3] = cl2; #endif #if VMAC_USE_SSE2 _mm_empty(); /* SSE2 version of poly_step uses mmx instructions */ #endif } /* ----------------------------------------------------------------------- */ uint64_t xvhash(unsigned char m[], unsigned int mbytes, uint64_t *tagl, vmac_ctx_t *ctx) { uint64_t ch, cl, rh, rl, *mptr; #if (VMAC_TAG_LEN == 128) uint64_t ch2, cl2, rh2, rl2; #endif const uint64_t *kptr = (uint64_t *)ctx->nhkey; int i, remaining; (void)tagl; remaining = mbytes % VMAC_NHBYTES; i = mbytes-remaining; mptr = (uint64_t *)(m+i); if (i) vhash_update(m,i,ctx); ch = ctx->polytmp[0]; cl = ctx->polytmp[1]; #if (VMAC_TAG_LEN == 128) ch2 = ctx->polytmp[2]; cl2 = ctx->polytmp[3]; #endif if (remaining) { #if (VMAC_TAG_LEN == 128) nh_16_2(mptr,kptr,2*((remaining+15)/16),rh,rl,rh2,rl2); rh2 &= m62; #else nh_16(mptr,kptr,2*((remaining+15)/16),rh,rl); #endif rh &= m62; if (i) { poly_step(ch,cl,ctx->polykey[0],ctx->polykey[1],rh,rl); #if (VMAC_TAG_LEN == 128) poly_step(ch2,cl2,ctx->polykey[2],ctx->polykey[3],rh2,rl2); #endif } else { ADD128(ch,cl,rh,rl); #if (VMAC_TAG_LEN == 128) ADD128(ch2,cl2,rh2,rl2); #endif } } #if VMAC_USE_SSE2 _mm_empty(); /* SSE2 version of poly_step uses mmx instructions */ #endif vhash_abort(ctx); remaining *= 8; #if (VMAC_TAG_LEN == 128) *tagl = l3hash(ch2, cl2, ctx->l3key[2], ctx->l3key[3],remaining); #endif return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1],remaining); } uint64_t vhash(unsigned char m[], unsigned int mbytes, uint64_t *tagl, vmac_ctx_t *ctx) { uint64_t rh, rl, *mptr; const uint64_t *kptr = (uint64_t *)ctx->nhkey; int i, remaining; uint64_t ch, cl; uint64_t pkh = ctx->polykey[0]; uint64_t pkl = ctx->polykey[1]; #if (VMAC_TAG_LEN == 128) uint64_t ch2, cl2, rh2, rl2; uint64_t pkh2 = ctx->polykey[2]; uint64_t pkl2 = ctx->polykey[3]; #endif (void)tagl; mptr = (uint64_t *)m; i = mbytes / VMAC_NHBYTES; remaining = mbytes % VMAC_NHBYTES; if (ctx->first_block_processed) { ch = ctx->polytmp[0]; cl = ctx->polytmp[1]; #if (VMAC_TAG_LEN == 128) ch2 = ctx->polytmp[2]; cl2 = ctx->polytmp[3]; #endif } else if (i) { #if (VMAC_TAG_LEN == 64) nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,ch,cl); #else nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,ch,cl,ch2,cl2); ch2 &= m62; ADD128(ch2,cl2,pkh2,pkl2); #endif ch &= m62; ADD128(ch,cl,pkh,pkl); mptr += (VMAC_NHBYTES/sizeof(uint64_t)); i--; } else if (remaining) { #if (VMAC_TAG_LEN == 64) nh_16(mptr,kptr,2*((remaining+15)/16),ch,cl); #else nh_16_2(mptr,kptr,2*((remaining+15)/16),ch,cl,ch2,cl2); ch2 &= m62; ADD128(ch2,cl2,pkh2,pkl2); #endif ch &= m62; ADD128(ch,cl,pkh,pkl); mptr += (VMAC_NHBYTES/sizeof(uint64_t)); goto do_l3; } else /* Empty String */ { ch = pkh; cl = pkl; #if (VMAC_TAG_LEN == 128) ch2 = pkh2; cl2 = pkl2; #endif goto do_l3; } while (i--) { #if (VMAC_TAG_LEN == 64) nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl); #else nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,rh,rl,rh2,rl2); rh2 &= m62; poly_step(ch2,cl2,pkh2,pkl2,rh2,rl2); #endif rh &= m62; poly_step(ch,cl,pkh,pkl,rh,rl); mptr += (VMAC_NHBYTES/sizeof(uint64_t)); } if (remaining) { #if (VMAC_TAG_LEN == 64) nh_16(mptr,kptr,2*((remaining+15)/16),rh,rl); #else nh_16_2(mptr,kptr,2*((remaining+15)/16),rh,rl,rh2,rl2); rh2 &= m62; poly_step(ch2,cl2,pkh2,pkl2,rh2,rl2); #endif rh &= m62; poly_step(ch,cl,pkh,pkl,rh,rl); } do_l3: #if VMAC_USE_SSE2 _mm_empty(); /* SSE2 version of poly_step uses mmx instructions */ #endif vhash_abort(ctx); remaining *= 8; #if (VMAC_TAG_LEN == 128) *tagl = l3hash(ch2, cl2, ctx->l3key[2], ctx->l3key[3],remaining); #endif return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1],remaining); } /* ----------------------------------------------------------------------- */ uint64_t vmac(unsigned char m[], unsigned int mbytes, unsigned char n[16], uint64_t *tagl, vmac_ctx_t *ctx) { #if (VMAC_TAG_LEN == 64) uint64_t *in_n, *out_p; uint64_t p, h; int i; (void)tagl; #if VMAC_CACHE_NONCES in_n = ctx->cached_nonce; out_p = ctx->cached_aes; #else uint64_t tmp[2]; in_n = out_p = tmp; #endif i = n[15] & 1; #if VMAC_CACHE_NONCES if ((*(uint64_t *)(n+8) != in_n[1]) || (*(uint64_t *)(n ) != in_n[0])) { #endif in_n[0] = *(uint64_t *)(n ); in_n[1] = *(uint64_t *)(n+8); ((unsigned char *)in_n)[15] &= 0xFE; aes_encryption(in_n, out_p, &ctx->cipher_key); #if VMAC_CACHE_NONCES ((unsigned char *)in_n)[15] |= (unsigned char)(1-i); } #endif p = get64BE(out_p + i); h = vhash(m, mbytes, (uint64_t *)0, ctx); return p + h; #else uint64_t tmp[2]; uint64_t th,tl; aes_encryption(n, (unsigned char *)tmp, &ctx->cipher_key); th = vhash(m, mbytes, &tl, ctx); th += get64BE(tmp); *tagl = tl + get64BE(tmp+1); return th; #endif } /* ----------------------------------------------------------------------- */ void vmac_set_key(unsigned char user_key[], vmac_ctx_t *ctx) { uint64_t in[2] = {0}, out[2]; unsigned i; aes_key_setup(user_key, &ctx->cipher_key); /* Fill nh key */ ((unsigned char *)in)[0] = 0x80; for (i = 0; i < sizeof(ctx->nhkey)/8; i+=2) { aes_encryption((unsigned char *)in, (unsigned char *)out, &ctx->cipher_key); ctx->nhkey[i ] = get64BE(out); ctx->nhkey[i+1] = get64BE(out+1); ((unsigned char *)in)[15] += 1; } /* Fill poly key */ ((unsigned char *)in)[0] = 0xC0; in[1] = 0; for (i = 0; i < sizeof(ctx->polykey)/8; i+=2) { aes_encryption((unsigned char *)in, (unsigned char *)out, &ctx->cipher_key); ctx->polytmp[i ] = ctx->polykey[i ] = get64BE(out) & mpoly; ctx->polytmp[i+1] = ctx->polykey[i+1] = get64BE(out+1) & mpoly; ((unsigned char *)in)[15] += 1; } /* Fill ip key */ ((unsigned char *)in)[0] = 0xE0; in[1] = 0; for (i = 0; i < sizeof(ctx->l3key)/8; i+=2) { do { aes_encryption((unsigned char *)in, (unsigned char *)out, &ctx->cipher_key); ctx->l3key[i ] = get64BE(out); ctx->l3key[i+1] = get64BE(out+1); ((unsigned char *)in)[15] += 1; } while (ctx->l3key[i] >= p64 || ctx->l3key[i+1] >= p64); } /* Invalidate nonce/aes cache and reset other elements */ #if (VMAC_TAG_LEN == 64) && (VMAC_CACHE_NONCES) ctx->cached_nonce[0] = (uint64_t)-1; /* Ensure illegal nonce */ ctx->cached_nonce[1] = (uint64_t)0; /* Ensure illegal nonce */ #endif ctx->first_block_processed = 0; } /* ----------------------------------------------------------------------- */ #if VMAC_RUN_TESTS #include #include #include #include unsigned prime(void) /* Wake variable speed cpu, get rough speed estimate */ { volatile uint64_t i; volatile uint64_t j=1; unsigned cnt=0; volatile clock_t ticks = clock(); do { for (i = 0; i < 500000; i++) { uint64_t x = get64PE(&j); j = x * x + (uint64_t)ticks; } cnt++; } while (clock() - ticks < (CLOCKS_PER_SEC/2)); return cnt; /* cnt is millions of iterations per second */ } int main(void) { ALIGN(16) vmac_ctx_t ctx, ctx_aio, ctx_inc1, ctx_inc2; uint64_t res, tagl; void *p; unsigned char *m; ALIGN(4) unsigned char key[] = "abcdefghijklmnop"; ALIGN(4) unsigned char nonce[] = "\0\0\0\0\0\0\0\0bcdefghi"; unsigned int vector_lengths[] = {0,3,48,300,3000000}; #if (VMAC_TAG_LEN == 64) ALIGN(4) char *should_be[] = {"2576BE1C56D8B81B","2D376CF5B1813CE5", "E8421F61D573D298","4492DF6C5CAC1BBE", "09BA597DD7601113"}; #else ALIGN(4) char *should_be[] = {"472766C70F74ED23481D6D7DE4E80DAC", "4EE815A06A1D71EDD36FC75D51188A42", "09F2C80C8E1007A0C12FAE19FE4504AE", "66438817154850C61D8A412164803BCB", "2B6B02288FFC461B75485DE893C629DC"}; #endif unsigned speed_lengths[] = {16, 32, 64, 128, 256, 512, 1024, 2048, 4096}; unsigned i, j, *speed_iters; clock_t ticks; double cpb; const unsigned int buf_len = 3 * (1 << 20); j = prime(); i = sizeof(speed_lengths)/sizeof(speed_lengths[0]); speed_iters = (unsigned *)malloc(i*sizeof(speed_iters[0])); speed_iters[i-1] = j * (1 << 12); while (--i) speed_iters[i-1] = (unsigned)(1.3 * speed_iters[i]); /* Initialize context and message buffer, all 16-byte aligned */ p = malloc(buf_len + 32); m = (unsigned char *)(((size_t)p + 16) & ~((size_t)15)); memset(m, 0, buf_len + 16); vmac_set_key(key, &ctx); /* Test incremental and all-in-one interfaces for correctness */ vmac_set_key(key, &ctx_aio); vmac_set_key(key, &ctx_inc1); vmac_set_key(key, &ctx_inc2); /* for (i = 0; i <= 512; i++) { vhash_update(m,(i/VMAC_NHBYTES)*VMAC_NHBYTES,&ctx_inc1); tagh = vmac(m+(i/VMAC_NHBYTES)*VMAC_NHBYTES, i%VMAC_NHBYTES, nonce, &tagl, &ctx); vhash_update(m,(i/VMAC_NHBYTES)*VMAC_NHBYTES,&ctx_inc1); for (j = 0; j < vector_lengths[i]; j++) m[j] = (unsigned char)('a'+j%3); } */ /* Generate vectors */ for (i = 0; i < sizeof(vector_lengths)/sizeof(unsigned int); i++) { for (j = 0; j < vector_lengths[i]; j++) m[j] = (unsigned char)('a'+j%3); res = vmac(m, vector_lengths[i], nonce, &tagl, &ctx); #if (VMAC_TAG_LEN == 64) printf("\'abc\' * %7u: %016llX Should be: %s\n", vector_lengths[i]/3,res,should_be[i]); #else printf("\'abc\' * %7u: %016llX%016llX\nShould be : %s\n", vector_lengths[i]/3,res,tagl,should_be[i]); #endif } /* Speed test */ for (i = 0; i < sizeof(speed_lengths)/sizeof(unsigned int); i++) { ticks = clock(); for (j = 0; j < speed_iters[i]; j++) { #if HASH_ONLY res = vhash(m, speed_lengths[i], &tagl, &ctx); #else res = vmac(m, speed_lengths[i], nonce, &tagl, &ctx); nonce[7]++; #endif } ticks = clock() - ticks; cpb = ((ticks*VMAC_HZ)/ ((double)CLOCKS_PER_SEC*speed_lengths[i]*speed_iters[i])); printf("%4u bytes, %2.2f cpb\n", speed_lengths[i], cpb); } return 1; } #endif tboot-1.8.2/tboot/common/boot.S0000644000175000017500000002757512365404265014612 0ustar rqwrqw/* * 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 4096 #define AP_STACK_SIZE 1024 #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 .section ".tboot_multiboot_header","w" .align 4 /* 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)) multiboot2_header_end: /* tag requests here--RLM, fix me!! Well, maybe! */ .short MB2_HDR_TAG_END .short 0 .long 8 .text ENTRY(start) ENTRY(_start) ENTRY(_stext) 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 /* * 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 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 # spin hlt if we exceed, since C code can't handle shared stack cmp $NR_CPUS, %ebx 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 %ebx 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.8.2/tboot/common/strcmp.c0000644000175000017500000000364312365404266015166 0ustar rqwrqw/*- * 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 strcmp(s1, s2) register const char *s1, *s2; { while (*s1 == *s2++) if (*s1++ == 0) return (0); return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); } tboot-1.8.2/tboot/common/e820.c0000644000175000017500000006435512365404265014342 0ustar rqwrqw/* * 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 /* 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 efi_memory_desc_t *efi_memmap_addr = NULL; static uint32_t efi_memmap_size = 0; 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 ) { 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 ( 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 */ void 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; 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; } } } *ram_base = last_fit_base; *ram_size = last_fit_size; } #define PAGE_4K (1 << 12) efi_memory_desc_t *get_efi_memmap(uint32_t *memmap_size) { unsigned int i; memory_map_t *mp; efi_memory_desc_t *ep; uint32_t space_required; if (efi_memmap_addr == NULL){ /* we haven't done the conversion yet--is there room? */ space_required = sizeof(memory_map_t) * g_nr_map + sizeof(efi_memory_desc_t) * g_nr_map + 0xf; if (space_required >= TBOOT_E820_COPY_SIZE){ printk(TBOOT_ERR "Insufficient space to make EFI copy of E820 [%d => %d]\n", space_required, TBOOT_E820_COPY_SIZE); return NULL; } /* for fun, we'll align the entries to 0x10 */ ep = efi_memmap_addr = (efi_memory_desc_t *) ((TBOOT_E820_COPY_ADDR + sizeof(memory_map_t) * g_nr_map + 0xf) & ~0xf); /* printk(TBOOT_INFO"efi memmap base now at %p\n", ep); */ mp = g_copy_e820_map; for (i = 0; i < g_nr_map; i++){ uint64_t length; ep[i].phys_addr = ep[i].virt_addr = e820_base_64(mp + i); ep[i].pad = 0; length = e820_length_64(mp + i); length += PAGE_4K - 1; length &= ~(PAGE_4K - 1); ep[i].num_pages = length / PAGE_4K; switch (mp[i].type){ case E820_RAM: ep[i].type = EFI_CONVENTIONAL_MEMORY; ep[i].attribute |= EFI_MEMORY_WB; break; case E820_ACPI: ep[i].type = EFI_ACPI_RECLAIM_MEMORY; break; case E820_NVS: ep[i].type = EFI_ACPI_MEMORY_NVS; break; case E820_UNUSABLE: ep[i].type = EFI_UNUSABLE_MEMORY; break; case E820_GAP: case E820_MIXED: case E820_RESERVED: default: ep[i].type = EFI_RESERVED_TYPE; break; } /* printk(TBOOT_INFO "EFI entry %d at %016Lx type %d with %Lx pages\n", i, ep[i].phys_addr, ep[i].type, ep[i].num_pages); */ efi_memmap_size += sizeof(efi_memory_desc_t); } } *memmap_size = efi_memmap_size; return efi_memmap_addr; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/common/vsprintf.c0000644000175000017500000003476512365404266015542 0ustar rqwrqw/* * 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; 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 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; 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 = 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 = 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, 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, 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; 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 snprintf(char *buf, size_t size, const char *fmt, ...) { va_list ap; va_start(ap, fmt); int count = 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.8.2/tboot/Config.mk0000644000175000017500000000277512365404265013764 0ustar rqwrqw# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tboot-specific build settings # 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,) # changeset variable for banner CFLAGS += -DTBOOT_CHANGESET=\""$(shell ((hg parents --template "{isodate|isodate} {rev}:{node|short}" >/dev/null && hg parents --template "{isodate|isodate} {rev}:{node|short}") || echo "2014-07-28 12:00 +0800 1.8.2") 2>/dev/null)"\" 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.8.2/tboot/txt/0000755000175000017500000000000012365404267013034 5ustar rqwrqwtboot-1.8.2/tboot/txt/heap.c0000644000175000017500000006727112365404266014131 0ustar rqwrqw/* * 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 #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); } 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; } /* 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]); } 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; } /* 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"); } 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; } /* 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 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 ( 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 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); } 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); } 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 ) { 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"); } 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; 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 bool verify_evt_log_ptr_elt_2(const heap_ext_data_element_t *elt) { if ( !elt ) return false; return true; } 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; default: printk(TBOOT_WARN"\t\t unknown element: type: %u, size: %u\n", elt->type, elt->size); break; } elt = (void *)elt + elt->size; } } 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; } 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); if ( bios_data->version >= 4 && size > sizeof(*bios_data) + sizeof(size) ) print_ext_data_elts(bios_data->ext_data_elts); } 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 > 4 ) printk(TBOOT_WARN"unsupported BIOS data version (%u)\n", bios_data->version); /* all TXT-capable CPUs support at least 2 cores */ if ( bios_data->num_logical_procs < 2 ) { 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; } #ifndef IS_INCLUDED 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) }; if ( g_tpm->major == TPM20_VER_MAJOR ) { u32 count; if ( g_tpm->extpol == TB_EXTPOL_AGILE ) count = g_tpm->banks; else if ( g_tpm->extpol == TB_EXTPOL_EMBEDDED ) count = g_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(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); 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); 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 */ sinit_mle_data = get_sinit_mle_data_start(txt_heap); 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.8.2/tboot/txt/errors.c0000644000175000017500000002251712365404266014522 0ustar rqwrqw/* * 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 static void 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 (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009) 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_get_error(void) { txt_errorcode_t err; display_errors(); err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); if ( err.valid ) 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.8.2/tboot/txt/acmod.c0000644000175000017500000010032412365404266014262 0ustar rqwrqw/* * 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 txt-test/dump-acm.c */ #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_t)) ) { printk(TBOOT_ERR"id_list_off plus acm_chipset_id_t size overflows\n"); return NULL; } /* check that chipset id table is w/in ACM */ if ( id_list_off + sizeof(acm_chipset_id_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_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_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_t)) ) { printk(TBOOT_ERR"id_list_off plus acm_processor_id_t size overflows\n"); return NULL; } /* check that processor id table is w/in ACM */ if ( id_list_off + sizeof(acm_processor_id_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_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_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); } 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 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); /* 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 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 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)=%x\n", acmod_size, (uint32_t)sizeof(acm_hdr) ); 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 ( acmod_size != acm_hdr->size * 4 ) { if ( !quiet ) printk(TBOOT_ERR"\t ACM size is too small: 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 > 5 ) { 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 */ /* 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 */ acm_info_table_t *info_table = get_acmod_info_table(hdr); if ( info_table == NULL ) return false; 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) { 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 */ 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; } /* copy it there */ 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 */ 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; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/tboot/txt/mtrrs.c0000644000175000017500000004617012365404266014356 0ustar rqwrqw/* * 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); 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.8.2/tboot/txt/txt.c0000644000175000017500000012244012365404266014021 0ustar rqwrqw/* * 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 /* counter timeout for waiting for all APs to enter wait-for-sipi */ #define AP_WFS_TIMEOUT 0x01000000 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); /* * 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=%x, end=%x, size=%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; 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; /* 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; 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; } 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()); switch (g_tpm->extpol) { case TB_EXTPOL_AGILE: for (i=0; icount; i++) { evt_log->event_log_descr[i].alg = g_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; if (g_tpm->algs_banks[i] != TB_HALG_SHA1) { evt_log->event_log_descr[i].pcr_events_offset = 32 + sizeof(tpm20_log_descr_t); evt_log->event_log_descr[i].next_event_offset = 32 + sizeof(tpm20_log_descr_t); } } break; case TB_EXTPOL_EMBEDDED: for (i=0; icount; i++) { evt_log->event_log_descr[i].alg = g_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; if (g_tpm->algs[i] != TB_HALG_SHA1) { evt_log->event_log_descr[i].pcr_events_offset = 32 + sizeof(tpm20_log_descr_t); evt_log->event_log_descr[i].next_event_offset = 32 + sizeof(tpm20_log_descr_t); } } break; case TB_EXTPOL_FIXED: evt_log->event_log_descr[0].alg = g_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; if (g_tpm->cur_alg != TB_HALG_SHA1) { evt_log->event_log_descr[0].pcr_events_offset = 32 + sizeof(tpm20_log_descr_t); evt_log->event_log_descr[0].next_event_offset = 32 + sizeof(tpm20_log_descr_t); } break; default: return; } } 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; if ( g_tpm->major == TPM12_VER_MAJOR ) { 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 ( g_tpm->major == TPM20_VER_MAJOR ) { g_elog_2 = (heap_event_log_ptr_elt2_t *)elt->data; if ( g_tpm->extpol == TB_EXTPOL_AGILE ) g_elog_2->count = g_tpm->banks; else if ( g_tpm->extpol == TB_EXTPOL_EMBEDDED ) g_elog_2->count = g_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); } 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; 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; 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_tpm20(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); memcpy((uint8_t *)next, hash, hash_size); next += hash_size/sizeof(uint32_t); *((u32 *)next) = 0; cur_desc->next_event_offset += 3*sizeof(uint32_t) + hash_size; print_event_2(cur, alg); return true; } bool evtlog_append(uint8_t pcr, hash_list_t *hl, uint32_t type) { switch (g_tpm->major) { case TPM12_VER_MAJOR: evtlog_append_tpm12(pcr, &hl->entries[0].hash, type); break; case TPM20_VER_MAJOR: for (unsigned int i=0; icount; i++) evtlog_append_tpm20(pcr, hl->entries[i].alg, &hl->entries[i].hash, type); break; default: return false; } return true; } __data uint32_t g_using_da = 0; __data acm_hdr_t *g_sinit = 0; /* * 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; 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); 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); 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; } 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; 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; } /* 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 */ os_sinit_data->efi_rsdt_ptr = (uint64_t)((uint32_t) 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() ) 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 ( g_tpm->major >= TPM20_VER_MAJOR ) { os_sinit_data->flags = (g_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 on BSP\n"); __getsec_smctrl(); 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; /* 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)); /* set MTRRs properly for AC module (SINIT) */ if ( !set_mtrrs_for_acmod(g_sinit) ) return TB_ERR_FATAL; 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 */ /* initialize event log in os_sinit_data, so that events will not */ /* repeat when s3 */ if ( g_tpm->major == TPM12_VER_MAJOR && g_elog ) g_elog = (event_log_container_t *)init_event_log(); else if ( g_tpm->major == TPM20_VER_MAJOR && g_elog_2 ) init_evtlog_desc(g_elog_2); /* get sinit binary loaded */ g_sinit = (acm_hdr_t *)(uint32_t)read_pub_config_reg(TXTCR_SINIT_BASE); if ( g_sinit == NULL ) return false; /* 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); /* 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(...); /* 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 */ printk(TBOOT_DETA"enabling SMIs on cpu %u\n", cpuid); __getsec_smctrl(); 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; /* 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; /* 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; /* 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; } 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.8.2/tboot/txt/verify.c0000644000175000017500000004653012365404266014513 0ustar rqwrqw/* * 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 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); 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 ( 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; } 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 */ 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(&tmp_os_sinit_data); print_os_sinit_data(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; /* 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++ ) { 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 )) ) { memcpy(&tmp_entry, &mdrs_base[j], sizeof(sinit_mdr_t)); pos = j; } } if ( pos > i ) { memcpy(&mdrs_base[pos], &mdrs_base[i], sizeof(sinit_mdr_t)); 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.8.2/tboot/txt/vmcs.c0000644000175000017500000004401712365404267014156 0ustar rqwrqw/* * 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");*/ 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]; 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, exit_reason=%x.\n", 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.8.2/include/0000755000175000017500000000000012365404264012506 5ustar rqwrqwtboot-1.8.2/include/tb_error.h0000644000175000017500000000713612365404264014504 0ustar rqwrqw/* * 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_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_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.8.2/include/lcp.h0000644000175000017500000000762312365404264013445 0ustar rqwrqw/* * 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.8.2/include/mle.h0000644000175000017500000000611612365404264013440 0ustar rqwrqw/* * 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 reserved1 : 23; }; } 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 0x00000027 /* rlp_wake_{getsec, monitor} = 1, ecx_pgtbl = 1, nolg = 0, da = 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.8.2/include/hash.h0000644000175000017500000001027212365404264013604 0ustar rqwrqw/* * 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]; } 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 { static char buf[32]; snprintf(buf, sizeof(buf), "unsupported (%u)", hash_alg); return buf; } } 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 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.8.2/include/uuid.h0000644000175000017500000000522412365404264013630 0ustar rqwrqw/* * 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 (memcmp(uuid1, uuid2, sizeof(*uuid1)) == 0); } #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.8.2/include/tboot.h0000644000175000017500000001471312365404264014014 0ustar rqwrqw/* * 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 */ typedef struct { uuid_t uuid; uint32_t max_size; uint32_t curr_pos; 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); } 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); } #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.8.2/include/elf_defns.h0000644000175000017500000001164112365404264014607 0ustar rqwrqw/* * 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; /* 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 */ /* 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; /* 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.8.2/include/tb_policy.h0000644000175000017500000003156512365404264014655 0ustar rqwrqw/* * 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 { static char buf[32]; snprintf(buf, sizeof(buf), "unsupported (%u)", hash_type); return buf; } } 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 { static char buf[32]; snprintf(buf, sizeof(buf), "unsupported (%u)", policy_type); return buf; } } static inline const char *policy_control_to_string(uint32_t policy_control) { static char buf[64] = ""; if ( policy_control & TB_POLCTL_EXTEND_PCR17 ) strncpy(buf, "EXTEND_PCR17", sizeof(buf)); return buf; } 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.8.2/include/lcp_hlp.h0000644000175000017500000000504512365404264014304 0ustar rqwrqw/* * 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.8.2/include/lcp3_hlp.h0000644000175000017500000000763712365404264014400 0ustar rqwrqw/* * 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 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) return offsetof(lcp_ecc_signature_t, qx) + 2*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; } #endif /* __TXT_LCP3_HELPER_H__ */ tboot-1.8.2/include/lcp2.h0000644000175000017500000001313112365404264013516 0ustar rqwrqw/* * 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.8.2/include/lcp3.h0000644000175000017500000002115612365404264013525 0ustar rqwrqw/* * 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" /*--------- LCP Policy Type ------------*/ #define LCP_POLTYPE_LIST 0 #define LCP_POLTYPE_ANY 1 #define LCP_DEFAULT_POLICY_VERSION 0x0300 #define LCP_DEFAULT_POLICY_CONTROL 0x00 #define LCP_MAX_LISTS 8 /*--------- 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; #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_POLELT_TYPE_CUSTOM 3 typedef struct __packed { uuid_t uuid; uint8_t data[]; } lcp_custom_element_t; #define LCP_DEFAULT_POLICY_LIST_VERSION 0x0200 #define LCP_TPM12_POLICY_LIST_VERSION 0x0100 #define LCP_TPM20_POLICY_LIST_VERSION 0x0200 typedef struct __packed { uint16_t version; /* = 1.0 */ 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; #define LCP_DEFAULT_POLICY_VERSION_2 0x0202 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; /*--------- LCP_POLICY version 3.0 ------------*/ #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_RSASSA 0x0014 #define TPM_ALG_ECDSA 0x0018 #define TPM_ALG_SM2 0x001B #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 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 prc_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 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.0 */ 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 */ 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 */ 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; typedef union __packed { lcp_policy_list_t tpm12_policy_list; lcp_policy_list_t2 tpm20_policy_list; } 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; #endif /* __LCP_H__ */ tboot-1.8.2/include/config.h0000644000175000017500000001003512365404264014123 0ustar rqwrqw/* * 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 VMM/kernel command line */ #define TBOOT_KERNEL_CMDLINE_ADDR (TBOOT_E820_COPY_ADDR + \ TBOOT_E820_COPY_SIZE) #define TBOOT_KERNEL_CMDLINE_SIZE 0x0400 #ifndef NR_CPUS #define NR_CPUS 512 #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 */ #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.8.2/.hgignore0000644000175000017500000000135112365404264012666 0ustar rqwrqw.*\.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$ ^lcptools/tpmnv_defindex$ ^lcptools/tpmnv_getcap$ ^lcptools/tpmnv_lock$ ^lcptools/tpmnv_relindex$ ^lcptools/lcp_crtpconf$ ^lcptools/lcp_crtpol$ ^lcptools/lcp_mlehash$ ^lcptools/lcp_readpol$ ^lcptools/lcp_writepol$ ^lcptools/lcp_crtpol2$ ^lcptools/lcp_crtpolelt$ ^lcptools/lcp_crtpollist$ ^lcptools/trousers_dep$ ^tb_polgen/tb_polgen$ ^utils/acminfo$ ^utils/txt-stat$ ^utils/parse_err$ tboot-1.8.2/docs/0000755000175000017500000000000012365404264012013 5ustar rqwrqwtboot-1.8.2/docs/policy_v2.txt0000644000175000017500000000621412365404264014465 0ustar rqwrqw**************************************************************************** *** *** *** 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 tboot/ directory: Create LCP policy: ----------------- o See the file lcptools/lcptools2.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.8.2/docs/policy_v1.txt0000644000175000017500000000643712365404264014473 0ustar rqwrqw**************************************************************************** *** *** *** 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 tboot/ 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.8.2/docs/Makefile0000644000175000017500000000071612365404264013457 0ustar rqwrqw# Copyright (c) 2012, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # docs makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk MANPATH ?= $(DISTDIR)/usr/share/man # # universal rules # build : dist : install install : [ -d $(MANPATH)/man8 ] || $(INSTALL_DIR) $(MANPATH)/man8 $(INSTALL_DATA) -t $(MANPATH)/man8 man/*.8* clean : mrproper : clean distclean : clean # # dependencies # # # implicit rules # tboot-1.8.2/docs/man/0000755000175000017500000000000012365404264012566 5ustar rqwrqwtboot-1.8.2/docs/man/lcp_crtpolelt.80000644000175000017500000000516412365404264015533 0ustar rqwrqw.\" .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.8.2/docs/man/lcp_crtpol2.80000644000175000017500000000320112365404264015076 0ustar rqwrqw.\" .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] breif 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.8.2/docs/man/lcp_mlehash.80000644000175000017500000000242212365404264015136 0ustar rqwrqw.\" .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.8.2/docs/man/lcp_crtpconf.80000644000175000017500000000141212365404264015331 0ustar rqwrqw.\" .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.8.2/docs/man/lcp_crtpollist.80000644000175000017500000000560612365404264015723 0ustar rqwrqw.\" .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.8.2/docs/man/lcp_writepol.80000644000175000017500000000237512365404264015371 0ustar rqwrqw.\" .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.8.2/docs/man/txt-stat.80000644000175000017500000000100412365404264014442 0ustar rqwrqw.\" .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.8.2/docs/man/tb_polgen.80000644000175000017500000000610512365404264014632 0ustar rqwrqw.\" .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 \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.8.2/docs/man/lcp_readpol.80000644000175000017500000000250712365404264015147 0ustar rqwrqw.\" .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.8.2/docs/man/lcp_crtpol.80000644000175000017500000000454312365404264015026 0ustar rqwrqw.\" .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.8.2/docs/man/acminfo.80000644000175000017500000000061412365404264014274 0ustar rqwrqw.\" .TH ACMINFO 8 "2011-12-31" "tboot" "User Manuals" .SH NAME acminfo \- display the header info of a TXT ACM .SH SYNOPSIS .B acminfo .I acm-file-name .SH DESCRIPTION .B 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 \fBacminfo \fIi7_QUAD_SINIT_20.BIN tboot-1.8.2/docs/txt-info.txt0000644000175000017500000000124312365404264014324 0ustar rqwrqwIntel'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.8.2/.hgtags0000644000175000017500000000103012365404264012333 0ustar rqwrqwdc19897ffffaca8f90aa3234c4eb85e12cfdedf8 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 tboot-1.8.2/lcptools/0000755000175000017500000000000012365404265012723 5ustar rqwrqwtboot-1.8.2/lcptools/writepol.c0000644000175000017500000001622212365404265014737 0ustar rqwrqw/* * 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 #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 = strlen(password); 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.8.2/lcptools/polelt.c0000644000175000017500000000751112365404265014372 0ustar rqwrqw/* * polelt.c: * * Copyright (c) 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. * */ #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 "polelt_plugin.h" #include "lcputils2.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; } /* no members to verify */ 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[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", 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.8.2/lcptools/relindex.c0000644000175000017500000001225312365404265014704 0ustar rqwrqw/* * 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 #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 = strlen(password); 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.8.2/lcptools/Linux_LCP_Tools_User_Manual.pdf0000644000175000017500000026173512365404264020703 0ustar rqwrqw%PDF-1.4 %Çì¢ 5 0 obj <> stream xœXId5Kàa™a™™Ë»‘y(cG„·+BB\h•4˜S² e!Ñ~ÿ|^ž_uµˆæE¤cûâsØî?6ïm^ÿׇÓ'N9n)–¸=œ$Žï[ûŽÕë·­éßÿÝ~?yç9ˆ§_œ“¤ˆØ‘çíÅ/' >9_¶ä ~g8抯(Фâ²l\¤ºLº"¹š sp\·Jt>l×"'¼%bvlâ>©ˆ‹rf—Ö8$'dC XÞÔGp>«Mv›\ÉED%*®2|ø¢ÑSˆÕÕØ¢ÚWò98Er¤y’å'!°K*s°P°R+C~)lBø&­4i¨¬ ïལ¬S#ÅqR¨)Ǧ Q½Â';Ò,7j~ŒçõôëI„“ËE«5<Ð<ÁªŠj%Wõ&Ä0–RÕÚjÉÀ˜sq¢ÅNR YQHÚ%ÀÃQQ@Á¥øè2ŠcŠ.(`"Bj¥ªEqIÛ„´@aÀâƒ5`CÐ.ÄBT®YצPYó‰ÈKÛQ"àxTêõô3lÐ)qŒú”Oˆ\hjn»†|Õö/š" !D |Îyx Y\±danÍ)ªó¤»KMZüÐܺ&ièäb\5ÝàŒnJ -ø;½†ŒÔ’µçÇbÏHäµ&W€j¥íÅO M ÔX­3”{§F¼2"î0 ™‚×½†º‡†9+ïÁû„fä'A’6ù 2¼Êjõ„&ãrÐxq( r´]H¨ÄçÈÕ:åë§i–ȽæÛK¸Ü +ì0o!+±M°Ù!£ ¨Æ`‹V""{Ízþx¢%b{KH°µót§Øm^]1lÒRï-ÕÚXÉØ}ÆÊ m³˜yŠ6sÀ™¸/C©U4•!’Î(ëæP`JÒñ‚imÄ27ð/6ôº¬9êxÎËŠ*mZÒ‘µËš)µªº¦y{ Z­³Â°Án[Qâ<5¢@ç ¡0Ýù¡z3‰kë¬t寓Élc’tsn{@$_{oú‚¦Ñ0Jl\5‡Ö=Zx”¢J;yc‘¶Çùaû¥iăicOï2¢Ä¶ŸºF¹g¤÷I¬/)Ô&˜Á^¢‰%÷Í¥2èL2e˜ÒeÝ~S3¢pé$?¡Ø·ã£rm›pls’1’¢uŽRžš9Õ™c;ö†Œ3&Åuî«e1‹î¡Ö=F“ÕȲ'+‡ÅÁ”gˆ¡It#ÇcvŒîQyTêAžÆy„ÁÉÆ«¼WÖ5J.=E†=è÷ÉVÛ%a®ÀµH/*ÓÃ÷SÓ³F–Ç:Zm‰là鹉SOkKíÖ5·¦aš“u©¬De/ Ò`;õTÖD¼Ê·¦°q"ý YO–`·•i—ÍE´›É¾"ê=ä?Û ŸÖÒ¨½Èù‘Ï®i½¿5!5›ÈK©Ãϵµ¾–<Ф´Ú»•î>wYxø0 Xóðašèí©rnbã=ÍŸKã=zHMQWt`çCÃSdÊ×ÞÖ°¬ÐÆ÷ÊAN:…®§E£ÛªÁd0›ÐŽP°UZ™€xLƒÄ¹s‰uhš&QãèÞ‘Uä¹ ºB=9¯T<зo×~0µJVM¶û7ëÈ“¶QBg_žbç¯D=k2ÑÑBzécÅ ß.§øØ¢iìv|[}pÃff1öoO“º³Ž±`Ô)޲uðú6:¸¿;ùíkü÷ z¸è?öò[¿¯Û—÷§/žçÍ® ÷?ãyWñ^ƒSý9lìŘÑxL¹û‡ÓùµËýo§¯îͽ®xþuÿxñWÕü)àq2#m /BÙ£ (Øwÿ­ŠŸ«„çÈ"-¿Ù_<aw%Æë®Ûýxú«îôgI™ÃùõËØLLåü†ê±¸J:¿©ê’ð|µ:FoiöÇtU«·}Ýé£Îl¾?¿­I„”jŽç¿]îôñ•K<¿£ê’3Çó¿_p¦åÎïª2å”Jɧ”ëL¾Æó{ê"{­cõüË ¦WÆÍìüw]QKô²Ú½ÁEÏCŸ—xkŒo^î°íq;9ÀùöŠÛ]PÖcHÜá¼ó½½>MnÁÛBã"çvg¯z,I±rF’^𮯒Ïÿ¸`rÖÒùŸºÒG¥¼þηz‘בO.¸(f õü©ÚU\Ϋ–¾d0?p>y­¾>³º*‘¼šÈw´Dž×µÏo«ç]’ö*„W-^Û²¤9±¸Ó~àr[=Ξu_|r A¡áÅ]Ò^ᘴ¡G”Õ¿ ñPÍ!W<†À¬Ü]üÛÐ÷|\±0sî9ØýGÇ€?> stream xœÅ<ÛŽ$ÉUZ׆6 öd­wX¨Þ1¸ÊÐé¸GÆ+²„x±5’XžÛõXò>ðýœ×™'*«ªwaF£©ˆŒË¹ß"2ÿt³TGËçzÐÎÛ£³‹=~|0¶ü~I¿mø;ŽÉ¿{üヘ…–F(kiðæ)¡ßüáÁHáf±Xๆ…u€_Ö@[foŽz1aö G¸98hk9ëptr±³Çç½(5}tJëYÇf6°¦ZÌl´½ž½<:-ÝlTœQz`Ì|Á5ä,<Îñ³‚9>¨Ù®J-sа†Xpw'm˜ƒM»Æ_Nx9˜Œš©"|FJ=;lëh3Œ\`$bð9y4Ê}bê £³à–BÌÊãŒÚc–Y;$µò6õH‹«ÂšzVÀ 8¯éùüð_Æh7û±ôæ[ã®f¤2‘Æf 8;ââÆÚ/³Adk€*=‚S@ì2@Y-ØBÁ’FØÙrZÙY"ÁŒÉQÚpÆ2;d€Bc4EÀ H­"ÁJvÁ^°«Ç:4ÂaŒ¸mPr¬P}~ø=̆€ 9m-þè+ØyQµç¥õ(ý¤G‚ FÁÎ ï}ܹ¬*½™—l¿Í l­ÈÈ‚}B!GAº—àùÒó’{nífkinhÜR*™¶ù­«J ¹Èž~Ÿ¸wÝI D@«yÊ@ÉÔñ›ß!i¤rIª‘ÀQ2Pö´­=F DØF†ÒVR ®Þ¥GkrECFÆ2=>#C&3=(áÁÐYLT³^ºaf@ Ú6j¡<@0@æÔBm?“}RÙ9ãü²¡ËK¤h˜ˆÁ£`$=2Ú#ADLPÑ KvVZ Ôõ9ÇF@¢ne@µ}]'€¶ dt3-­² ÷Ô¤RƒöE©”ȶ¸§¯Íhs@fl -(ŠÖ‚ ”¦B¹Y:@GCóÖ: V\Ö7Ñèå6ˆæÙ“DQ"Óš¬ÖFHUÂ*÷$B¾lH‹x‚­ˆ´m3‘ØH%íkA €öEb¨ù2´3N9¬‹¨£\€yŠfÒG3©P9mC>dÞä©ASÍUZ0rOV FS#ä’ƒ_J³œþêüáÒâƒ<ýõù ôÈäåéÇç'HÔÀéÓ§Ø ©¨³þôýó&¬Ÿ~‚?¥Zt k¤-¤‘¡GU–Žä“5ßÖÇdÎÔ†~ïü„F8E÷<|^§e°!ª>ýàünt`?ï ‘Ý‹…ìõ¦íE “÷ Öœ~z†&XÝ­@@@íl€ÍHïÕt9ä­ ü ÏÛ/²üaÄL×f}ˆO_œÿãÿ>(Ð «þ„…Ìfùòɼœƒä{#Vø”L!нkkþ 0ÆzmN—(­S)èò5^S¤§/Â+àE[÷oq1á,D˜š®Öp Äö†ÛDzÿŽÙ<>FÁ€œ—AÍK¡èØi:K,¯8¤-2äI¹·`Ÿ çp‰+%ý¤j1ž¨ÙýÝâp-|7”PŠ®¯;=¶Ç_Eä´Wä1Ňp%ɤޒ7TA<„+ yש`Y¶CRSHv|ÞÕªÎì°²J ¢rõ `¬p)FÜ- tXI*ϳ‘\)ÛWÕB´‘¬Öï*Î;–k‡¤Âe:p¼Y…¿ÆË¢*:²Rj_ß°v&8pxÓ¡„ïÛºo9rL,åHï{tž!•6#Û<ø†Œͺ䳬T§)š .'„¦×C¼Nôú¢?C?Ýû³­Q"p|ÉHíÏà—-³IB­¥Ö0µóŒ+©Ž®º$-Ô5" ?­Ûm]£ z—ü×Xßå{þþŒÑSX EåÎXç f(Õ™’Òi¼tu¨<ˆDaÖÏñ—FW¤Á°“:ç5âñÕ­}3l-'>ÿ¬v¶Ç_ŸÎXŸpÄ L¡F›ö·>%V:?ýöü´ÌFyo Y¾ § 5zͼY4¬ÔUCdðé ÍäqáiÚ(&ÆÇÔùµÐ¢íNÔb/ò úöÈÊE7¯¸ôåMÞ¹ìÕ^³Uƒ ~"Àf¼iˆ:oµ$ª>u™e[ºÅ@G^K¶é¼ M‡wÊF1ßKY»K(·Õnãz§VvþAVS1CŒYôôX„¼ ÿÚbC¥*xÀ»(“ª‘±ÝÊEßñw®–õ/šË(Œçe¶jm,™¤g¦®ˆž”0E×@zY•û“3•ÂСÚ4 ¿Iqx…%4¾VwÒ5Ò½žÈ[ÕÁH¥=oBȺ¶21MÜü¡¥+C)&¬È2$™5o3H…è]ëÍkà1N±vªeá™íÄT¼Y+*?Õ7l8?L-+!×5+λx¿ÍŠÑ!ÄX-ÐÛsànyWjy+p÷tÒ%ÙtKZ‡·— ±°vap~Üëd R¿Â U;L›ÚØìu7š ‘Y|®ÝLÔùó%Æ•˜};à–zÊçï.mIJXèj¶×T4¶ü¢öኊF1FH?kš)È0ãe,br½Ç.m¿3¾>=¿Æµs5º›!²YO^WDòÝQc“‡V;d 7¤ª£0ìÊZo˜º('Ù km± ê|¹Ú#o°†,ÔÕö¤‚¸ý둇Pð> Ýïñ6•&j ØýxÏ`A\£¢z;ëÅz&¥;ðuéÁ±À§hü"Ce”Pˆ¯Éý6Åtà™  °PoXE¸#º­.`.²Qx¬þë¸J= 6èЯÏ\†ßª5»È{Ö˜3BXÌÐ'ÞXê¹r9èÝ+•]QÊ»¾J¾kX[¡Š?(œ?ÿ&Y‘EβU.Ç^…ñ¥²ï‡<I,fš³,ìQ {œaYà7.hÏд€~£§…Ôh9LÖÓV-~[õ´+ijU¡O¿¨õÕrâŽÇyýaÎ*²)+ #ƒv¤[„—Éê…õ©­àIQP²[6±¨?¬ˆ6öýˆÖ˹šäÄž:_SyØò*§Øe½/Ð䱘…¿Œqx˰‚è;]µË£ê­:bz•+ £4¤\ì(ªš‰ÎçêׯÀ¨Ì[SÍþ¦b~yþ½R{"H°'`ƒªûÎaË¢¸¬‹úü dRAÔÃLÚàÙ;pîÿkëE¿KþoKß9W?(0òƒ[J1ˆØuÉÇM˜žx³FH ëÛYzâÝ ÿ&>ù‰Ssò|brñ²MŽÐÿíáÃ/xßßßH(§7ÞRÛ©e­Àö8 ´V¢{Õ›6rT”X=y%¥åuAEY÷Æàö‘Þ)ÀÅ“öqGE®°¼’÷æT¶ë΢d+ÒJ{?©öD™jO®°©í ¨:üA­cPx»|<²­£KŒCÝ„6„_ÀA÷Ü;û‹g)mQk ”II ¸˜m¼Š›ò1CÕRì¸å p‰kkÞè•÷V¨pȼÎXã|)—ÂÒÛ[ž}CÁŒ¼é¢ÌÎE”ë¸WÄב:–µ)O›– 7Z„vØÇ2¶jën•qß·_-[W\£nñêÚAáž[uåaKŸ–`BØëo™´DÛ-tþ<­ö±*qãm,U« {xÍwwþ w¾á–<ÖŽ«Û×½â4»hgbÛuŒ')fµ¸…G›È)Í>¶» óùIãVÎrëë¯Ë¢éæRß×ËéÒ×›­7۽︆´¶@\‰ë†òâD.ʱ°¾² ìF 3ˆ·j6ˆNu[øAõ£¡3ÕŠðÐ]ö°õ~)Ó½=!]å¾ä'/£h»dÇýñTÞltá=?¾÷„.Oo©êÀolo¬GÜUöþ’9x~ *Æ*IQ-˜ÜZ—þ¿ÅŠ?П¦=F$ŽÕœöxtyGˆ"]޳ÌVÑU I œ‚LÓ¿¤ôU}“¤Q¼#ÝúÖJæÑÝ‹W§âM¶G.Ò½å¢éð‚ÏøîÙr‹îÄ Šb´{b¯Òñððñ=¤=6e¥¸FÓï^âbÓð@†ä\|u›síŸnÀúl8%±qoðŠ@ý ̼˜òÈÂEŸx²|oôÉÞÛÛ»RÆjÕ¢HÌ…5d|úréÌår!í)ˆÂ¶AO·RÇf!É d‰‡Äl~:¯*ñ÷Ýotl ߯͋'Z“:lMÖ6Â^•Š×¯¡ö"–²ö_rüNª¨Ÿ.⧇\æ.–"/½Öƒ|}ýk=£»kÝÿ~UMa"%±ǘoãÍÍ‹a3K–‘’³TflÇàè|$Z%½M´¢÷ØöWžm\á^¾±ÙØÀôÝ{sâú7T'>åÀ³‘I×DzíâÊcjsûKF…ÚôªÀà8b2mãÜln_& ax¹Œ>5-š8%$šK©W¦ã£2`7ÆM?>Kš³pÞÞd&ʶ¿Qïûô2ò–J݆,Û ¢ `^5WÀWÞÚ5Jn#-ÞOðKMÜ믯ƒ0\”gËÈÍÛï׿þ$¥œáA`pJÔ — r"ÂEaÚ,;ϼâÏZ³T¯¸Ñ×β!;i&ÿªÁH5¯—ÖG n$`àïvÊ -šUò…Áf¦ÈZ|bÅ:{â·tzl@^Œä?VÐŒ éáR%w|O¹™5VùIƒW#·æü‘,k$Ú·EJâhg+mr²zUž ¯Hç#·¶k·÷œ€ì& _æh6ŠäÑ}ÕïüêË:Œ¯J2•erš8C£>Üý*Ð^k*‹$¢øÁ¥À÷\‚p—¡xå›ý ûdzƒ,)ÙPáåž }Ã*'½œ²c^.eŸ÷ß9!»r¯Žooâ—•Úœ®¢Q.·²oNIÈõÇë¸Iâz‰kÙÄŠÏ|x«KS…CŸOs¾†ß­õóÝ›Xƒìí×ÁXþ>Á=Õ›Q&+Øo¿Û“çî¢XE6¾ëUì_¦-¼m€_Ýë M¼ }ÿ¡ ûõ¦¸>0,ƒŽ·ŠÜ”o¸ìý¸ªí-ñöÝê[HÁ‹^{ôÊÑHäÚîÌ+ä&úàý?¾,té“°ØŸEXÂDùeÒF…<©·@~XžËÓ_П~^œP&,R ìm€l?HwhƒÉˆ¯¿ÉËÙÓ×lÝd¹¾±C<öm°‰Äë‰øúOòl?GA&”&ö¤l+îÚ­Jê¹æÌ¿|ÀO3âWô…°!~E?~Bß üÌo~5~öÍ5Ÿr~˜Q¹?&¿ÌØ ŸÚ’ø@ øíÒ7&@‚„wÝ÷&ݸ_­¤|ß[ºm~<~×W’z 8‚9Múúõ_ÀäɆ¯Ì-åh¼nýë‡ÿPŸ­pendstream endobj 16 0 obj 4946 endobj 19 0 obj <> stream xœí›Ë·‡‘ø%ŒØyX›DÐ@™A0Y,¾®¹YX 9§Mì ˜5`ò÷çWÅn6g5;Û#mì}IDÖUÅbñ#Ù=óÃ`£ÁÊß©pq¹úaåc C 9 —+SyWË¡X)k›±ü÷áû•5Ö;¶¡Ë§È1 €~dýðæ»;ÍC´Ÿ{(ö¥ÀÄl>s1‰¤E4%¢îñeˆ.cÝp±ò™È°"yo¼ö`ÃÐI™M(¨'o’¢wÑ0iI‚è¹ÎØ$}’!ôI…L€U¢lЇ›Åzt¡˜ªU-E›œaô(L†ÄORÿØ9o¢Ô}F Ѓ]FKü‹n`Jˆo”‘Fñ‚=F–á·³ÖP’MÂÙø(¡¦ªÄÑ Þx¿1æ«ñ¼Xý{Åì£IYF«ñÀä1ZŒ–Smìˆ5Æœ‹ôÖ±$ÄØ§lXÛpÕ%qDºH€Át1âa(K‚J¶Á$ ÎS0NÆ<„àZ.Ò#›(Ó·4ì „P“l’8LlÁª/IÚFW¼øÁà—L[ÀŽ+C½X}‹>˜$Rô!Èÿ>Ár¦&ÙͲE¦¿“8$|`‚e'OI-OZ]b“ÕÙ}3;˜ö9’EfIfÙK”ÁO’Ý(‰b:šz‰Ãlø„Ù@(ÉUSÈߦÕ%¸uzöí¨íf‰¬ À“ɈÊ•BÛIhÅšÕ`Í É=š„­dD˜Ã0ÕÉYYk÷$ñ>IÞkj8Ø’É?ve’H$à ÷½HŸ÷$– †…zÐUH9G¦”V¿èìTIgyóî­¸ì4VXaV‰$±/;‰Sv°Cа¦ Rƒ%ZüT…eòV¼nŸ#Ômoªc‰¡ç¾ôÌÚcÔPÑ:Û¨uép×;«w‚Vo&&ÉäĨ`òqºÎVý4²àz üÔœ‡ìl¾¯Ï#%’\²‹Ld£wÝZבy=$´8ÉA¥i˜ê³&½˜4L^-’OöMìz2¶Xa£dW%žšDëÂ"©Ë‘ºåR§+ÐË®,ŽXÙ”wU 8áñ€ºì6žžf¤Ns]U=™Ì-‚lÐSý¿µ…} ®©ÝÕÓ£¤Îýn_âbí|7TÔÝž‹:õ%ï…’û>NO¥³Î¹Î~Ò¡diH“•«gH©§Z­yOíã\ósHUPúè Ÿu5žÌ­~1N«ëZÈÄ>ä½z ]¬:Iíz È }\Ý‚u¤¥&"â”Äcf¤1—¼@S%‘jŽÎ3ÒW}[£@¶=©úÔ§â^úŽËuܘêH.{IÒó·äq](n̾Ԫcþò^ƒ {Í^h¿CŸZLÉ7×c¸Ú£Jôt¼ëuø›æÅ´~G7ýÝ6Ž©Á4N6´W×¼x+6î¯Wvø ÿ¾ÃEgù£7¿¾|q9üå|õòUô¸pþ-®w÷5(•ÝàHoŒ Ê_®Ö?Ûœÿgõ×sQ/7Akqœ’› ^£uð÷ÕW×öf™;8"bÍ,ÌêÕH✌´ƒ;¯×?ß  'ëhýÁf‹øäÂqý¡qÅ+nýÑDØÙÖo¶Û¨/Ÿ‹G¸@¦ú9—ÖŸl¶¸ê$œl0Êœÿm&"è`4kqÐr=lKxoKÊ<ð}o²žtëgÖ—¯HBÞ{lŽ“ŠÞæZó¡6?¬¼Ø®éëõ/6H¯ˆÛÙúó Ìz"’PÈý wŸõ¯6[hGŽ&·þåf‹#lN[ Ög\ÿV»9vë³®ßo¤è(ûÒwû|³•kSŽeý‡Ç¶E><•Þ¡Ä·¦O2Yž­$YÃù?‘?õàîk(ïwI!ÙRÞ1Þ7’[\­l¦¸vê̵¼ãÓnD©ÓÇyÒú›ï—°tn#K[Ó×ë?mdGÆßžy¿ó ¥äûâGÂÕÐ6à‚vX}.¨Ä…/ä;‘÷·ôc­o]?÷ë@¤O¨¼-Þ^$4íhž€5y)Ák@æµ’¨gѳM”ûÓQ³Î²>·kêŽ[–ç¹òP¡³þgœÀs ¡ìE?Q—BÁQó¥ˆ-ÝuM¶‡Ž«ÝõyWþx#÷ýcÆ¥%ç§sëOAzFÕGi”¬O,~W²žÄ¿…ÿBöò¢éÿ =€³¾EìÍw·êfŽgIœ8ºóãï6ò*œJX{q¹€›{‡Êi_ )‘±çàÁ“h×i€ÑMà'þx«·,£±å‘ÞÐ#Öøf¬-e‹`-&yb{ká$ª5u˨ÖY_ª]sÒ{1Ãì4®É7kì™üû[:kdrðO\{,\;@¸On!g„pÁÊë³#„s'®©[F¸ÎúûîÅÁW(gßl ¬À =Âîò «—Öb¢MoVï1Ê®&Â:}¡À[ˆž÷ò¥Þ#À³'¯©[¼ÎúûïÏfÖ³þ­ L¨¸ÁÞ…Y¾¿¥[~—ü˜oªƒ[’!Ÿ×Ï*gä4Ÿtq7Ÿâ¢E æ’|ùðÔø$¨5uË ÖYïNagJ5/Xš°Å9¯Ïú«h{{Ððlï0¿~ããÓ Þ»¼èÕ-õ¡óëtº=[N·…ŒºYý™Å±— oNÂ[Ó· où[À[G·ò~ÀïèNLèý-ý¨_ZyÐoV7Ò¯^Rå7[yÊ„ö‚sûìãÌò›Ó#ìûôôÍꡯ·~3ú~Ÿ8XœÐzÞð]‘=2b ¦Å–þ†÷Ö»0ñ÷·tÛ_|~Èè{㻢Ï-&ßRþùbj¿º8L¾xùšºeäë¬ßL¾kÞ®öÏß>Üd(å®^)ØènL÷ý-ý?–éãDßãÞRôÙåè[ A_ýëÑo7ágË(è¬áNñ2v~Ü ÁîÍÅ‹„̦ÜÓðËö,¯çâó/7[ùi,Û§³Þ]^°êeÅcdß¡Çy¼œn‡È²÷³ãDà*_öýõê™ÑDendstream endobj 20 0 obj 2575 endobj 24 0 obj <> stream xœ¥YY9bà‚ø õXq=Þ—WÐh b&j ¤„‡Îí΂nw2dþ¿‘ïØeûÔ-÷MZQ—OÙgýÎâê&)”ž$ýÔ‡ãÍî‡ñÁMÞE7Ý쬫ϧòì’¤ç¼gyþÇt»“Be¥öàe‚·Þáç´4ÓÝ›UÒ '/#Þ06 O΂â£v2Ñ&4íð"y¬&M^E'¤šŽ;µÖL^#L>a…O­p ë`DP“7Ê «ó‰JÁ œ<%d 3Ahœ I ©ZG‘ xÈHÒ½rI$W¤æ'/ƒ'’ÕB“ž:ëg•2ÂÓÚDø'¬ŠØI–A?¯&«üëÉROZXË"ôVR èD£Ø(Œ'Wëà E9â žFhÒzÃæswowÖ/B$k³?<‹] ÖÚˆ›UÚfÛ˜èt¶%ÀÇ&DaÉØF€ª*"t„dá„ËÂBGZÃQ`i¥Æí„"‡Y»8DCµ˜èDžÂµkà ®ÖÙa•¢.È‚T“íõ*ÒÃZ½(l&Âg¦w¯q¼qŽ~Ã| ÉQ7Ê©S´L~FQt°’9>„,¹rUÁŠ˜•]‹9A´IÀH$šÔQ ;&OÆWÊi¡xí…sœ¢  ¸R«" øm\U€j>‡g-'Ën’´$Œž TJzº»&×(í ªÉÁ„=ãÅJB„ën¨k­$åì®cá>CCåÀ(U?«¬§ („ðdù©EiaâŠ"­€YX»œ…vÀœ)µõ‘É)&y±ù´ñË)û &sEìFQ¹vXˆØ @ˆAŠ&S—¬$­Û{¸ÇeErnYm‘Ú¡±£È6IN(¹ÒjÜgUSA¥AöeT* [–Ú2×`Æõ Ê!1Z‘T©KM5*G³£ÖSyAµÎÀÊlÀßæ¢·¬IG*Ïíð€¢¢ y*Y}MšêbÕB)ŽaÓëŽ ¾¾öîüD¡äéøÄy˜â›¦EÍßEMS½Û쨪VèÕ:Gð¸ñ îïwrúÿßࢇـþå›>ÞLºØ}ý1íÚ†WÊõnð†Ö 6™Hº\Žˆ:‘çReÊ ¥Ò ‘žåwyOcƧöt_H4f)uIÎÅ÷,9?°6ù…pÍmy€VÑü0a#ͲÖõGË;ãéôHµàÕ8à¶ä"/ï™aäø`Ì-–®†nãaç!êiÕ!òjÈáŠÇà¬îPà‡]w˜`ìÐ6-iïÕ¨ÿr­?· 7£Ç¬Ê*Àªo” Ål˜lÍÐi”7,YV¾mhõ‰çå@dóS˜çcR‰DÙ°º=V¨6‚^#Êø÷òµÍFIUÜ5Lª Yóé]ž{&ŒÃ]”ÓHùÞæ®ÙóeéÙÚ#ÑGÄA‡Übb5§ötdÙú·½~¸dXú‡“ÏÓ{Ð=ExPä9˜&¯<¼ºål¡!ñâÙîâ/Æ•í]/?ãìÝb…ñ5جÀ^"Òý2f]Ù<†®Û:cÞƒ âç—Í/ 4Åុ qŸvU@D•ž\tôë‰WúšŽkw”ô·Ò‡î Šþòk 'n^)Aì†0¨›÷ÜÅ~æa&|²½ÿ†pB¦šíо¹þŒæ¶.`x{]µ'Úé¥â×–>+uD£Ñ€B[Óá¼¾KúÒbx}æùåƒùòS›`Z=`{ìG^=8ñò^‡°GÊûè Ìè;;òÔ’ÿqü=âÃ0:q—$lÚ[Ó‡a9à­´¢„Ál5r×CéOÿF²LKHýL–†7’m­S‘÷Áárâh0šÜãò«‡½ÇjÅûQDº#˜ü³|±1Ïuí«ã÷»ÿêuIõendstream endobj 25 0 obj 2655 endobj 30 0 obj <> stream xœÍX[\G˜ëAgc’L"g@{Ü—ê[¸IH(â%ÖJ<Ø<-$ÍZŠøý|UÝ}ºÎÌYïÆø[–O×t×õ«êªþjofëö†ÿöë›ÝW;SØÇÃþfG¡ëw(†¿eOûþÛþåÎÌÆ[2.‚—O‘bÀÎ9ã÷¯¾Ü‘5q6yMÆïŒ}ÁW Pbží}¦2'Ç;â\"ÖÞξì£Ía6v½óÙ¹™ü>:ïg/'h&ðt™æP°N~Nv½399Ñ)8“Gæag“øLšÎ¤âæ©Îå¹xð0™¥GÊ\B•*_Ñ$;Nr³c=èGÖú9òÚgø'ÈfìdË _´{r þlid-Èò ½­1³K|b¡Pž}dW»*Åæ ž~v¬ô†Í§þ¼ÞýkGäãœ2[+þ@ð» ¬¥T˜YGâcÊ…O‹- >ö)ÏÄÆ.¨j+ÂGØA‡ \Ì.óŽK2aN0λ0[vQsˆƒj¹ð‰1îV»Aéú‘¥ÈAÞ 0 éSëfŸWC3ÌÂ:H:Ø`sn.eY_+9•¢$7›g~9НaF*Bb`ß(Š•ÚA!  Ä E‹ïKHvÞ°ÖËïpOE$·ÈR;-ìø²Íp  Ê€TZ€{QµTTzdŸ ÒrØDfZ–Rs€™06Ø€Ä`heV¥/×(‰f' G)ryAµ` ð')zmÍ:ryNjG--rÉkÖÔU«¥:òxæZ¶µB|ƒl#q6{ɧ…B\¸¾8Æ™o‹á:]ô:1qò$e2I™tœœû!Ê—›¶¡RX”)W•¡DÏ)NT”Rcl®7OE,Ô6¸?$_*… ð(’¡6rz¬!%Ô|jÆž€ÞD’œøLZPƒ 3EsjÉÅkÀÙѲæ‚*uú-”.Å€ŽÒa¤ã‰¹’&>Ô:éQ’‚DγKýBYªº÷¡^{};&]÷ùd–C-­CF]ó x€ÔܬÞ*ËzÑ)]‰Æ ë¸¶B®Ñ!ÕwË‚Õè)˜‡Ül^¯‡eÂàâ[¤sà‹Þ*¹u-–yi–h‹¸QY8ôõ±PšC×rmGµ-:)x|oâÖcÛbmÃåX)Þ-Ys-â5'¯ U—ZÉ@Ï·2+bøR>V‚”j-Ö|Ûx²ÒÍðÚµ°Ò™Œ/è¾þOÝa¢ÞAÚjNx6JýqM±±ž ^™Šµî¹®¡/yåPbÔg¬t¥ƒçX“ï<„”†Ôy%é!yê²âÞ-?çŠ{ÄÐUBÑÞÁ9c«?‰–õu «U;8ðM‡¼ZG®B×;E 죣¦ 2È[¯@°ZZ*˜àñ;ˆ2RÃ’ç¢)”è*FGDôÒ/YÐ|íñÒ' Å|[º¶‹©Zr£)IúoÏ%j¢Ø†¾´,~iµ!ð]³Z;·>AÍô¾£ƒo¬c8=Q)Ò5_}³hÑó·©é»w;ú†n'Ínµ–^Ÿù† ÷ç;³ÿ ÿ¾Ä ‡Þ€ÿÈä§¿¯oöºÚ=}–öÒ.\}ñ®`^SþÙî­“‰1!ð¨rW7»é‡«ïþ|Åìy4íO‚2Fc¡ï³ÏnÿíÕýÔA-ú 1«>®z}2`ÇêüˆÕyú ^YŽXF †!³¿úÇnÚ× Š%'']>}ó”ŒuÓƒïàÒôîá7Zù,˜sŽÓl—3©„é[¼CdÈÓ;‡K΋äìôÝÃ%Bf¬'8êïWižB,„‡` z•\ûõÿÍMñ¡UÜpg¯ü„6ØMϧŸCuŒ«Öøéƒ×µ ?<$Ëu&³¦OŸá.¸ß×nðë^}ÅhñÅ/Èò0}ÿÀ¥09'>ôèk’¥é#P1CClàÉÜ„8~wx‰Š|‰Ó‹—lE_86(¤?޽s@?YЯ¨RiWÌÚÖ˜/¤ûfKÙ—apLÊ`#õQ,þáI1¢†wÎÈ_G”¤KÌ 9;ý¤iKм‚ E12’P:†¾ÕŽÊSûôÃ%È_5·ñ»>õ¾¨`É6eøkÅIFJS¦÷–Ÿ›üö›2 Uʱ ÂBÔ9¢TÔ!ŵ…ÓRi#ô?ƒ¥ ÒG;U›ºʧå * Š™fñèÅaqâ§Êˆá9…‰é Å®n€ÏÇg¹TÕáF)ÄÀ¸ì!¸ä;£†áɈ¨‚eÓ2Ròë$Ms1Æ Z@yà«aæ÷Œ«¿î®~ý|ú-_U®l–…ß1BÑX!kì|Ÿ“Š0 Dö”ONÅðñB;‡ Ôš&ÖbÐ+Z‚²tÀðb0næÃmi·ÈSðz92ÿ8£w€HS»ß¾7ˆ/^ïó¬^©ðæ¥Ë$ò®W©lžüRH»èâÔÍahÊêwSóªoWš‘‡ôwÅú^ÞbÍA…þQù=’Há~³þ´tBuÝt¯Nã¡•¦*µ•,½Ceì$–ó&e-Mg2–ßÅ£þWîYAøÖ{àÞ¥E å·RQâ¹—%èfr™~æ)g”}}*YŠ×ƒ3LI¢ªÍ£ý îÔÈ»ÒW : ‹:Y‡¯¶½ð*~Ì{t|i3Ÿ•G`6£yV×=Í… ±º46mz¤Ax¡¶\ÜQhô¹Í;H9^é³– ‰Ïož.œ·êÔ¦ÆU¬vê nÔíd½£íPn¾+ Ê[·ô—[ÑUn9¶©ØYû[–ž²&ëŠW©Ú|þöîþ¯‘©áÿ1Uyçv<ÇËàòHið‡“ËõèîJÜ×¶‚ý=À£ S,.† ?*H剘C–‹¤éÜ™ûù½¥ÝR3ØèÑVøÒ}«æv˜ªZÔ»à|^)ØÅÛµè¬<ðÖÍì;ÁÉb³À`· Îý2ëd°l5:ؼ»w7ì²yù²Q›Þ¨¹z´]íè†b‘úPw˜ôR¶·@±7ðˆ,å^œßèŠÚüýžÃÌiÅÞÜ ìSAY]lÛMÑf.=ؼ·t n2»_7Îåùön8› ö}(K ŽÏ?ª[Oq5@ºéê3°Iç­7A•>ä;¹øÐé—šhz*,MqѪIKí?òÃóðãóÜÅùÐ]^uÀ–‰.o¿â,’îNÕ¶qxRë1Z.õ$¡Œ;W?Y´Jë÷ªU·X¨n춯Qäe‰bQW¶nÖîjß·{†ïdâvŸq^OsP ;í4ä¥ùóÝHbÛendstream endobj 31 0 obj 2935 endobj 35 0 obj <> stream xœåZë%E,²æ²‘U`–‡Èå¡ôEoSS/5TÄ¿@&ñƒøiŒ™%þýþNUWש{»çÎì £»Ùl×ézœÇJï7[5j³Uü·>\<Þ|³±>¸­wÑmoÈÕçËòì’âçÝk—ÆäÊ©ùÉ« GŠDf4̧Éü‘Övô<¶:À Ò3Y2ðçõ–L€~=Kê™ ²,‚o­Ôh¯˜)GëYÕ&¸BÑŽwÅžv4Ìø†Ì‡ú¼ØüsCdý"K›õãf%HK!ñn¤ eSL¼:Ë câH,ìL«:0#¼„DPÌEÐÇh"¡(lIÊÂYãFÍ #šbÀZL¼"ŽžÍ¶²P‹Âª6Ya•¢a.œ…Sm <×ëd™"¾Øl"B¢^l¾Ä@òÖ9þâœÍL¹l£›_P4€ÈàdÍŠ!Ÿ\wÕÆ˜™í¹ÄÑ6#‘iʰEî˜< _)—ÅóÑ~tNR4¬a¬U]Ž~ç]uk>›§?'Ÿ=Ÿd `Í¡9J§d¶ßþƒU£/¨fgd0ö¬›)¤®©¡ŽVìk»R¬ Œû »@©ü‘&ÏF^ 0ÂÉU mF;Š¢baì²È`sfLi_ˆs Eœ<É|y¤—ˬ+x˜Ê!0° ŠÎ±ƒ4 B2€M¶q²±Š¹žßC=.3’}‹ ÁµÃ¼/€·)6tBÈ‘Ö8à>³š *-¼/£R³Ùò™aæ˜̸6A;8C+2+uh8FekV|”<‡Dë ¬¼ ö§ô¦1óÈá9ˆPÔl4Ï!«™SS¤š(E‘—Gªe9+²nàm”•ÍZ²a¦GŽ/‚±çë¤8Îxã-›.‹Î¸@xÊa2ä0iØ9·í@0Ÿ&ÛL …Y@(Éáªl˜­g,æP£t,™§ l+äì/…B xÌ'ƒmøtãWüi¢0ö2è•§lƒ#¯ 1Xñ¦0b “sñp649` JGé~3¥žb@GaÐÜñ@Üì&Ö•8i’\¶œe•Ú™2Guk]I{uŒãŒû¼2æÓ%´¶3ʘW@$& ³Z-6˜Çó•R™˜6¨<öRä4ÚNµU2§%|fÌãd6+ÇM²‰Âàâ,RwàD¯Å¹eœ%³¹H˜g ,âBeÞ¡ŽÛ3eâ¢îP¹ìå(²y“çMd=–Í—2l¢\Š53%9ñ˜„ÇŠŠJuö@ËY™Qœ”/ !‡šJŒ9ÛXÒ¹šá±iã¼…Ë•I›á8A×ñ¿Ë åå *Ðãp°çD)¶¿ì)Ú—5Î Q1ÖM=Åô)vêÅ{¹F窴íÙÆdë™”ºP÷ȧr ÉãP†÷f~ îaCSIjë”.ú$šÇ“Yµ˜Á†ŸxˆÝØsºØŠc]J "C^£K ‹¤©€ w¾‚xBF˜°d9hfŠ7£Í"rhg/˜œöxhƒ„bßÉ]§ÄT$y,)!×ß–CGÑúÂ<œðKÝǹ¦Ó¯ Iô:£‚¯½;\Q(¹:¾”{Ø¢›™‹ê¿›¶jw–£N¨rÒhºq¶àÅ‘n8p¶QÛOñï+4z¨ øOîüäóÅãíoÏ7~¶¹\8ÿí]B¿†MùµÞj“;ÆÃ#Ê?Þ ÏìÎÿ…i›Út„­2=©­G-„²`žúÉ9sÂM£R¨¼¸iÌ£W¢}þéú»o¯Ã¹Ôñ޼U˜1Eë>»øùëð㤉Z+;¼¹c玖@ š-þíüOØqmCNZFl8l‹.®à"¸‡SqšöÃÛ»=ˆâðÎn´OÁ Ï2SämÞÝíQ¯cµÞãg«‚5ÃCu˜lžãE1m†ŸîPnºäÃðg`Aëºõ‹ÍˆztøÞBç^÷w,w±Òµñ‰—̯)"î@³¸?ÛíXôqøâkœm}Мէaœw!kÞÍ@ð‹:_?ÜíáU½»XôþŽƒPí>tˆÚ Mï$Å Ë=š>‡|æH:ÿ{f†‹D~x{% f‡—w{´¿&BãgÏ€ …{?<¹¨äq„^b;9î–äã÷XÑç/λ=ÇâF„4?´Í–xu^tvŸåEÓÂòÏóÁ¢M_í½X$¶z¸Ä@cUÌ\<é•«g6]þOÑ;—†ˆ'M»´y?ÙíQT£¥ á7;.L½£eÝ,jQœ½Ý¡hOÎ:,‡u5°2¼9å#ØP…»“k~TÜÁÆu5•"wЪàä„è¿föˆDzÇᙢZhïU9\µÊùá&²þsªTŠÚ!6½¼C뇒ž }ÁÄxZƳçwÜö’\L«ŠÌ°Œ¿7!› &ë›K @uµ¯ÊÚ£/E§ð´=Ë Éõsg)*OŠ?[ô£·qwG.ËJÿ.\¶½Uâð!Ët!èµq‹ ­97¦€×üHÉú5ïj½VíŠgÿ (r)TÿZôté ô_HL–p_óО;gKÀ÷,_gTÅ¢^ØñŽ*yôŽGv)V@ E›kN‰‡y„‹…Óí+¬{¯I 0Ü$|mÇ×&¹Á²P ºîÀ¼`}wó¨h;У«d|ç…·ŽºuùGT1tn~&Žø'nÔYAîû±Xwzg¡å׺·Èº Œ“mXã2.I6;÷ÁFyªFcÜ´ƒeôAåUá¨õ(êUrõO,ñ¢œ’‡³³–C|–_÷cq"2©f.£ŸjÏ—Â ‘¬›Ä¬fh¥f2ξ6AÒôqe@B$ÔtªÚxqi¦ŒR ËSîÔ¨±"ÖkðÈ’°ž´d³ÍK¾Ø^K{ „`÷ÙŠ)(ç¤ o,Šû¨¨ÖË¿3«¡Gé:&LüysþÁµP1Iä(èeáåax‰¦Œ\´½–z™«@ë"‹2«N¾†È5¯™³!µ‡ÁA:B62dl—6¾²Ƥ4jš„Vú‡¶ÉÙ(ÚžXÒ„\˜®×9þ¨%ýøîó;¹»¶­žÍ©W#·¢Ó„Î=A–©\@ªEÉèò® Vãq~n{‰bM¦M€bké!,,ç.JönKÃoÌj4ÑÇå"îDKpË„z£(tuÛö„ÕfönþB–Òq•ÖY²DHÜQtèrK¦;{"{ø…^'ƒ•x!ÎkšÉR<®äÇ>È•öÒXqYöÒpBãìÁg¥…;[)f\Nµ!×.ùOøÆÕyíÐ;×,9½@Œe+Iïš È~râúåªbÛ·~“¿¨ ?›œÏi#íxÐ GØÜûÜ ONðDô00m¥q] gW€s=h®äÛG¯,õÑ ~|-“ÝèÊÂ\U{X¼ ±O¨¿Åî!XcOF8)á‘‘»bÈ¿›wíSÛ>¤0Z äA‹t-š«BdÞ¬<¢~ôʸÕ÷óã÷ë£ÄFÚ9J©¥ÿ}®• Aô÷¸ï$£ãð ï`žDý´ *ŠZÎ\Üó;$KO(J~)¸zKúo=.›^6[ù»˜ofè"ZuváKE)ŸÄ?ˆ´lý?j–_An(;ðŸò7„j3µcµ¹‘iš#-;Ê–ã9ªb<®ZAñÇêc#p0Sø`åñÚF¨%â…>˜“[©w¡w=ùcŽJ½:½vÝ„À´ï‚›¬Öî?ú´qåýGûânêÄý;esÅ視—x<ª—ü©zéîï{êqwW“‹í[ºÃÞ¢Þ0=ß0-tTføç„‘ºŠ}ò¾'¾eÒlüº[ñ ©ï±ØŽ¸­mÎåéJ;pûÂøÊZ†˜LªoŸ–I˜¨-õqÐâ;å)hñû´øJà(hñÌ+3zœãz¹¤fgþE n9ödÌîÃ÷µCýOÜEq¤,wQOOy'ò.'©¿Ä¿×áNUx*Y¶ yZ…í:ïé©°KšÞÍIÓ÷ðãßÁ>¡>ºCõI}s½jâ >mÌá=y üƒˆ2ÒŽ&ÉÇë~&u+OEXQöÊ›ï>„®t•'/7–"ãõ3˜ ÒoË«7ââ…Æícðâ—Ý…Ï2/¯´¦û¥ Ĺ+˺ ‰ìr™|ÍØ7P·˜pJórƒ³ÃO¦{þzHëµæÙÂÕI_ ˆó%ù_ÿN–•2µÈt»²ò$NÏrä±8a8%ÀÓ«ó®ºC®Õñ£µ*}çÅÝ“^P=ÑýÔÿ{åå÷ 2©¸–™ÄµÆb”k_·–o¶û‹Û¾J˜ øÙæ?3étiendstream endobj 36 0 obj 3410 endobj 39 0 obj <> stream xœÝXY$G–«ðÁzìe4kË®6êÚ<"/„„° †[#ñ`óÔ`#ÔcÉûÀïç‹ÈªÊ¨éì™ÙÑrˆ]­6#:3Î/"#ëÛ­­Ûþ;/×›o7>¦°!‡íõ†Â¼>Öu(†×²gZÿyûÍÆŒÆ[2.B–O‘bÀçœñÛç_oÈš8š¼&ãwÁ¾`œ˜ÇD[Ÿ©ŒÉñŽ8–ÚÛÑ—m´9ŒÆnŸÉo£ó~ôr‚F‚L—i tòc²ÛèmÉɉ™ƒ8ydv4‰Ï¤ÑáL*n Ðê\‹‡ “Y{´¡Œ%T­²Š&Ù‘p¢ÛéÄ>²Ö‘iŸœ ›±“=ƒ}ÑnÉ%Ä7²§‘­ Ï2ì¶ÆŒ.ñ‰…Cyô‘CíR¨X*dúѱ°>ߌçaó÷ ‘cÊì­ÄÉ#ì*ð–RaidIŒ)>-¾$ÄØ§<;»0`ªMlá‚tâ1ºÌ4‘d˜àœwa´0¢) ¦åÂ'ò9M0  !°èpµ“€Í‹tA´ú’xo´Å³DvqÚ\D8n¸zØ|…3H€}ü?ÜwМÝÂ96Ž3…Ó¯8@€ ä ÙràSͳT›hÌbìZͪ}F2óŒãŒݹDv~æ'NdÕq As,²á²P:[U¿‹T›`Z”ô¬õˆîE“3ì€wcFä([ŠÛ>ÿ‡ÆºXQÍd0ö|X8d¡…a¦5\kð{æxŸ÷ +‰ípfûÈRä$w8ŒðBúT‡cÝèóŠch„[ ƒT¡ƒ0çÆRú ôTŽÒ<ù|<‰ËQb… 3ÒûZq¬ô²€ d %ZüLB³ó†­^~Gx‚"µEŽPÚiÇPm†]ФӺ܋©¥¢Ò£ú•–Ó&:ÓBJÏfBÛ` ƒ¡•Ù”™tÜ£$›35J‘Û ºµKÄ@>IÓ›h¶‘ÛsR;" h9i‘[V£ÙRW½š85ǓвŸèTI°9J>-âÀýÅÁ1®|[ ÷™è¢çÔ‰ëŒ ´'i“IÚ¤ãâÜ6…0¾L¹™6T›€V"íª ”ì9eÀ ¥Õ›ëÍS ³ î©—Ê!<Šf˜šn4´„ZO‡±' 7‘$' >“V ô`ÃB‘Äœ¦âbpv´ÐÜ0Ð¥³.¿…3kñ £Ôa´r¼á®”‰µOz´¤ ™óR¿p–®î}¨×ÞL㎉A÷}>™åÄ$¡¶Ö¦£Ò| µ7«·JÀB/*fÎlÄ$`¶qí…\£M«Ÿ= Vs`§`jp³yM7Ï&ƒ‹o‘Y_ôVé­´xæeHXv`,âAe‘0ÓMÇ™¬˜%ÌV®ý¨¾E' ïMÜzì[¬cØÄ9VŽw GhîELs0m¨†ÔJz¾•Ù×ò±2¤Ð4€æÛÆ“•i†i×hd2i;_Ð3ýϺÃD½ƒ*´nÈœ85÷Ç5ÇÆz&xå*hÛÂs¨©/ypbÔg¬L¥Mf£ÉÏ2„”†4ËN02C2*Yqï–ŸsÅ=rè*£èèàœ±5žD }˜ÒjÕNüdC^Ñ‘»Ða£8ctÔt9cëVOK"â â iÂ’ç¦)œè*F[F4é—*˜|í1铆⠾S¹NSõäZs’Ìßž[ÕB±úÒBNø¥Õ†ÀwÍŠvn}‚&×ç3øÃÍ•#ÓñQËð56‹sýNfú9º‹ó†ÙOÝŠ– NbÃû³Ù~‚_㡇ـÿÈËO¯×Ûß^mž}ž¶2.\}…ç]Á{ Bùg»µN^Œ ‰G—»ºÞ ¯ì®þe[Úv´­i;/¼ÝÈ5‚í_ ?ÚÁ¹ˆ·Áð³Ýý$Æíð»ÝžÐ{ð’Þß¡Qãw;|Œ.e›¿ÛãÊ1Øá×¼³þþáŽÃ7ÎðËf‡@à©¿ÚíyÎ*!Ÿì`vq˜ñg­‚ýà°8Mðb_8˜) %PÉŶ-_a[01Äál@Pãð”|¾¿Ûóûo‡ár(,/E—)Ù(û=SÖš*no?ä"–¹útƒ©™½úÓæê£/þí‘ùhÇCA 4|g·Ç³Ó6ËİA¦ÄUTlÂ+¼ Ô Š{Aù)v›ä°{’Yrøöüº'\Šû)Ô>ØñÓ¡PÞ†¡!´Ã#¶ÉºìËp9›ºÜ8¼¹Ûc€Ï N_4ÿ”Wê˜Úûú¢ì{ìjH!†4q{ŒúUÔEî™÷£†^w9‹x=‡ÎAxyO÷€|gèž5‡Î—ÇÄeèó·ÿ2Ϋ©çpÞt7}Ý&§òtqûåyÑn™;ïáÎàüBúÛ!5Üéft©ð^7f5RÏ>·¶~påñ3'³þÂðåsÔLÊ(Ô”áRŽ0}Š¡ æäÐÈVè^zI’sÁHðÚŽÕe¼º>ÜñÄ‹ªŸÀ¤>ôZgœ_÷$¾…®#ôŽn~ ‚áÇ<àeWÔíëö´º qúKþغʣ^ïüa»o·Kí*æj™0T†WÕjùùÕî!Å=1*¯?=>îôŽ®y×+™ª^oÿܽ:¥ÑÙ3¥9ýå7íT¨]ˆ?#Û¥ )Uf9E÷„Vºü¾Ö:K]©Z–‹.·4ŸÉÂÿs@‡3×n6ã¯6Ÿáï¿> stream xœÝZ[Å–1g° x—K’¢i×åÔ-ÉCB–B^°VÊÎÓ&E³Hø!¿?ß©êª:=Ó³»8 E!ªÎTëw.Õö·ƒš´ÿ[—W›o7Ö7xÝpµ!W×û²vIñ:Ÿ™×¾Ù¨IYMÊxð²Á“wXàžQvxþõ†´ò“ŠƒW¿[0¶ +G ø8l¤4Ã'ü”<öVO6 ^G7)=\nl4f";xcídó š¶!NÄÆ6TÕá+ì ‚C.‚?&yG%)7g›4;Œhvˆj1ñ8yÔhÈÂ- 2 \m²Ã*E#\©6>ëu²¬‘ƒ^6áŽS/7_á yëÿæHަQöbTâð Š HÖìø²äÊUšbVv)fÑ6#‘iÊpDî˜<_)û™âY´Ÿœ“hØ€hÀ•FQÀoãªTó9¹Ø<~†<.\|…ç]Â{ Lùg=h“_ŒG•»¸ÚŒw¶ÿÚ|zÁìù%¨Æ)~ æg Wú>}rú·ç·QGC0-B3* ™âJ<‰ÕùrüùF­•ßßrÂFKã³í6hΠø·‹?ƒ!ªÜ)†Ü‰Lg8lßµ*$%åß…PÈÒ~üp»hQnwèäÜøëDÞ¦ñÑv‡Ì«íø¯­ Ö„ñÇ[. Á7¾¼t"æÅñ>U­Ç7ĺ³»_¤ÙäŵŸàgxÝëñÕ-[^âtkÀèÔ F3j ¼Ï©ŸMþåvâ™Çgß@¶õA¨VW¯Ã"œw!{IïÀ ‡þ£­ºÝ!YžäâÒ¯¶, ÆYóÇOSѳsˆx‡îðÀ»àâïY~#$òãÜOV“ßÚîð’5®9»³ÅŒ§®Ï! Cy Io²Ç?|Ú2¦âéYÛ×·—ÙĈêäÇÎLŠØî4W,%»]?{•­ÅK:„uV?bVÁâí9 ûï?+1·‘8”;Œe‘•}¯k $Ì&¼p’;;y¢SïvÍäUïl1*'g´}Vé´X¨öp¾Eãcf‹ÜŒiáR!á p@Nø…w{nòã[[LùH¤¸ˆˆÑqËŒ†fÔûX©`°ênÍe$…[ƒ‹=1# X—Ké÷¸PàP†Hðê'WœZu:ç3 ©’øe î÷£.¼_ñtgËc°ÏÛU—íðæ¤9Õné@!¢( ÅÄÏ=iUôÎ¥1B~ÁdOÔƒ"!ÞrÊÇuH̨ut‹%S) µšíÖJÈ»¤˜Øó¯m™_Ô4ž¿ )¨Qžk**xÄ*ÖÊrÎ<æ<…Ã*e0õ{ 2,‚Ë$‹9.2MT¡nÓ;[þÀi’-[—àÝ­s‹l¯˜ õŒYO³aˆ~.É©’ñ €ß¹>#¯ã_ÐY®»EòßÝÆÉ™\„O쬽ɒjÿ¾²a!¢gëĉ#0ÈHU0À”ð @ž<³Ì˜” +N´1 ‹ÊÙ(ºØkŒ]ÜU°!þÂA´ ÊÅR–Ê0µ³üPÇ /Áóý‡³Ñ®ÕK94ÀŽõ›~ÁGÆ)í©ë2WL+¹õ·õjòÊììà`þBáÉ‘gW-{Ô-ûECM&z)Wðz°V*¾'T{Ñ%jE¡~{]ü.á} ¿qè*®ø²ývQ'šò{¥¿1X€–ãþ¶È¦µ9û3ÔÂP>©èÛ’1¶31M>Ä9{v: ]áA"êÖ¢ö‚!=ë,ä<&Y¬Æò¬;[”±<ác¡æM]íD¼Ð¶¼qö…x"®gÇ-鈻I×ß1‘È¡úðÓ‘¢ì¶·Ïñû¹ÔPLЧº aÏŒÒïƒãÉéØjÑ%ŽKŸ–£QÇËœ±N©öÁ@„gžÓ”" 7•ÝÃêÁ4‰ó›ªÇÙ5p<]iKBvþ€Ÿ_dÂbXÉÜ ¾›B¶±7¢]/J{Ûâ§í¢1î¯d{ãëAZxdÖ¾ÙçÇ?6®½æ²R˜,Pr¿×¶ÞT!²î÷O,Máê÷¶¼W—Ixç¨;ÃõúOìk¦Ä##ÇO™ƒUXÍÃ#²+¥À¢` qµ<¹Êó3<á'L4¿Z} Ó½¹3üesññ—ÂÁ/0Ë£P-¤ùÃb¤,’ÿð+Ðz|ôÿi|~ »áõä?áo]ÉI],¿n#MϨõŒ¸®czÇòdÿÁÄq¸ª©N¼byë Ôó" ·&W¦eø]ƒ'åSi•¡ª…`G¨0AûE•“³þݵÒzüTÊQ“O¥Ý@”ÍõÙÿE'6 ³ï:9ù‘E~ ÀÓŒ(ÈAEÌ\·«#ôÉGfùr‚GÍxäÃÃaqñ ­y$cÖí‚W ÚÑÝë]y·Ë¼1*‹ñåä÷KâÛ„œ>Τë­6âão.üWTX<ž=çoåx[2WñW¯âxþ°4€¢bÛ÷ºþö~¥¿¸ëG™$¾Ùȯ3‹—öÎð߯°f‘j<¶þ¼]Ê#T˜Lúá¿Ôˆ4|‘/5Ÿ÷ú¹ú-@ÍÞoª´÷Úï÷Vßz;Ô"‡?ïÄU0uþ½ëúlä¥nÄhE²æ×dû!¢vóHù_úNMˆöÇ2_lþ‘ÐÈrendstream endobj 44 0 obj 3051 endobj 47 0 obj <> stream xœ½Y[GÖâK'vìB¸hb#˜!œq_ªo E‚§X+ñ€yÚ\:)~à÷óUõôtÍÙY{‰¢L×v×嫯ª«w¿ÌlÝ`øßöqs{øæàc C 9 · íûT¿C1ü-{–ï¿ _Ìl¼%ã"tù)|àœ3~xýÕ¬‰³ÉC4?÷Pì ¾Aóœhð™Êœïˆs‰X{;û2D›ÃlìpsðÙ¹™ü÷³—4tºLs(X'?';DoãLNN4 Nàä‰uØÙ$>“f‡3©¸9Àªsy.:Lfëц2—P­ÊW4É΄…ÜìØO'þ‘µ~޼öàÙŒü‹v —€oäH#{A‘eøm™]â«„òì#CíR¨X+túÙ±ð1ŸãysøçÈÇ9eŽVð@ò» ¢¥TXYG‚1å§%–Œ}Ê3q°«®ÚÄŽðˆÒEÀcv™× *É„9!8ïÂl0¢×ráyŽœ&¸Ò,6 vX“X¤ ¶`Õ—Ä{£-žý ð‹Ó"à8 õæð%Î ! Rô!ðÿ¾ƒåìVÉ©Kœ)œ~%± | Ë–OI,7­6ÑœÅÙ­™LûŽd–Ç»s‰|“œIdÓqAK,²á²(­¦ÀßU«Mp-Jz¶vÄöjÉÀ»99Ê–â†×_04ÖÅÊjX˜ÁÜóa•aF„C[;k¸Öw“xŸ˜÷B +‰Ý‘4ÿÈRä$ïH˜á…ô©‰u³Ï‰¡aa¤ â1À97—²®o”*Q–—˜Owp9 V¨0#!1±o•ÄJï ŠPÔcP¢Å·%,;oØëõç€'ˆ#R[ä¥Vu|Õf8Ñm@:­ ླྀZ*+=ªOXi9mb3­Ké9àLèl@a0µ2»Ò–Ž{”d³ P£¹½ [ ±D ô“4½eÍ>r{NjG-'-rËêköÔÕ¨IòtZ޽B°Aµ‘€Í(ù´Jˆ;÷‡À¸òm1Üg¢‹žS'¡3/О¤M&i“Ž‹sèá|Yr³l¨v­DÚUU(ÙsÊ3¥Õ›ëÍS · î©—*!>Še¸šîkX µž sOHo"IîøLÚЃ +EsZЋנ³£uÍ ]:ëò[%ÍŠ/ ¥A/dzp¥L|¨}Ò£%ÉœgHý*Y»º÷¡^{m;&Ý÷ùd–‹†ÚZ»ºæ@€ÔܬÞ*ëz5Ñ$͉EAóq…\£Ýªo‘«%ðS83¸Ù¼^÷È “‹o‘¦/z«ìÖµDæeHXw`,âAeÕÐÖÝÆ*Y¼hš—Û8jlÑIÃã{·Çë¶HNUâÝ*‘5÷"^sðÚP…ÔJz¾•Ù×ò© ¤Ð2`Í·'+Ó ¯]_‹Š “Ißø‚në×&êT©­ÖéLç"©¹?m%6Ö3Á«P±¶ž›šú’7ð@£>ce*í:ûš|Ó!°4¤¦C$ÁÈ ÉëT—•÷nýq®¼G]Î[ñ$Z×7KZ­ÚÁ‰_|È›uä.tsP’À´AÎØz€‚5ÒRÉÄCl$^˜‘.ynš"‰®r´gD/ýZ‹€¯=^ú¤©¸¡ïR®ËÅT#¹Õ’$ó·ç–GµPì¾´.þÒfCà»f³vn{‚–ÐÛŽF¾¾ŽáüD•Èt|Ò:|Åfõ¢Õïâ¦oè®q´ -NšÝf-¼¹ƒ 7îÏføÿ}…‡fþG^~úûævøÓõáÅË4ȸpý%žwï5(åÛÁ:y1&$]îúö0^L×ÿ:üùšÕóKÐŒSü”g`4þ¾üôþŸ½~ˆ;†iã.£ê«PâéHìÎßÇŸOð0[küø‹‰ 6{;%Ë”ÿqýèC“»O_D®ëï£Í?‚Mزqüh:‚³‰(Ϧ#.rJaü»DÑ—ñùtÄ朷~ü{“¼Kã»ü?kÇ÷±oo[Æ'¬ŒŠ5nüx‚Ú€Gòøxâp*öN-")= \0kb‡¥œ%Ž_OGp £_}=²l‚ûíë `)Ä$d B~:îëÙõ# à™­ýfb9/ž¿xYª/ü´Ã 21ÛcÖ¿þ\๿PŒóÅ[²ã¦#^§.¾Ë H^ŒãlaÐΩØñÆ)ðcF ¦‹·OVmïpˆ'Ž]Ù‡úV01kc?Ûý쇔Pùrõj‚²R|rjï÷yoòxeªÀ3pxhCØwv>ÆWŽ!”1ãË^õØw,è0!Œ¿äèL ˜_ýø‡‰ç½ì÷˜œjë·#gC’¨ÏÔ„wôÛ@Õ&¦#ÆjL0 ¿ˆü\>ê§WêÜS¥Œ¹Ã)þÝ•°åJ{³Ÿ®g’Œ x4]?Yý¾Tvwcø¨ ÷4©”Mí•J|æý [~üÃZ÷‰K\¡|1ñEærÐÇõ¯@Z å­<ïAv»zç•ò¬ï]ü ”6ôÔâ%—ÉhœTt®v þðRøÎè®^üö™ìÞº7ŒûÔÇ.•ºÚ=ÄSÔý÷?ÜBéÌa~}&Ò;w 샠ÝêÒ(_^^œW @Ý©˜·×ú>规ɾàKA® ë¶óÐNÖöu²#ÿž$»øÆNËN·NëŒî* °Áºlì5ÂOæóâZâ⊤]2«`_°2kŠ‹Vݺ¸ží\JëY'E¦•)Äï²fë¤Sž]ì–ýÓ½:¼Ç €4#=)ïáü†ÎÝ›ç-Ìð?¹ ÐÈ©{°—8_øyáïµ¾º“* åÚî Pç‡×š1©UÔÞµÒµ¿™¹|™ìß@›k3*"n?ë(Õæ:ÌPòg=K}ÈEKÂö÷&¶‘øÕð Ãü}‡çÓŒ¡2·-q¡w˜VÓù¸æãŒé´šK¥(ħÕÝÔ‘øéĽq%Œž#.ȧÿV#Ô'+·Ë¦;£ÿ¸ËþO”TŸëì«ç¬É9ÝV‡Ý}5J°¹ ~4<ñ–4Ág5¿Ç¡â,îüûfã=°÷ƒîÞ¹K]ÏÛû˜íñ¯Œó3¿ç؈|¶û9ùos$·SÌq§–ï™ÓwPÕÖërÝÕt|§ƒëÁLîÚNâ·µ¹{ÊV.u#Ò>{¼» ª¢y¤;ì} í€k2솲Û v ün£ÝƒÓWSÊfæÑy{®Ûu›YZZè-”ÿЋ'ü»W¯ùeJ§ñxû¢kEƒþý ÜDœÁ©ò·}ë¬E5^Ýbï-õÆ q“ýóì°aü«€Z€ã¦¿¬¿nøìðžmendstream endobj 48 0 obj 2560 endobj 51 0 obj <> stream xœÝZë¯$E,(ˆ ÷òPœ]ÉÚƒNoÕ©S/5QQ$A¾@nâðÓU0æ. ûÁ¿ßß©êê:=Ó³wX0!„ªÓUçý¬¹_oÍhikäß¶¸~´ùzãBôÛà“ß>Ú°o뛺öÙȺœ™ÖÝ~µ1£q– àr1pðXà·}ü冭 £IÛ`¾; v+Ï€„4FÞºÄyŒ$'˜öÎŽ.oƒM~4v{½q‰hd· äÜèÊ 8)ñè3öÑÑnƒ³ad*77póFpØÑD¹G˜iô J”Æì€Ã$¡¬Ïcö•jYíȸ‘™F>©ðÇÖº1ÈÞ%è7Ø&œÉÀ_°[¦ý‘4ì YßÖ˜‘¢Ü˜!œFDÕ}…X/XÓ$\€oÈ|¨ÏëÍ?7Ì.Œ1‰´E0ãT†´³`cK\tÌ)Ëí"K„Ž]L#‹°3¬Ú(ŒÈQC!0C#%ÙCQ@ÉÆÂ9ò£…1O !°–²ÜHc3-8 ;¨Å€AÕTÖ æ-Pu9ÊÙ`³>˜=ø³yˆuˆz½ùw`8RpÞËÿ!>r¢rÓ!d²˜_A,<0²ÅÇX(7¬6ò˜ ³K27 í2|$ ÌXÞráäf‚!Fï5ÄÂ.ÂP%ÙJ þ;cµ¬…bž%B{¦DFp4&hes¦íãˆj,…êÕ¢àââ{ÎÏ6⾫¡íɉ5ÈÝ ÎEñûâ¶vÒøcËAŒ¼Ϭo­@,.- †Gˆ…½/QHŽŸ£1çy­èTˆ¢<É|s¤—›¢+D˜)!Šc?R[r[¸—ëÀc¢Ùµ-(“3Âõüêñ…‘[LŒÐŽ3:¹€h3bèŒ4P2-yø}a5W¯tˆ¾â•VÌVhÆy[r|Æ÷Ö#0ĵ’°Ò¶$9ªX³£$½ [Ç*h€ŸKÒ›ö£¤ç¨N¸¢£IY}/œR•j‚TEÞ©VäD®(ºA´qQ¶hÉÅÂ’$¿“È·ÙHž œ˜®ˆ.~ôTÒd,i’$8· ˜Ï“m¦", •”tUë‘bà€Å’jŒMµòTÛõ£ÄK…°?Ê`1Ý÷ âk‡ ¼`Ũ2DU•YØùløÉ&k~º“€Mއ_í¢•J»úøäNá“BDß°ñžÈA6šüÐ-†{»=|62§áþnBÎÑÏ K\~¾Û£#rÖ ïÊÚ™è(¯î<¾ìâðœÜJ1ZRXï VÎÖÐp¹Kè]i¦„ÑiøáN$¬æ8ÛÚ.wÁPsf[oC(^D{°ÛÃÝ0 ¤áó¯v ˆ6B¢¶º Íû胅_Äø}y·‡<èÒíðÊn˜ð˜¼Õ¥_ì„@Jç?Í•™öлl÷h÷Ñþ_ý üIpЯíö˜S)A‘wœ9Âðv?/:ع¿C‡•zx+D@ã†ÈÑè0í ¯˜Õ‚ p‹ÀvÒkàk;4‘0Tºõú…|D¤GûTD•$ZV…à™Åx‘(‰be…îên¤:Ñçº~©~RΏƔºß‘>GN™ÃðK¬Rð> +Ë ûösïˆLðК~·ÛËè“HcZ%¯hªï—Š«‹Žá•â:$Å*Z¸nq–É.ñÓ 4ÿ‰”ÆVKM¡;ƽÎù3uk]MmU ýè¥2w=Ê!ž pwƒ‰lÈtì9ìŸ'®d¼T: „“èzß”½Ç8ÊSxê@T<\*®:Ý)Wkî}›ƒ¨ûÛ)Ð ¹ß¡G&äþg¦ÄÒ²Ü~-µ¼%)4å˜ÂðâN°%$™ËWA¹«Ær1F¨Ô2V,Œf¹Àñ0{¡uÏÖr!!éSH( (E½*„½¼¾(áÞÜÉû&e?8‘-#¼œŒ‰ÖKò~/¬AͰÃCµV>?.j~¡´Æ¯hïÍb ï<ÜÈæ›uV{c-üþP˜²¨1öˆí }¨ÖkÉNÉ­cêââ-°ÃÞ„EºÔ!¬D;‹ +`¬Ê#óµ½N»DóºÏ‡B3e ¹7ûÚ‰â‰NÔx—Tí|QÁ]ô§Ê¨•'ÌŠÚ¿[Ë·€ë×ßœaÚ!o3=)®:®gK\ZÞð£=04ðNU>é*ä ¦ cKs2¯u‘Xµz?cÈSIð|:ɯèeK?Ù³‡‹˜’´ÊýGÇdJ»ðd2a¥lk«í¢ë]E‰ZžPÑziY­M/¯«á)ìiê°æD×Îã^«éYç6^+@fÏŒè‘¹Š“SÍÌ·oPZ ÇØgLƒp‘ÉÉrZúXé_ä©CÕÔ¿|s/8§y˜€!Ùã^ð°âww™b×c™Ù“»ï ×Ć\žÀû;\<Á #RözG®hb—¯Ë°Â3ÃJÄž‘‰®ò„gÓ¢ø@«ò{_Ӷç˜Ü¢Š¼ì³£»µÓ×YW¸WÖý㌵gf‰Š}ÌHpp—zNÛÎAg*PxéÄ2"À ù“ßçå mICV:YÔ>[LÃ!Càw¥a²iø@DwÆ.“O(ºŒ¸P'Wqþc.Fýýµâêg:Ø—6›êÀÇ›«÷>SjU®Ù{“Õlö\¤¥…Y¤ †Ä…¤üyÝ*öÿÊ*¿´Ðu†—(=™˜r'kélˈAzô¬GÇVr7Ú?,OêÞÈËü±ê%ƒ™|éÄòlÕ·Ææ{Ôý{sT;3hÛ§¼n™¼ÔûBÛŠßËcðÔ—¶<ÖÅXkìW;ý4rÔêId©îF!P×ÔÙ{«µÿ¢Oßå¤ëÚ¥•ß&Ï«ÝѧçwTŠùîæêÙbýéérõAéÄ+‰¯¶àg[¸Î3òóµM­5ú“Š_h¹ç]…èíÕe¿toýªvÎ~¥,Šª¯”dÄO?²Fvø¢±§ tz¶;o<.éne<>l™'ë£Úç§3›6?‘¼³¿ë{zù=õÈ)?oRK‹ ÓõÏ=Ó~„Úœ‡Ï©‡Ñž?Û‹œû®ôšÙ†|Àà0º=´]*·öZ¥íŽ÷cy…‡GÙ¬-rư`“”RíÉg‰/<)BÊo9ªRF-<fUúé,$ê!OôÍä,Î’"êo™a!q›¹ŽLO?É}Oh-.ŠQ¬3œs >)mX>"êà{}%E¯z›rÜ;:›È•¨èV¹5Ê¿¬ÔÉÕ§ê§).g˨³Òô*‚ëîBûêâù³¥Ç'¼òÊkšƒg˜ÏËïh .fÃÈ»j0i¸¼§pžÔ#Üóýé­½ýfõ4¬O¾ü6¿øxùýKé2mJë/~«SÃm£Â øÂp}hè÷÷¤–VgʤŸlþuÒj…endstream endobj 52 0 obj 3163 endobj 55 0 obj <> stream xœÅZÝ%EϺ êŸ ì ‚È]Pè¹½uê»ÞÄDIà‰Í$<¸>‚1wHØÿ~çTW×é¹=»3º¨ÆØçLÕùüºðÃÞLd÷†ÿÛ>.¯v?ì\LaCû«íûX¿C1ü-gæïoößïÌdyc#d¹} øÀ=kÜþùw;O&N&ï£Éø»ƒ`Wð<81OÉï]öeJ–OÄ©DÐŽ&Wö‘r˜ í/w.[;y·Ö¹ÉÉ ?yÈ´ÙO¡€NnJ´Žâä­ÜhÜÀÍ#Ë É$¾“&‹;©Ø)@«µy*2Lfí‘B™J¨Zå+šD“ÇâídÙN+öy"7E¦]F pÃSÆIö öEÚ{›ßÈžF¶Â;x–a73ÙÄ7ŽÏ“‹j›BåP`©é&ËVÀnø|=ž—»ì¼wqJ™½•x y§ ¼õ©°4OÖKŒ}.|[|Iˆ±Kyòì쀩”ؾÂòÒåÉf¦(ˆô&L Î9&â€y?Ä´\øFž"§ f4Þ!,:,Bm%`CHtA«+‰ÏF*Žíð>À.N[€‹Ç5W/wßâ Eÿ?ܷМíÂ9vŽ5…Ó¯8 Ào¡™8ð)‰æ&•’Ÿ²»Vs„jW€‘ÌP9lZ‰´«*P²g•×L”Vc(×ÉS ³ æ‡ÔKåx<Šf˜šî4´„ZO3‡±' 7ÑKN|'­èÁ†…"‰9ÍÅÅ4àlýBsÃ@—κüNÓâ @çÓ£—ã5w¥L\¨}Ò¡%ɜ㺅³tuçB{ÆŒ‰A÷}¾™åÆ,¡¶Ö®£Ò|ðê&«#%`¡ÓŒ˜4×^ÈíZ]ó,æÀNÁ<Ô`²9MwÏfƒ‹§H“Àƒž”ÞJ‹gN–„åÖ"^T î:ÎlE“Ь\ûQ}‹VÏML=ö-Ö5læ+ÇÙ…#4÷"¦¹@˜6¾†”¤Oe6ÄðP>V†´?¯ yÚ8O²Í0m;-"‚l&ýDàÝèÕ&ê¾B[ÑéšÌ™Ss\s(Ö;Á)WASÏeM}É«ð€£¾C²•v™ö®ÉPR“!œ`d‡d:U²âÞ.Î÷È¡­Œ¢£ƒ{†j<½_èË9­¤NpâgòŠŽÜ….wŠ8FGÍAg;TG X=-Lˆxˆ Ä32ÒŒ%ÇMS8ÑVŒöŒhÒ-U03xì1钆⠾s¹Îƒ©zr¥9IöoÇ-Ï×B¡}i!güúÕÀ³fE[»¾ág×Û‰¾NÇpýFåÈv|Ô2\ÍbE«ßÙL×¢»øÑ4?ýdW´dðò$6ܸ¿Þ™ýøßwxèa7àÿÈËO_^íÿx±{ò4íe]¸øÏ»‚÷„òŸiOV^Œ ‰G—»¸Ú ÷Æ‹îþtÁâù%h Ö)~ Ê30‚½O¿¸ùoÏocA±_„aT ²5”x:z6ç/ÃoFX˜‰Œ>¹`³óÃaLÄ”ÿzñ%ä¡ÉÝ$‘íò†=»÷B ŠÑê_(e h}8PÎ…ŒËgÆ uøŸp&9›ú ~>rGHÖ†áþH¼‰¸P¯•äJÔÂÞ‚_x’S~ÂúèÊðû;f(1 ?ÙÉš‘['þ•îÆÎ’î}ŒRäâÝ'ãˆÃƒ Ͼ=0(ÁŠöõN„bHì: 8¼9& Á÷·ÆÊ"àñ­.}:²‚œgËŸ<-Õ~ða}Ù°ñãpñ7ðéÈ€gíð«èàá"4àšRÿlÂëãeàA§O܃b‹Ý/ö³)(î}ö1£Åá}@6#¾7È}s¹×°íçTheÚÛœ¶À¯+¥â\~nqäIÉz§ëý¸[óîrrVà2¾gÞ³Ú0%bV†åQ)ëÆÌ"Wq±gÛšÕém]›2ìdÐ$ëtÈ?açâãðh¹²™1•m‰òð`ˆ_$ÔtûÏ•Ø]؉tÓä_ñ›#±ZhUh»TXN“¿ÎÇ+K~¶¥‰doJ>oÀ2ÇêЂuÀÓÒÏu¦`{Cq‚âz)6¹¼=:ï>˜˜uÞßüì—÷8½¸Ð¥/-gï/V¹”°­ÈìÖ=Ø”¹‰åˆ ÷æß_‚oås·äþ 6ƒ· "±ÛëÜŒí;µ¶ðN­²ú E ÑÐRªÞU]¬Jw+â­_xÜBùÇOŽ}ml,ÿ"ÌV³â=Ö’KÂù7F—Éçoà #X}0ø¦„'X!ò"–g ‹Uñ<—Ô86tplrÉBÎÙ}ƒ{#ZÇë#ÿâ¼NéËfA‹Zž°$2ÅÆ&zX?ƒ9†PÔ˜üWGNK­ ªr\•Ú³Ab• |¼Ø + žT&¸¬6À7¸p»í]*ñ¿(¼tÅÞ9ÿ.ÙVHÀ êáÕ¨\jðîáÕ¹ÏCþgY.þ(ñ[é{1X²iÝ­¯5nþ ÃX·Jæ/ÑžMù¸Ç!Fý¯žžõª„Þݼgj+Ó÷öR¸ý’ñ‹ž]V=c4„þ©Çšla:&­¬4Àÿþ¯“A€æÜÆ@§-D|ÞÞø¬² ë=SÛ‡žo›¨Y–Øð‚ìÿGË?ÞÛ»¬.wñ¤ÏÑÓu-­d_Aû¶¦Œ:4žnI·]ñÂÿú¹µ¹ç¬Æ¢xµoýÛ±~æÝÜ[XШߊõf€Tî¿p­´zŸ~)€7£©ó’¥üöÛÿ­Ó=` gg:±ëlµ§Îíkþw ÅU‚ž=Gð¦½G×6ÜU¢ÁÖûÿå(Xµ¼Ö[·‹ÚÆçiŸÊmƽ˜É¿„þÿVð¯úÈßHFè3€ÔÔÝØ›Ãj,tnè3¤gø«~rkl8rúÓBB´Šðwz*.?(~½û7AËêendstream endobj 56 0 obj 2660 endobj 59 0 obj <> stream xœÕ[[¯dEÌ€Øg¸L7ƒ¢=Jt7¦7u¿ ‰\T"ÁÈI|ŸŽ‚1gHàÁßï·ªvíZÕ»öôéE1Ä®:U«Öõ[kUm¾Ú‹Qª½ ÿ•×7_m´óvïl°ûÇcËï›üÛFA¿Óšé÷Ÿ÷_nÄ(´4B9ÐÒÞgñû”Ðû¯¿Ø)Ü(ÂÞ‰€¿kÖ¿¬ÁŒ £7{L½¢nŒc-G÷N; ¹¿Þè ÔhôÞ)­Gv˜Ñ€¦ f´c¯G/÷NK7•v”ìÀ΢!Gáiöø¨F‹S• cÔ !î¤c´ùÔôË /GƒѨQŸ*ñg¤Ô££±Ðv°’$NîòЯ#Iqa4$ à[ 1*O;æFíHÕÊÛ<#-QM=*â|CæS}^oþ±1F»Ñ’6éÆ3X!­ñ‘¨©LÒ± ‘v'YÇŽä´µôÿ_áä æ™›:£D$ó³ GFádIŠ÷>\¨JoƘm¹ÁÑ:ÂGÍ E…w‡èHø2s3Í8:ÚÖò khk@•Jæ£à¿3UéÁšKæiÏIgÏ')Ah5h%cTû¯ÿNª‘Êe¯&'Ï ßÓvž1‚<ÂV5”±’‚b r—­=ù}r ™ Û™)üi¹3C ßÕ™‘jÔ¡™f„XÛ… rÀ1àsjŒq_³sò ;y’ùf¡—›¤+D˜Hˆàɱ³™°ÃH¸ˆI.×Ç D£.Cœ¬´ ®ç¿C=61’bË(ƒÐö39Ú€hdèHH«,ü>±³WjD_òJIfKgúy˜0>cëiäZX)CE•¬Y&£Æ¼­“c%2 oèMcâ‘àÙ³®(ÉhŽ «Ž‰S•¥šf²"oª%9I7ˆ6“”MZÒ~ž1„„/ ‚QäË(gœršL—D'¿<%˜ô &ç¾æãd›iAž!% ®2Ád=Å8a1A!gžì±`[ ¤xÉ3FÀÓÉ`1]Ç8ÅæxšfÈ÷’Ó g’ ´Ç7À`ADaÄà§à¢1ÜY™yL€”<üæ™rŠŽp:ã;5OÄMa¢mÆI H²ÉršTªç™Õµ¶9í•1rŒ³÷igH;& ZëyL; Ã ³jÉÌãùˆ2S˜˜[)R­§ê"™•||&ŸÇ1Èlš«dÓ 9e‘B½dçæq’L§"a^²ˆ •™B×3晉‹B¡pÙÊ‘es*åMd=’Íå2lš¹É3ZÍ3iLXDc  “U*SjÊÊĈ ¤|“'œ˜©À˜²62U34VuœHØT™Ô–tÿ+¯ޝ0ÙµÙØŸÐœf²íoÚéò«™¨˪žëlúõ`Æ9¾G¦ª´Ò¬c£ 4/µ¾ÐH3V¤’Æ>³ß«ùÏ!û=l¨òDäÚÁ>!³>™ÇדY%[A†ŸxÍØ ]oØŒ%Ýð CÚ#s € fIcv&hܺâÄ“gøÉ—4fšq*ûhµê9 ¦ J{4Ôž»bã¾S¸N‰)Kò˜ÏøTk‚<“ENÞççá俦Y`)×4c¥Úf½¬(ÎWÇΞîÈ3©:¾á4tÖÍÌE‰ß‰M]´;ËQ9ͨšq²àõB7ÜŸlÄþCüû=ÔôOêüøïëÇû÷¯6oê÷©\¸úí]D¿¢ôg¹—*uŒ†Ê]=Þ Ï®þ¹ùý‘§NP”SÔ ¦6Ð ~?ýpýo_߆‰ƒMÃ’QfHeU¢u4ÄÎ_†ÀaRèálÐf^R…¿^}z¹5z”ˆT¥7ìI¼'r?þ¹Ã¡ŒdƒSïŽç(…¥Ÿêð&­ÐÂkåë 9|ÿ@ˆà•²Ãƒ¤JDÛ¼-zÝð„A.c9ÂF)‡ïH¢¬þ[[ÂÄ*rÌlÛ½s)¢“(¿8á^¨þÃðÙ—ƒ{é‡gç_÷À±õÖYOæ­tÃýÃÑ"­HúÒሰè´Ù¦_è€&Îßþ4f^¨»C­²?¢¼G¹õ·Ä•þѸáöG- úhI½‡çQ¯ˆvØá(”ÚÁG9¼B*³ÔÎðŸIg³÷fbwIÂÌqŒØ«‡#Z`t¶uöµyÓ–±Ð%ð<ð}äÀøbܾ|@wƒzÙsi&=ÚRN¡+/_[¥©ÿ ±…ÖÙè› Ã=ü Ú ÎÚÈÞ©üO¬¢Ä~T5À”±ûHÅháØ•@$Nlö¹êªˆvçÐ6à¯Ï¨÷†ŸÉÖUŠÏ%ÏQ658"» c™ý,Û5‘—‰Ý3óýLž“ñéw˜~~ j«†Úë˜3V¸À\œsð cÝÝtUý ó€Â$•³ß§¥}¯z9£‰'”zæ@U‚„|œ4|DÇi¦ˆ|T…o8nÊ1q&²ÖøF ÆCŸ.O¡:{FNõ¯3˜(++žÔXø%3 Ù"›‡Ü;CSÁÉcœ^'p Ñ7¼x ³‚4ÃîôÃað¿[8Áæ¡À†›D–@÷Ä‘wÉU5I1h’'";Ò¬À>\ÀÕ<«iÕ¤±B™äCƒ€ü«‡·“{Ѝœäz¬ ÖH¡—F 'ÑB·²*ÚÂ-i„Q­ÑtgÅʩ ~bq‰0uõ† GôìQ;;l›ÙySïÏ+ï±3V¹e㑨ŽÉL¾öá,Û2´t ¬qÕnÅübûrAºµ5± `Ý÷Ù†ÑÄýáI~’\ÇYØNc Ùh`Å•g2IT 2D&(“b·‚„k2CAJ8ÃýdÇÔ\[Õ³^)“*¦¾à§ø=*MÝJl¢ö]æðÜù·%¶mLÍǦjábáÛY‰z§ì{µ›‚³ï±óêq•£Øp4/¨ªØb6Ùž5ya›È㜕pm6yÀSįÖóZ¾–žÇìT?Ua/WÞm™|Ä‹ŽÊäTi܆Å]ôxe‰®»eÿ“ò>XNÄ5C\$%2/½õ¸êЙž/ÖšYdW¨Ê¨°“"Ú8vrü\X:Ó¹ÝxåHÒ¨åŠâŠú åèÅ‹_•±w—ƒ7YQ…{Þ/,ávÆ –ï'=‡FÑ„¨82DAîU²üJãcÑ7Yní{^$Á±UÖmÊ‚W« úéìH§½êWOõÏýü¬ºøõlªƒ$ e¢A_,Yry1ÑŠ!r˜GpGax¼âJL²êvsR·“U•C,bcJ‘ùð „uŽ9-^;Ç8ž9x“ÉIt‹ÑmÍrLÝ} åb÷áÝàÝï+9¥L«ûNp¦„>© Ê‚íJÕÓ-‹º¼žmYWþV™†7T9W ÒÜ]ºQI[ ûëÝ % ½­8kÖÐîrßyRóÜôf~MÓœÝíFíý®{VçcªëŒ½°øFS7=œW®ï¯õÜtË]Eº$8‹/+w0MëýͰˆû9?b%˜ÔZ°öÓEŠúIÄRì³ôÙÖ¿ïƒïµ:éšf¿`mS7­7—+S¤†U$AUÛ¤gоãQqøA}®ÉÈòo é_c?â,Újù*/‚cÔMoÎܱZâð m©Û}«vB,bëßÙ™MÄ`ǾÓ'Å"z0Nòö…v“({ÆÈ¬Ókx É|ë^/îÖ<øÁL´±ÎÑÃWPÎ /ü÷ÍÃñ!×J¢‡kÔßï`?¦;g„Œ´š¤Qà€Ž0FÉ0ü.]™ ìjª>Þ\½õ´ªºì_(O12p©v—n^ “D!˜‰¢’ ö»µ ÆOôúoC‡‹ú„°†N;æÑlI½eìú>‡Õ>2iÈk`ùÝ*žõ;DD5Îü³èðQ˜°J¨z8[ù!=uEeTl ÷&=¼Dh>pbçd©AV}2ðÑS´Pzµaá1ÂÝ­`pÿ2nÅú—È5]±Çž^£bÿ×®ÌҨԻ殓•&£Û…/žEx™fYLu ²[äGßj‹Ó­¶ynÏs®éò»íü-ð 7·tq€5nÏ1äa§¥øí,ÜõS,lùÉòºõâË®5RÉá–X‘/N¹ âyŽÏqY9«s¯õÀ¯ÿDÇÏZö²”i¿>­—P“|`¥W¹Ô´x? º—ÜìÕ½»ôÜ{$¿—èX¾Õ·ÛÝ0aô®V·ýîvW¯áùp~Æ ô]ÕÅý«’eäXBìÕÀÙöèÌ¥míš{—Hgo¯{>Êkæ¥g¯Ÿþr„Ê­nïþ/×]ÊZõŸ’©›8{¾rÛ›7^¾1FW^"V.þªîšÇ%I+/ûº”÷gVú}h7.|Ì$˜‚.øÜ©æ‹^âgAÁ‚´} È/?D=Ô—ŸŽ”»sWš œz0Øyé§ÆX§°[)ŠøÛ=~hãä“læ¢j@N¼âäu´óþ(›¸~-1(ô ž{“ü^ðãÿ5οtPìŠT¾Õ¹ 4N>:òç‹”{ú\ë +Ÿ-uµtþ’S¢¯Æ¿“›y[[ØÊT¿ŠÜ¦2K£¾ø%l@ˆÐç6õQá¢Ëa½Ë ö0Ðýk»ö‰` OçÀ`¢t¿ œø¢wÔý,MS |#[w³Ê |.<$žqô-Ù«õ3vA9ƒÑÉc…ó£Ó¾y¬èÖ]TX4~tUxÚøe x×âŠÎ^twsÂJíÜ…ïn`0«ž7Ýýε}¹Øó» ^¯Ö»ý;àEË {ú/攢ûŒc@#å½=©ìsW‹ÊêLçŠü.«ûSU%·í?‘í˜Ye´¢ãusQ¿Ë¡Èè[ƒ×(,JÒ7ÜŸlþ b mWendstream endobj 60 0 obj 3882 endobj 63 0 obj <> stream xœÍZ[cGVÈUNÄ%°v ¼DäÞ¾TßOH€”ð’h$Xž„<‘²ü~¾ê>}ºŽÝ^Ïl&h³ŠÖ]î®®úê«K;ùf«•±[ÍÚ‡Û»Õ7+¢ßŸüönE¾}>ÖÏ>kþ\öLŸÿ¶ýz¥•v†´ Ðåb àñç¬vÛ_­Èè tÚð½ƒb—ñÉ$!©H[—(«hyGP9`íŒryLòJ›ííÊ%k¹m°Î)WN"è´‰”ÏXG§¢Ùg‚"[N4 Nàä‘u¥#Ÿ‰ÊâLÌVyÜjmRÙA‡N|{0>«ìë­åSÐÑ(‰LVY¶Óûȧ¯]8A&a'{û‚Ù’À7°§­ Ïì6Z+ùÄ,¡¤\`¨môUbÂA¸x(›x   ’´WÎ9ë•aÀˆ&@,LK™O$8L0 ¤!X4î°€ÚÀšÄ \¸ ·ºyo0Ù±DvqØ<\'®Þ®¾ÄD Î{þî[Üœì,9v‰Õ™Ã/$D€ dq³aàc,77­&’JÅØå5G\í28’X¦-GìN9°óMrœ$¯Ê{)1ˆ†‹ˆ ´¦^þÎZM„i¡„gyO¹{¾ÉjvÀY•€er¶ÛÿbhŒ •Õ pasÏùYBšá; mmæ\ƒßMâ\dÞj˜ؤÙG†y a†g’§c•K ‰&·°ö% -ü1À9«rž×·âž*7O>Ïp9¬aºT„ÈľSjP„ e@0)š][âfë4[=x|1¤äYBjÇY@¶itF(•Öz𾘚++²¯°ÒpØÊq^–šÎø¾Áx$S+±)mi¹F•h6r”—TëB¬¢ú©½iÍ6ryŽbG -pÉêk¶ÔV¯&Iòx-û‰ZQ°A¶Q›Qrq–W®/Žq曬¹Î‡®¸Î¼@y*e2–2i99·ýBŸ§ØLª„M@))åª*,ѳ€K©Ñ&ÕÎS ³5úGÉ—*! >–›a6rº¯q‹¯ù4I˜{…ô:P‰Á™€ÏÄ…5X³R1Å)¹x :[š×\0P¥“L¿YÒnq¤£8ôtâûaYØt÷óÃs­|Ÿ•×BìÉu“­/…+ã+®´ùþÆgÃÇ5ë!¨ú†ªÙ=ÿúá)þººùíÚѸ5,ÂlѶ.ÌÏ—êd/ ÐaÝ}ÙS¡¿ÒZï_Ïîí­dܸñ¬×²"}"S©E_–©Àž}aLý)㜲dÝ"!ž¿x1!Öà‚Æ”‚NLgË~¢ó<…užL}{þèÊìp5Ïf¢"¢ló«(®zñôŠ *›“’¹œùá‘c_夿)|Ä9m–qMDƒä!ëg ÿ¤qT?¨¼¼¢ô|Ö…ã’.Nýræë=]†Â3ý,ì?€ ©°lø UÔÞ7¨ù /€ö€ðsq½¨÷Š iáÞKÇ8°@uõ!&®íùùqMr Šblï¿¡þ={ê<;i}myøÞŠîU‰bØ<›.bÖ Ê(ë!=6Ã@rx"´æWŽÙÿ©ç?eþ}´68”DëEíþòôVe¡_ðºåäœ~ú’óÿÏ“D´(éûA¡¿ÀŠÁÁ›û>ÁtJ:苾æêÅqúµÊI%'/ü¤“”·>Üë‰2`äÛücjLFN.TåPüî/eãlá½r°½¬ûs:ÉnÔo]ÛÕ{râ(Å÷Q[÷8€'É/s§å¾`æË«õòMrV­¹ |GÕúۥƣÐã;-ÑÖ—e¸„{áa—oýŒÐ.Îÿ3T¥ÔŸnVŸãÏÿÂÁ „endstream endobj 64 0 obj 2744 endobj 67 0 obj <> stream xœíZÛ¯$Eϲ‹â°‘•ËœD!Й¦î5QP$_ 'ñõé(3KÂ>ø÷ûûªºº¾î©ž™³nÄ!„®oª¾ûµê|·ƒT;Aÿ–›Ç›ï6Úy»s6ØÝã±åû¿môöŒßÞ}»ƒÐÒå€K{gœÅÎ)¡wO¾Ù)Ü ÂΉ€ß5ëˆ/kqaðf§ƒ‰ƒW´Ã Ña­å ãÎÉ`!w7”ŒÞ9¥õ Ó 3àTÁ 6bíõàåÎié£Ò‰Á œ<9Ogü pÆG5XPU* Q‡DÝI‡h3Õôå„—ƒÁ‰hÔ ˆO•ø3RêÁÑZè'Œ ØI’?'wFyèב¤Ž¸0’ð-…”§Ä„A;Rµò6C¤%¬À©E\€oȼÔçÍæïc´| i“>`<ƒ]Ò ›‘Ê$›ét’ÅCÇÚ‡Á°¬JOŒÐRB`.} *ЊJ#ìà!œVv¤0cF…(°"ƒ#3-8ÑP‹ U«¤°‘0hªŽžö:5ñaŒ_d6 ¡Ž…¨7›¯q#9m-ýâ+Pj‚*D‰Hæg GF²$Å{Ÿ(¬Ò›!$fçd ­#|$L(²(¼;DGÂÈa„8"ík9DÂÚÃP¥’™üwÂ*=Xsɓσ *›æë*Ù!ç¢*R0P¡—Œn^'Étj¦h‹¨Q™0”u¥1AF. †Âå\Ž,›S)áQÝDÕ#Ù\nÃFÈ!C´š iM¹ˆÖ ´&«T¦ÔT•‰AEù)˜±Àšª62u3´VuPØÔ™Ô– tYÿ3ïŽï0ÙµÙÚ/pŽlûÃ"]>c5kYÕs“MÃL=€8ÇÏÈÔ•VœumtÁ‘ ðRë Ž±"õ´öy™ý^M?‡ì÷°¡Ê€ÈµƒsBf}3­oF³J¶ƒ ?òfkGYèfà –ttàd†tFæÌ’ÆìLиuʼnGÏð£/iJš âTöÑj¾ÔSŒ*{´Ôž»âÌ}Çp S–ä1‡øÔkJy&нÏOËÑÍlƒ¥Z3[+5?aFÑËŽâ|uíìòD†¤îøÀq講‰‹¿#›ºhw’£l(ršAÍÖÉ‚7Gº¡ÄýÅFì>Åß`ÐCo@ÿ¤Éß<Þ}|½ùðK¿KíÂõ×ï"æ5 ¥ŸåNª41zYîúñ¦»Ó_ÿcóÉ5¡§IP´S4 ¦1Ð ~¿ütý·'—°#AØÌB1Ê ©¬JŒŽ†Øùªûiƒ”Bwoõ°A›îÃÞK  ð—ëÏ€In "Uñu;ï$QpòÏ÷{„2Š ¨¾ÔïÎQ Õ½>&ÔîÝÓuè÷ËÂèîG=e¯”íäó6JÙÝÿà[ºî^ h3¢èutÝOð3&sŸg‡~Ø“ŒÙ ÛâÅ*ªÎdís)Æ“pïõ{8æÐ=ú,iç¥ïž›¾^‚Ö[g}âÑÞœ}ºÇ{D…ÅìͽßêüŒÉ¶‰™D°öÈ5bwýWP¾Óïá-]>iãÆi”þ=æÌi×{dðë^ú¨¥!}€2ÅþŒN g1¤èî·=5õŽ9Ñ ' þ<ó‹]S(2¤F'©’ ÇÓüóÇ= ‡\¸ ïôÔ[ 2R•â I¯Ã1¼­€y†±›Ümúý#ьәnÁb Ht4zŠÇv´í&w5c¨… n(Ècgåà Jç!z{¤é®^7(GYÑ¿[ˆÞ.Btǘ«!ðåNg/é Ú†Dˆê"b>~•4§‰óN“ i;´ÜÒ˦[2Ág1€ÎÎK4…–ajÍKDåf8Ï'‡¦¶én]E[ØwV"»’ ´W3ab?dÉÏC§qFþw%õ?ˮՇêÞãÀ?Y‚ˆY˜£0Knzæ›M'ý¨‘“×Ù½Ûré»íhÝn«Éï®N´ÅÕoGù ˶”¬}ÐG õqô8C£3žG],DA‰®„ÌJ[‡FVXT‰ÚÕ½H¶ÃYô¾ï÷T- “ö³èR¨rägëÉÅiÃZQ=—ÒƒDü³:7ÖYj¶Ym¶ +:ôÔøNß×Jª Î\³Í¼@4“A³½…²,Oß•ñóÚ@‰±:p·y°€b×§…õDzZ;úâA ^gö·-ånŸRcÛó%¼9\Ú‘,•Õî›…pEñ¥]¨Î33ÍJç¾åõ©ªžãõÂáá|lòÌÍ9œu¡qä"c¼Ä0—ÒÄk=†·÷‚” OuSæ‚_(Ÿj6;Õ¶áºî½d«ž2˜¨Àû+Ÿ«¾´jߣî?˜º¾ÜmBÛ85\OD¿¸bÚ>ºíd½RÉc¼WnMRÌA0šWU63«‹Ü¾ìfô(õ.ûê§k×JWH¦e„Ÿu…9…(kÕù‘|ÀŠBÊ[Ir§·žž$fi¦(Ð2¤5õ4Û±õÞr<A?7î<šþ#÷«x¦‹›Øñø­o‘Æs‹Ûìºî'VzßVi[÷‹3ï®750.-¸ÔÁ›ãd-Li¥!li£ytÕl‘¶LÍ&¹å í9¨Z¸žù¼æ§&N¦ß»},=ÍF+²º3CTO_Þa²Ç~ïW‡ì ï4Rèð;•F‘yݹäàn5ËñªtÛÙˆnÙQðßH¹§¯Ù™R/k2SòêmP*€'bw¤Ãe(Ý[¦ÄôL¨ôjò?›‘/¸}œŒÒœ-Yý­ÀvþmZo-&Vo¼“¿çªæpœ”¿žœo=}Ù)¼ZW­GÈöámL“qsyŠ+{É-ÿJÞý÷gþV<³{—«–›Ì"ªÔ™„ÀÔ°mÚ¿UÒù¡J©™[ÚJä[2Þ«¹`yZOwÁÛm­åͬÞ.žs÷áW ôGÞÌßärë1 vŸõôvnáȬf)2w¿tS8¶Ä`‚÷`³þ™úzL·õÌùš¿—ôWŠÊ?uÑ?z´å^ôŒKý‘“\PêGÏ`¥¾ÕŸÏ*}+U¶_²O{0Šõ:ÑŠ©fndʺ»,F­I¤ÖÔ³%}v-Ö¸ujºÄÓ\‡^,7 ‹Tž¬¶Üßáñ^Þº¸)³{fqzÀì­gåâÑú+Ÿ€‚¸ôÞæDjéÉi{|y¾>¹”§ËÈ^6Çw—-Ú Q.ªÔ÷ýdùyí(ï<ö™^ÍQ]{îgðòXúÚ”:ÞtQå›®ÿn‹4î/éºæÜÅÌ ü³ü΀÷[Àfm)¯^þ_y'•÷}h/žßì–SÍ Ì$yôí$Ÿ­Pv7Ë.Ï͸µ”Âô÷_lþå?Žiendstream endobj 68 0 obj 3593 endobj 71 0 obj <> stream xœí[Û¯$Eì"8lÜ,s¸ˆŒ@ ¦î5A$Q_ 'ñõé(3KÂ>ø÷ûûªºº¾š©>3g#1²!ÛõuÕw¿VÏ~·£TAÊÃõ£Õw+í¼Ý8ìæÑÊØò¼ÏÏ6 zN{¦ç¿l¾]‰Qhi„rÀ¥½3Îâç”ЛÇ߬ŒnaãDÀ{ Ä:âÉ@\½Ùè`âèípctXk9ê¸q2ØQÈÍõJ¥F£7Ni=êtÂŒ8U0£X{=z¹qZºÑ¨t¢@p'÷„CŽÂÓ?*œñQT• cÔÀ!QwÒÆ1ÚL5=9áåhp"5*âS%þŒ”zt´Ö:À #v’dàÏÉQúu$©#.Œ†d|K!FåéÄ 1aÔŽT­¼Íi +pêQà2êózõ•1Ú>´I0žÁ®i„ÍHe’ŽMˆt:Éâ¡cíÃhHØV¥'Fè)È@!0—>Fh E¥vôN+;JR˜1“BX ‘N„Ñ‘™ÀœÆh¨E€†‚ªURXH˜ ´@UGO{Œšø0Æ‚/2›…ˆPǨ׫¯q#9m-ý ñ(5Cö¢D$ó3ˆ„#€£@Y’â½O” Véͳ-™=Hë Š, ïё𲟠ŽH»ÑZ‘°†ö°T©d&ÿ±JÖ\2OK'Ñž))Ah5h%cT›Ç'ÕHå²W“‚“gïi;CŒ °U e­¤ XƒÜ¢µ'¿O®!“a;Ÿ‘Æ‘‘;òðhø©DªQ‡"̱°¶) ä€cÀçÔã¼¾ft2„QždÞéeŸt…)#xrìG "Sî0.b’ËÀuà1ѨË”•Äõü걉‘[F„¶ŸÑÑD› CG¤”i•…ß'VcöJèK^)Él‰¦Ÿ—)çÀglÝ -ƒ\++e©(G%kbÔ8J/ÈÖɱà7)éMkâ‘Ò³g;\Q’Ñ¥¬º&NU–j‚dEîTKr"W$Ý ÚLR6iIûb(P~QŒ"_FAyÆ)§ÉtItò ¤§”&}J“Š‚sS ‚ù8ÙfÚ!ÄRIJWa²žb °˜R!Wžì±`[ ~¤xÉ#à‰2ØFL×5¨ØO„|/9½p&Ùà@g|@„F ~ .ZÕ™×”0¥¿R¨è§3¾¨áx n msžÔHI6YN“Jõ ™³ºÖ6—½²Fq–ç}:Ò‰ CN­•F^Ó hÀ° ¨¬Z2óz&Q …‰ A᱕"•ÑJUɬäð™|dPÙ4_WÉ&9U‘‚ ½dtó:I¦S“0ï@[DÊŒ¡¬+2qQ0.[9²lN¥„GuUds¹ › û Ñj†¤5å"ZS€ÐZ˜¬R™"PSU&Få}¤tb¦kª6ÚÈÔÍÐZÕuBaSgRwX*Ðeý¯¼C8¾Ãd×fk€s‚dÛï[ˆtùŒÕLT¬eUÏu6} zqŽŸ‘©+­8ëÚè‚#Aà¥Ö bEê!iíó2û½š_‡ì÷°¡Ê€ÈµƒsBf}3¯¯'³J¶ƒ ?ñšµ£,t½bK:Ús2C:#s € fIcv&hܺâÄ“gøÉ—4%Íq*ûhµ_ê9 &•=ZjÏ]±qß)\§Â”%yÄ!>õßšRžÉ"'ïóórò_Ól°TkšµRí 3‰^vç«kgOdHêŽ÷‡Îº™¹(ñ;±©‹vg9ʆ"§U³N¼>Ò %î/Vbó9þÿƒzú/M~üùúÑæ“«ÕG_úMj®¾Æx1¯)½–©ÒÄèaxd¹«G«á™íÕ?WŸ]zš…@;E“`à÷ËÏ—ß=>‡ ¦aÅ(3¤²*1:bç«á§[p¤zxkK´äÖK  ð׫?’Ü>*Dªâ6$ÞDÁÉ?·Ý!”Ql@õþv‡pŽR¨áçé1`BÞ£Zx­üðã-¥¦n¸»…›ô†Ãå=Ú=^äsô膗 q ¥žß’HYÿg›ÒÄ* ŠÌlÜs)¤“,ïowð/´ÿaxø-ØÃè/ýðìütÜ[oõÃ-uŸVºáb»³¨+’¾´Ý!,Fmv胭¡FϘlŠ˜9AÀjÔ"6Wåg¶;8&U‡GÚ¸C=q•~‡öã@Úõ>Ù7Dã†W>jiH ‘Õ{œ÷hòÜp NЊåð iÔҸÓJ'YîÏÈî’r’eÈlw‘UÐqXWèkó¡5c¡‹àG„ÀkÌ™㫾ÂS{¹ª‰C±õ$Ú3Õv’ ËγSÝ÷Ln†êbÖל늪¼·ÃoH ùÆÀ1(¹™ ‡_@tå¢9¦;Eæ†æ›ÕÌ.—ï$§¡9$*UªPe[;ÆnÔ¾W1Zm‘M4º.¥mëóã‡[ê´5 ç;Û¦8®ì;ÐùÔ™õ@ÅŽ_´Kíÿ‘v]LY§ƒô™-õpõXEIƒZý¤©õîÁKÆùEOœžçs2~^ëùÕ“83 !Ž“F;o¸×œ øTm¬p ôf÷±+P—9FžGÂË9ë°”.–BhÝõ¢^à±×]q{9€ïäT‡ME}Ÿñ%°n#Áôaš©2Ôj¶Sè¹ThJÄ”âCôˆÏ·Äd€˜—¯€ ”(0~5Þ[pÖ/Lt͘+$ðåf'…0%BT+‰ãû2I¦I!ƒ&ÕÄ`ªÑ-༞*ÏÝm­BEj•ƒ¦ÎKeg†iñ#:.ET8ô ç¢·Ê6t­®¢-l;+‡×“æµW™¸¯ÝŸvømbP¢‹³ù¹ç´ÌºÑºÍÊ($Þ‰m²q7?½ÙMU¿c\U^–øf!¸f¨I ZMßÅüä­t®¤.‘³DäN/Œ’Éz]Sk n'UM²Ç<óÃ<¤1¨ò{8$¢! ‰|Xk¡!Ä8%¬¬|‘l޳h’?ØRY‚HÏo›TS'¦Bo߯ßW kEõlJ"Ybø ‹Gs†ŸÑVñ[k#jVtô©ežŸ»åjNžƒ:KÁ<ŸïíJön•ì-4‰Ð†•ñÓÚ8êY, '£¼Œ5íë =Õ¿.˜é]Þß’+…KšÆlO½ë'ÔÙú¨Z¥„ÌQt üºæ!žýÒÆÓo¶»ÕsAõR¡Ã±ú‰z¦ñV„oy}.¾§x]hçåˆRbo¼ös›&<Ž’\dŠL©ñSº¥ëG=•·÷‚ƒÁ¥+ôt¡QæÅÜ…ó.½ºËT‹¬TmƒÖôæÁ–ܽ¹»A„Si­òzTÍ“›Ÿªæë¼q9“-49—¯Òµ€QÞÛ›7ùÞ)“õ-¶à઩‰W ¯|ÐMmûؽ×J/¨ø¢›5ŽŒÜtánøýŒµÖ Ž~Ôð’{5µÕ Pd ñ~oáÑ#ÎÅ¥÷óã åQ ‘é䨺Y¥…>Mý¬2ø=j’aøŒD×O¬ëZˆ´ÕÖ <ØÎ.Î?lQ·œAWð+ÆÕÛýÁ;Çw*^]}øS+sÍÚÝïy6oʳHº¾NöNÒ'VÌ’]«Èÿ)«üÒB×^þ9Ý£FôÕ±’•êlËAjôô£cê4Ð.ë^ÐG¯cÕSxoáñlÕ—fí¿¨ûz”ûMh[§†ë‰Øê½5Ý”**yS·\òï–{ƒ×ÓŒæ…mFÃQܾìVõ(õvÖOÖ®•®KZºÂœB0§¨Óƒ_åã6’Ô¦øÔEnÍ= m¾¦ê2u~?·t•âÉ=]à”'v‘rÔÀ– ·A7]dC˜æžôxú¸˜Û¶žö÷·rΛ-š|E©1bŽ:ÁÉ´ÄGs|bN.Üòߣ’¤Uᤩ{—»§Ý£i%-¬bsÍË?‹<íw€ÿÈõi¹k¬ÁLÀr}çļòÖ–~'ªeÉ#z Ƴ˜1osås«Ï<½Ù²½œyn;Åsn&r¥:ºš8¬vÇ©´¨àã¹ ÝfV¨N}†®:þß誼¯ãîé…zêâP×)ÿ²ò@=Õ¨ïã-^Ú6rõòÞâÌÁÓaÁÀÓa-ÆåíB:|µvËè©O"Mü£B³¹~ßž.2i†“õÛƧhÔ-o*«,ðU^÷Ó=ï ¦LÑÍŠ'›Y|]ÁÝSꄾ>üfj±M¦O9˜Ÿš/»è—Ò[û…d)eÔj1¿yۜŸß6/Üt³ÖÓw}®7nÛ$Yú5ƒ¤ßƒ —®7ROÒÏ“*‹ºó¦Çƒ ÐÅ{úúáöH‡‡ äîQ¯‹¹Ì¿xν0ÒU‹¤;‡Dè·eBµW UW'MÅ®8N~Ÿ}ªo¾g Æé·|ë5·Ñ»< Kîãñt0l±O#ôC„t>†ò|@ùEÊ459‘zpErZž—øxømD;jkÍâ[äŸêèÝù$c¿×;´#ªKßï”ÊpÎGfúþ …/}H,SÔÒð1]IQèä+©¦%:ŒTŒŽ/QÚû«*°y¬—,ÕúÌN¬¡~S:lJùíÞÿUÙUeßåoõËŠNÏF¸âÿÝúʘêæ_& æ"›JØU*»ë6ÓÖÒͤŸ:~±ú7 Ý…ðendstream endobj 72 0 obj 3563 endobj 75 0 obj <> stream xœµZY$GÖ²k@½ƒ¯ðÚÐö» ˜r‘BâŒo¶Fâó4`#4kÉûÀïç‹È¬Ê¨îêíY¼`!gFgFÆñÅUão÷f²noøŸyqûl÷íÎÇö1ä°¶£0¯ïê:Ãk9ÓÖݳ3“ñ–Œ‹àåS¤°À=güþù×;²&N&ï£ÉøÝƒ±/X%æ)ÑÞg*Sr|"N%bïíäË>Ú&c÷·;Ÿ›Èï£ó~òrƒ&O—i ûä§d÷ÑÛ8‘“37póŽyØÉ$¾“&‡;©¸)àUçòTÔ²7ïQcbÐyŸof¹Ñ8ÔÔÚߨ{¾ :€Êê­b°ì—'fÊ,Dc0˸ÖBÊhÕÏš«)S0gPÙ¼ÞwÍ…ÁÅUdæÀ…Þªwë^4óÒ$,'Ðq£²p˜÷ý…Ò¤˜9ÌR®õ¨ºE' ë&ªëkÖ(w•âÝB‘=ç"Þs€ðÞP5©•ô\•YÃEù®$Pk°çjãÉJ7Ã{×÷Â"HgÒO.Ðóþ?õ„‰úUh«}:àÙ(Õ÷wkŠõNðJUìm7Ïmu}É+ó€£¾c¥+í<ûžüÌC(@iH3¡#=$ïSÝVÜ»åç\qºJ(Ú:¸glµ'Ѳ¿mnµê;¾ÉWûÈYèv§(mt§)È rÇÖVMK,â ↌԰ä9i %ºŠÑî½õK4—=Þú¤¡¸‚o ×V˜ª&Ï4%Iÿí9åQ ÛЗ–mÃ/­®5«½sëÔTŸOÌàëûoTŠtÇwš‡¯¶Y¤˜ã·‰égë.zÌf=ir«½xðöÈ6œ¸?ß™ýgøÿ×ôÐðÿdòÓëÛgû?Þì>ù"í¥]¸ù ã]Á¼¦ü³Ý['c‚ã‘ånží†ãÍ¿wŸÞ0{žA;Å“ ŒÑXÈûÅg§{~q,¦•@(FU WM‰Ñ‘Xœ¿ ïŽ0[küðÞÈ›= ?ëD7&˱”ÿ~ó°F¾;Å:Èè´°ö¬é …)FKòÚx¨FÝã5"»Xã†÷e™1¬ò o’wiø`²mÈ~¾ŠµÃ£ñÚ£Ò'ë†7Xо WG´JßL$7ü`d…ª#îígèRº¨6‹—÷1Jl‹&׿€<|ù äô1Ù4|oY]À¼!…Òðpä64Ø8üx¼(0z¾>^#fnué㑸ã#ªŽ(UD®OÈ1fó¼ü`¼J0²F,ùà5 Kô(ùט0驯 ¹PÞûâ-YØÏcvM 7'ÞÀœW=yNÅo²Ï=z)Æoº\,̱2’SPÌÞ¯1+» \BLNX&ªß²\¿TÂl²ú>³J£ç $ì¿?X°'ŠÕÅ–²oTôø rS&aÔÕOlšFŸíÔ/‡‘ûÇhøó ƒË4ü²Ñâð _BXeHûC‘1‡¬ïþÐü›¹à2u _j&@·Ë *È£§Œõ6‹Ð ‡m¥ fx&0ÖϘRìµ±Û·FÌ ˆË¬Ï^œ“!‚‘"ž°éEµPBïaÞR‚_irÕ1¤ÄÓlߟá‡'›Æè6äd•'}y|‰hmì_òØ]ýìåƒã®O9n ¶Ra>ù#> ¥¼ýªº¤Lø.0гɓbÕͧp P4­Ÿ{“ÓÖTÜÚÅ«èžÕ ÜJš±Psë̺†W›fÙäºÊ) Lº RùB »-—rÈ6¶1œpw Ô8EÓ'5HÐ’aWK„šñ[–™(Ž޼r6¿Q©ç=Hj’óa]/®m,|À“¨ÃQøòP:!x¼•ÕI—›H®ÞËfj&MÜ| 6w¦€UBïñkÜF§³qûseˆU4VË2(cµî†Î§R袈 ß&s ôâĹõ£ÄÉ?o%ÎSácsyQRc3ŸË„çÊ­rÞæý3•ý  Ô'¯—×ï<â¶Ú‘N½|¸©Ë•:­M(aèÓ$-­åœ‚Gè¦xÂÔ¯LÓÍ ÕéðѦÎ:u)) õ‰îã+œOìˆÊ£¬-Q«™SõTäõR£×ÁZí¯‚µfbŸÜ†:‚ïoéå&xU³«Î>óÜ)Àoc«¶b´Êï÷˜UâÂ4‚æ|VÞèÂ6û%›¿Ÿ¡~Kx• Ù‰–ôEäªú µ·ž¿.µx]5çãð$>¸€¯À­äÑÝ{¾U2åüª²/ëý¿ˆª^ºy¢ BÕÛžRœÍ(mW:\WÐh°} S5Ú©adŽ;Z1³ Ëïeˆ[ádSÚV÷ÈKíä™Ñ¥¼ß”PóÌÉß‹oCf'Ÿ¶<ê6ÖmW³Íß/;õàKQ£>íªü𛑂5ƒ‡«æ±]z¹ú±øA°bËdóÒ¦nzd5yô‡p“2&ÀMßI 92ŸI-7ý¸)òñ|¾útvÎ`¿à ˜Nvã«BE§®TÛòõ‡“ݦ.gû¹X?®y×6M¶øu¥ÛÎèõ·à×iâwËwÊïÒ"¯kÄ=ZäC]<ÙOëü»]Ó¶ ºý%êáašä?çWöú ’cå|Ú]`¯#QéyªG~é4xoÅâv}V·./uÖyªáœÐðpÛ˜¼âqYæÿ†ÏظrЗÏa¼„²LH˜>rŒ&WRÐ38U«_ëzjÅZYNå>uùÿÞc­ ó6þ··^V޳ú BùKÓç»ÿ9ãß#endstream endobj 76 0 obj 3074 endobj 4 0 obj <> /Contents 5 0 R >> endobj 14 0 obj <> /Contents 15 0 R >> endobj 18 0 obj <> /Contents 19 0 R >> endobj 23 0 obj <> /Contents 24 0 R >> endobj 29 0 obj <> /Contents 30 0 R >> endobj 34 0 obj <> /Contents 35 0 R >> endobj 38 0 obj <> /Contents 39 0 R >> endobj 42 0 obj <> /Contents 43 0 R >> endobj 46 0 obj <> /Contents 47 0 R >> endobj 50 0 obj <> /Contents 51 0 R >> endobj 54 0 obj <> /Contents 55 0 R >> endobj 58 0 obj <> /Contents 59 0 R >> endobj 62 0 obj <> /Contents 63 0 R >> endobj 66 0 obj <> /Contents 67 0 R >> endobj 70 0 obj <> /Contents 71 0 R >> endobj 74 0 obj <> /Contents 75 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 14 0 R 18 0 R 23 0 R 29 0 R 34 0 R 38 0 R 42 0 R 46 0 R 50 0 R 54 0 R 58 0 R 62 0 R 66 0 R 70 0 R 74 0 R ] /Count 16 /Rotate 0>> endobj 1 0 obj <> endobj 13 0 obj <> endobj 17 0 obj <> endobj 22 0 obj <> endobj 28 0 obj <> endobj 33 0 obj <> endobj 37 0 obj <> endobj 41 0 obj <> endobj 45 0 obj <> endobj 49 0 obj <> endobj 53 0 obj <> endobj 57 0 obj <> endobj 61 0 obj <> endobj 65 0 obj <> endobj 69 0 obj <> endobj 73 0 obj <> endobj 77 0 obj <> endobj 11 0 obj <> endobj 81 0 obj <> endobj 32 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <> endobj 82 0 obj <> endobj 7 0 obj <> endobj 83 0 obj <> endobj 21 0 obj <> endobj 9 0 obj <> endobj 84 0 obj <> endobj 12 0 obj <> endobj 78 0 obj <>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.8.2/lcptools/crtpol2.c0000644000175000017500000003127112365404264014457 0ustar rqwrqw/* * crtpol2.c: Intel(R) TXT policy (LCP_POLICY) creation tool * * Copyright (c) 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. * */ #include #include #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/lcp2.h" #include "polelt_plugin.h" #include "pol.h" #include "poldata.h" #include "pollist.h" #include "lcputils2.h" static const char help[] = "Usage: lcp_crtpol2 [OPTION]\n" "Create an Intel(R) TXT policy (and policy data file)\n\n" "--create\n" " [--ver ] version\n" " --type type\n" " [--minver ] SINITMinVersion\n" " [--rev [,ctrN] revocation values (comma separated,\n" " no spaces\n" " [--ctrl policy file\n" " [--data policy data file\n" " [FILE]... policy list files\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\n"; bool verbose = false; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"show", no_argument, NULL, 'S'}, /* options */ {"ver", required_argument, NULL, 'v'}, {"type", required_argument, NULL, 't'}, {"minver", required_argument, NULL, 'm'}, {"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'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; uint16_t version = LCP_DEFAULT_POLICY_VERSION; char policy_file[MAX_PATH] = ""; char poldata_file[MAX_PATH] = ""; 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; bool brief = false; unsigned int nr_files = 0; char files[LCP_MAX_LISTS][MAX_PATH]; static int create(void) { lcp_policy_data_t *poldata = NULL; lcp_policy_t *pol = malloc(sizeof(*pol)); if ( pol == NULL ) { ERROR("Error: failed to allocate policy\n"); return 1; } memset(pol, 0, sizeof(*pol)); pol->version = version; pol->hash_alg = LCP_POLHALG_SHA1; 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; if ( strcmp(type, "any") == 0 ) pol->policy_type = LCP_POLTYPE_ANY; else if ( strcmp(type, "list") == 0 ) { pol->policy_type = LCP_POLTYPE_LIST; poldata = malloc(sizeof(*poldata)); if ( poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pol); return 1; } memset(poldata, 0, sizeof(*poldata)); 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; lcp_policy_list_t *pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(pol); free(poldata); return 1; } poldata = add_policy_list(poldata, pollist); if ( poldata == NULL ) { free(pol); free(pollist); return 1; } free(pollist); } calc_policy_data_hash(poldata, &pol->policy_hash, pol->hash_alg); } 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; } static int show(void) { size_t len, pol_len = 0, poldata_len = 0; void *data; const char *pol_file = "", *poldata_file = ""; lcp_policy_t *pol = NULL; lcp_policy_data_t *poldata = NULL; int err = 1; data = read_file(files[0], &len, false); if ( data == NULL ) return 1; /* we allow files in any order or either one only, so assume that if first file doesn't verify as a policy then it must be policy data */ if ( !verify_policy(data, len, true) ) { poldata = (lcp_policy_data_t *)data; poldata_len = len; poldata_file = files[0]; } else { pol = data; pol_len = len; pol_file = files[0]; } if ( nr_files == 2 ) { data = read_file(files[1], &len, false); if ( data == NULL ) goto done; if ( pol == 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); err = 0; } } if ( poldata != NULL ) { DISPLAY("\npolicy data file: %s\n", poldata_file); if ( verify_policy_data(poldata, poldata_len) ) { display_policy_data(" ", poldata, brief); /* no use verifying hash if policy didn't validate or doesn't exist or isn't list type */ if ( err == 0 && pol->policy_type == LCP_POLTYPE_LIST ) { lcp_hash_t hash; calc_policy_data_hash(poldata, &hash, pol->hash_alg); if ( memcmp(&hash, &pol->policy_hash, get_lcp_hash_size(pol->hash_alg)) == 0 ) DISPLAY("\npolicy data hash matches policy hash\n"); else { ERROR("\nError: policy data hash does not match policy hash\n"); err = 1; } } else err = 1; } else err = 1; } done: free(pol); 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); switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* show */ 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 'v': /* version */ version = strtoul(optarg, NULL, 0); LOG("cmdline opt: ver: 0x%x (%u)\n", version, version); 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); 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 '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 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 ( *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; } return create(); } 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(); } 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.8.2/lcptools/getcap.c0000644000175000017500000003351612365404265014342 0ustar rqwrqw/* * 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 #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 = strlen(password); 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.8.2/lcptools/pconf_elt.c0000644000175000017500000002014312365404265015040 0ustar rqwrqw/* * pconf_elt.c: platform config policy element (LCP_PCONF_ELEMENT) plugin * * Copyright (c) 2009 - 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 #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #define NR_PCRS 24 #define MAX_PCR_INFOS 32 /* * TPM_PCR_INFO_SHORT * (from tboot/tpm.{h,c} */ typedef struct __packed { uint16_t size_of_select; uint8_t pcr_select[3]; } tpm_pcr_selection_t; typedef uint8_t tpm_locality_selection_t; #define TPM_DIGEST_SIZE 20 typedef struct __packed { uint8_t digest[TPM_DIGEST_SIZE]; } tpm_digest_t; typedef tpm_digest_t tpm_composite_hash_t; typedef tpm_digest_t tpm_pcr_value_t; typedef struct __packed { tpm_pcr_selection_t select; uint32_t value_size; tpm_pcr_value_t pcr_value[]; } tpm_pcr_composite_t; 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; /* need to define TPM_PCR_INFO_SHORT before including lcp2.h */ #define TPM_PCR_INFO_SHORT tpm_pcr_info_short_t #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" static unsigned int nr_pcr_infos; static tpm_pcr_info_short_t pcr_infos[MAX_PCR_INFOS]; static unsigned int nr_pcrs; static unsigned int pcrs[NR_PCRS]; static tb_hash_t digests[NR_PCRS]; static bool parse_pconf_line(const char *line) { if ( nr_pcrs == NR_PCRS ) return false; /* skip any leading whitespace and non-digits */ while ( *line != '\0' && (isspace(*line) || !isdigit(*line)) ) line++; /* get PCR # */ pcrs[nr_pcrs] = (unsigned int)strtoul(line, (char **)&line, 10); if ( pcrs[nr_pcrs] >= NR_PCRS ) { ERROR("Error: invalid PCR value\n"); return false; } LOG("parsed PCR: %u\n", pcrs[nr_pcrs]); /* skip until next digit */ while ( *line != '\0' && !isxdigit(*line) ) line++; if ( !parse_line_hashes(line, &digests[nr_pcrs]) ) return false; nr_pcrs++; return true; } static bool make_pcr_info(unsigned int nr_pcrs, unsigned int pcrs[], tb_hash_t digests[], tpm_pcr_info_short_t *pcr_info) { unsigned int i; /* don't use TSS Trspi_xxx fns to create this so that there is no runtime dependency on a TSS */ /* fill in pcrSelection */ /* TPM structures are big-endian, so byte-swap */ pcr_info->pcr_selection.size_of_select = bswap_16(3); memset(&pcr_info->pcr_selection.pcr_select, 0, sizeof(pcr_info->pcr_selection.pcr_select)); for ( i = 0; i < nr_pcrs; i++ ) pcr_info->pcr_selection.pcr_select[pcrs[i]/8] |= 1 << (pcrs[i] % 8); /* set locality to default (0x1f) */ pcr_info->locality_at_release = 0x1f; /* * digest is hash of TPM_PCR_COMPOSITE */ size_t pcr_comp_size = offsetof(tpm_pcr_composite_t, pcr_value) + nr_pcrs * sizeof(tpm_pcr_value_t); tpm_pcr_composite_t *pcr_comp = (tpm_pcr_composite_t *)malloc(pcr_comp_size); if ( pcr_comp == NULL ) return false; memcpy(&pcr_comp->select, &pcr_info->pcr_selection, sizeof(pcr_comp->select)); pcr_comp->value_size = bswap_32(nr_pcrs * sizeof(tpm_pcr_value_t)); /* concat specified digests */ for ( i = 0; i < nr_pcrs; i++ ) { memcpy(&pcr_comp->pcr_value[i], &digests[i], sizeof(pcr_comp->pcr_value[0])); } /* then hash it */ tb_hash_t hash; if ( !hash_buffer((uint8_t *)pcr_comp, pcr_comp_size, &hash, TB_HALG_SHA1_LG) ) { free(pcr_comp); return false; } /* then copy it */ memcpy(&pcr_info->digest_at_release, &hash, sizeof(pcr_info->digest_at_release)); free(pcr_comp); return true; } static bool cmdline_handler(int c, const char *opt) { if ( c != 0 ) { ERROR("Error: unknown option for pconf type\n"); return false; } nr_pcrs = 0; memset(&pcrs, 0, sizeof(pcrs)); memset(&digests, 0, sizeof(digests)); /* pconf files */ LOG("cmdline opt: pconf file: %s\n", opt); if ( !parse_file(opt, parse_pconf_line) ) return false; if ( !make_pcr_info(nr_pcrs, pcrs, digests, &pcr_infos[nr_pcr_infos++]) ) return false; return true; } static lcp_policy_element_t *create(void) { size_t data_size = sizeof(uint16_t) + nr_pcr_infos * sizeof(pcr_infos[0]); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_pconf_element_t *pconf = (lcp_pconf_element_t *)&elt->data; pconf->num_pcr_infos = nr_pcr_infos; memcpy(&pconf->pcr_infos, &pcr_infos, nr_pcr_infos * sizeof(pcr_infos[0])); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_pconf_element_t *pconf = (lcp_pconf_element_t *)elt->data; DISPLAY("%s num_pcr_infos: %u\n", prefix, pconf->num_pcr_infos); for ( unsigned int i = 0; i < pconf->num_pcr_infos; i++ ) { tpm_pcr_info_short_t *pcr_info = (tpm_pcr_info_short_t *)&pconf->pcr_infos[i]; DISPLAY("%s pcr_infos[%u]:\n", prefix, i); DISPLAY("%s pcrSelect: 0x%02x%02x%02x\n", prefix, pcr_info->pcr_selection.pcr_select[0], pcr_info->pcr_selection.pcr_select[1], pcr_info->pcr_selection.pcr_select[2]); DISPLAY("%s localityAtRelease: 0x%x\n", prefix, pcr_info->locality_at_release); DISPLAY("%s digestAtRelease: ", prefix); print_hex("", &pcr_info->digest_at_release, get_hash_size(TB_HALG_SHA1_LG)); } } static polelt_plugin_t plugin = { "pconf", NULL, " pconf\n" " [FILE2] ... one or more files containing PCR\n" " numbers and the desired digest\n" " of each; each file will be a PCONF\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.8.2/lcptools/mle_elt.c0000644000175000017500000001161012365404265014507 0ustar rqwrqw/* * mle_elt.c: MLE policy element (LCP_MLE_ELEMENT) plugin * * Copyright (c) 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" #define MAX_HASHES 32 static uint8_t sinit_min_version; static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static bool parse_mle_line(const char *line) { if ( nr_hashes == MAX_HASHES ) return false; return parse_line_hashes(line, &hashes[nr_hashes++]); } 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) { size_t data_size = sizeof(lcp_mle_element_t) + nr_hashes * get_hash_size(TB_HALG_SHA1_LG); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_mle_element_t *mle = (lcp_mle_element_t *)&elt->data; mle->sinit_min_version = sinit_min_version; mle->hash_alg = TB_HALG_SHA1_LG; mle->num_hashes = nr_hashes; lcp_hash_t *hash = mle->hashes; for ( unsigned int i = 0; i < nr_hashes; i++ ) { memcpy(hash, &hashes[i], get_hash_size(TB_HALG_SHA1_LG)); hash = (void *)hash + get_hash_size(TB_HALG_SHA1_LG); } 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; 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'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "mle", opts, " mle\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.8.2/lcptools/crtpolelt.c0000644000175000017500000002110712365404265015100 0ustar rqwrqw/* * crtpolelt.c: Intel(R) TXT policy element (LCP_POLICY_ELEMENT) creation tool * * Copyright (c) 2009 - 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 _GNU_SOURCE #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "polelt.h" #include "lcputils2.h" #define MAX_HELP_TEXT 4096 static char help[MAX_HELP_TEXT] = "Usage: lcp_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" "types :\n"; bool verbose = false; #define MAX_CMDLINE_OPTS 256 static struct option long_opts[MAX_CMDLINE_OPTS] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"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 */ strncat(help, plugin->help_txt, MAX_HELP_TEXT - strlen(help) - 1); } } 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 */ 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 ouput 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; } 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.8.2/lcptools/mlehash.c0000644000175000017500000003065712365404265014523 0ustar rqwrqw/* * mhash.c: tool to determine the SHA-1 hash of a Intel(R) TXT MLE * * 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 #include #include #define PRINT printf #include "../include/elf_defns.h" #include "../include/uuid.h" #include "../include/mle.h" #define SHA1_LENGTH 20 static bool verbose = false; #define log_info(fmt, ...) verbose ? printf(fmt, ##__VA_ARGS__) : 0 /* * is_elf_image * * check an image is elf or not? * */ static bool is_elf_image(const void *image, const size_t size) { elf_header_t *elf; log_info("checking whether image is an elf image ... "); if ( image == NULL ) { log_info(": failed! - Pointer is zero.\n"); return false; } /* check size */ if ( sizeof(elf_header_t) > size ) { log_info(": 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_info(": failed! - ELF magic number is not matched.\n"); return false; } /* check data encoding in ELF */ if ( elf->e_ident[EI_DATA] != ELFDATA2LSB ) { log_info(": 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_info(": failed! - ELF image is not executable.\n"); return false; } /* check ELF image is for IA? */ if ( elf->e_machine != EM_386 ) { log_info(": failed! - ELF image is not for IA.\n"); return false; } /* check ELF version is valid? */ if ( elf->e_version != EV_CURRENT ) { log_info(": failed! - ELF version is invalid.\n"); return false; } if ( sizeof(elf_program_header_t) > elf->e_phentsize ) { log_info(": failed! - Program size is smaller than program " "header size.\n"); return false; } log_info(": succeeded!\n"); return true; } static bool get_elf_image_range(const elf_header_t *elf, void **start, void **end) { int i; unsigned long u_start, u_end; if (elf == NULL) { log_info("Error: ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ if ((start == NULL) || (end == NULL)) { log_info("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; 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_info("expanding elf image ... "); if ( elf == NULL ) { log_info(": 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_info("expanded image exceeded allocated size\n"); return false; } memcpy(base, (void *)elf + ph->p_offset, ph->p_filesz); memset(base + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz); base += ph->p_memsz; size -= ph->p_memsz; } } log_info(": succeeded!.\n"); return true; } /* * print_dump * * dump the memory * */ #if 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_file * * read file from disk, if compressed, uncompress it * */ static bool read_file(const char *filename, void **buffer, size_t *length) { 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_info("checking whether the file exists or not ... "); if ( stat(filename, &filestat) ) goto error; log_info(": existed!\n"); /* try uncompress the file (gzopen will handle uncompressed files too) */ log_info("trying to uncompress the file ... "); fcompressed = gzopen(filename, "rb"); if ( !fcompressed ) { log_info(": failed!\n"); return false; } log_info(": succeeded!\n"); log_info("creating a temporary file to uncompress ... "); fdecompressed = tmpfile(); if ( !fdecompressed ) goto error; log_info(": succeeded!\n"); log_info("opening the decompressed file ... "); while ( !gzeof(fcompressed) ) { i = gzread(fcompressed, tmpbuffer, 1024); *length += i; if ( fwrite(tmpbuffer, 1, i, fdecompressed) != i ) goto error; } log_info(": succeeded!\n"); gzclose(fcompressed); fcompressed = NULL; log_info("testing decompression is ... "); if ( *length > 0 ) { log_info(": succeeded!\n"); /* uncompression succeeded */ fseek(fdecompressed, 0, SEEK_SET); } else { log_info(": failed!\n"); goto error; } /* read file into buffer */ log_info("reading the decompressed file ... "); *buffer = malloc(*length); if ( *buffer == NULL ) goto error; memset(*buffer, 0, *length); if ( fread(*buffer, 1, *length, fdecompressed) != *length ) goto error; fclose(fdecompressed); log_info(": succeeded!\n"); return true; error: log_info(": failed!\n"); if ( fcompressed ) gzclose(fcompressed); if ( fdecompressed ) fclose(fdecompressed); free(*buffer); return false; } static mle_hdr_t *find_mle_hdr(void *start, size_t size) { void *end; end = start + size - sizeof(uuid_t); while ( start <= end ) { if ( are_uuids_equal((const uuid_t *)start, &((uuid_t)MLE_HDR_UUID)) ) 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; uint8_t hash[SHA1_LENGTH]; mle_hdr_t *mle_hdr; int i, c; bool help = false; char *mle_file; extern int optind; /* current index of get_opt() */ EVP_MD_CTX ctx; const EVP_MD *md; char *cmdline = NULL; while ((c = getopt(argc, (char ** const)argv, "hvc:")) != -1) { switch (c) { case 'h': help = true; break; case 'v': verbose = true; break; case 'c': if ( optarg == NULL ) { printf("Misssing command line string for -c option\n"); return 1; } cmdline = malloc(strlen(optarg) + 1); if ( cmdline == NULL ) { printf("Out of memory\n"); return 1; } strcpy(cmdline, optarg); break; default: printf("Unknonw command line option\n"); break; } } if ( help || (optind == argc) ) { printf("mhash [-h] [-v] [-c cmdline] mle_file\n" "\t-h Help: will print out this help message.\n" "\t-v Verbose: display progress indications.\n" "\t-c cmdline Command line: specify quote-delimited command line.\n" "\tmle_file: file name of MLE binary (gzip or not) to hash.\n"); free(cmdline); return 1; } mle_file = argv[optind]; /* read file */ if ( !read_file(mle_file, &base, &size) ) goto error; /* expand image */ if ( !is_elf_image(base, size) ) goto error; 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 error; exp_size = elf_end - elf_start; exp_start = malloc(exp_size); if ( exp_start == NULL ) { log_info("not enough memory for expanded image\n"); goto error; } /* expand the image */ if ( !expand_elf_image(base_as_elf, exp_start, exp_size) ) goto error; /* find the MLE header in the expanded image */ mle_hdr = find_mle_hdr(exp_start, exp_size); if ( mle_hdr == NULL ) { log_info("no MLE header found in image\n"); goto error; } /* 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(exp_start + mle_hdr->cmdline_start_off, '\0', mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off); strncpy(exp_start + mle_hdr->cmdline_start_off, cmdline, mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off - 1); } /* SHA-1 the MLE portion of the image */ md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, exp_start + mle_hdr->mle_start_off, mle_hdr->mle_end_off - mle_hdr->mle_start_off); EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL); log_info("SHA-1 = "); /* we always print the hash regardless of verbose mode */ for ( i = 0; i < SHA1_LENGTH; i++ ) { printf("%02x", hash[i]); if ( i < SHA1_LENGTH - 1 ) printf(" "); } printf("\n"); free(base); free(exp_start); return 0; error: free(base); free(exp_start); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/lcptools2.txt0000644000175000017500000000505212365404265015407 0ustar rqwrqwThese 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/ directory: Create policy element(s): ======================== Create an MLE element: --------------------- 1. lcp_mlehash -c "the command line for tboot from grub.conf" /boot/tboot.gz > mle_hash 2. lcp_crtpolelt --create --type mle --ctrl 0x00 --minver 17 --out mle.elt mle_hash Create a PCONF element: ---------------------- 1. cat /sys/devices/platform/tpm_tis/pcrs |grep -e PCR-00 -e PCR-01 > pcrs 2. lcp_crtpolelt --create --type pconf --out pconf.elt pcrs Create an SBIOS element: ----------------------- 1. Create hash file containing BIOS hash(es), e.g. named sbios_hash 2. lcp_crtpolelt --create --type sbios --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. lcp_crtpolelt --create --type custom --out custom.elt --uuid Create policy list(s): ===================== Combine the elements into an unsigned list: ------------------------------------------ 1. lcp_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 lcp_crtpollist to sign the list: ----------------------------------- 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. lcp_crtpollist --sign --pub pubkey.pem --priv privkey.pem --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. lcp_crtpollist --sign --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. lcp_crtpollist --addsig --sig list.sig --out list_sig.lst Create policy and policy data files: =================================== 1. lcp_crtpol2 --create --type list --pol list.pol --data list.data list_{unsig,sig}.lst tboot-1.8.2/lcptools/custom_elt.c0000644000175000017500000001575612365404265015263 0ustar rqwrqw/* * custom_elt.c: custom (user/ISV/etc. -defined) policy element * (LCP_MLE_ELEMENT) plugin * * Copyright (c) 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. * */ #include #include #include #include #include #include #define _GNU_SOURCE #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.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) { 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(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_custom_element_t *custom = (lcp_custom_element_t *)&elt->data; custom->uuid = uuid; memcpy(custom->data, data, data_len); free(data); data = NULL; return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_custom_element_t *custom = (lcp_custom_element_t *)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_CUSTOM, &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.8.2/lcptools/poldata.h0000644000175000017500000000454212365404265014525 0ustar rqwrqw/* * poldata.h: * * Copyright (c) 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 __POLDATA_H__ #define __POLDATA_H__ extern size_t get_policy_data_size(const lcp_policy_data_t *poldata); extern bool verify_policy_data(const lcp_policy_data_t *poldata, size_t size); extern void display_policy_data(const char *prefix, const lcp_policy_data_t *poldata, bool brief); extern lcp_policy_data_t *add_policy_list(lcp_policy_data_t *poldata, const lcp_policy_list_t *pollist); extern void calc_policy_data_hash(const lcp_policy_data_t *poldata, lcp_hash_t *hash, uint8_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.8.2/lcptools/hash.c0000644000175000017500000001052112365404265014011 0ustar rqwrqw/* * hash.c: support functions for tb_hash_t type * * 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. * */ #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) { if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) return false; if ( hash_alg == TB_HALG_SHA1_LG ) return (memcmp(hash1, hash2, SHA1_LENGTH) == 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_LG ) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha1, NULL); 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_LG ) { EVP_MD_CTX ctx; const EVP_MD *md; memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); memcpy(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); 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_LG ) { for ( unsigned int i = 0; i < sizeof(hash->sha1); i++ ) fprintf(stderr, "%02x ", hash->sha1[i]); fprintf(stderr, "\n"); } else if ( hash_alg == TB_HALG_SHA256 ) { for ( unsigned int i = 0; i < sizeof(hash->sha256); i++ ) fprintf(stderr, "%02x ", hash->sha256[i]); fprintf(stderr, "\n"); } else return; } 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_LG ) memcpy(dest_hash, src_hash, SHA1_LENGTH); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/sbios_elt.c0000644000175000017500000001301112365404265015046 0ustar rqwrqw/* * sbios_elt.c: SBIOS policy element (LCP_SBIOS_ELEMENT) plugin * * Copyright (c) 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 #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" #define MAX_HASHES 33 /* +1 for fallback_hash */ static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static uint16_t *get_num_hashes(lcp_sbios_element_t *sbios) { /* because fallback_hash is variable size, need to calculate this */ return (void *)&sbios->fallback_hash + get_hash_size(TB_HALG_SHA1_LG) + sizeof(sbios->reserved2); } static lcp_hash_t *get_hashes(lcp_sbios_element_t *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++]); } static bool cmdline_handler(int c, const char *opt) { 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) { /* 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_t) - sizeof(lcp_hash_t) + nr_hashes * get_hash_size(TB_HALG_SHA1_LG); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_sbios_element_t *sbios = (lcp_sbios_element_t *)&elt->data; sbios->hash_alg = TB_HALG_SHA1_LG; memcpy(&sbios->fallback_hash, &hashes[0], get_hash_size(TB_HALG_SHA1_LG)); *get_num_hashes(sbios) = nr_hashes - 1; lcp_hash_t *hash = get_hashes(sbios); for ( unsigned int i = 1; i < nr_hashes; i++ ) { memcpy(hash, &hashes[i], get_hash_size(TB_HALG_SHA1_LG)); hash = (void *)hash + get_hash_size(TB_HALG_SHA1_LG); } return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_sbios_element_t *sbios = (lcp_sbios_element_t *)elt->data; unsigned int hash_size = get_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 polelt_plugin_t plugin = { "sbios", NULL, " sbios\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_SBIOS, &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.8.2/lcptools/lcptools.c0000644000175000017500000010267412365404265014740 0ustar rqwrqw/* * 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 #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 enought 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(data, 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(resp_data, resp, *outlen); ret = LCP_SUCCESS; exit: close_tss_context(hcontext); return ret; } tboot-1.8.2/lcptools/poldata.c0000644000175000017500000001420312365404265014513 0ustar rqwrqw/* * poldata.c: * * Copyright (c) 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. * */ #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/lcp_hlp.h" #include "polelt_plugin.h" #include "poldata.h" #include "pollist.h" #include "lcputils2.h" size_t get_policy_data_size(const lcp_policy_data_t *poldata) { size_t size = offsetof(lcp_policy_data_t, policy_lists); const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { size += get_policy_list_size(pollist); pollist = (void *)pollist + get_policy_list_size(pollist); } return size; } bool verify_policy_data(const lcp_policy_data_t *poldata, size_t size) { if ( offsetof(lcp_policy_data_t, 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 */ size -= offsetof(lcp_policy_data_t, policy_lists); const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { LOG("verifying list %u:\n", i); if ( !verify_policy_list(pollist, size, NULL, false) ) return false; size -= get_policy_list_size(pollist); pollist = (void *)pollist + get_policy_list_size(pollist); } return true; } void display_policy_data(const char *prefix, const lcp_policy_data_t *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[strlen(prefix)+8]; sprintf(new_prefix, "%s ", prefix); const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { DISPLAY("%s list %u:\n", prefix, i); display_policy_list(new_prefix, pollist, brief); pollist = (void *)pollist + get_policy_list_size(pollist); } } lcp_policy_data_t *add_policy_list(lcp_policy_data_t *poldata, const lcp_policy_list_t *pollist) { 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_policy_list_size(pollist); lcp_policy_data_t *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((void *)new_poldata + old_size, pollist, list_size); new_poldata->num_lists++; return new_poldata; } void calc_policy_data_hash(const lcp_policy_data_t *poldata, lcp_hash_t *hash, uint8_t hash_alg) { size_t hash_size = get_lcp_hash_size(hash_alg); uint8_t hash_list[hash_size * LCP_MAX_LISTS]; memset(hash_list, 0, sizeof(hash_list)); /* accumulate each list's msmt to list */ lcp_hash_t *curr_hash = (lcp_hash_t *)hash_list; const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { calc_policy_list_hash(pollist, curr_hash, hash_alg); pollist = (void *)pollist + get_policy_list_size(pollist); curr_hash = (void *)curr_hash + hash_size; } /* hash list */ hash_buffer(hash_list, hash_size * poldata->num_lists, (tb_hash_t *)hash, hash_alg); return; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/Linux_LCP_Tools_User_Manual.doc0000644000175000017500000061600012365404264020664 0ustar rqwrqwÐÏࡱá>þÿ ‰‹þÿÿÿ…†‡ˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿì¥Á#` ø¿Ã8bjbjm¥m¥ õÏϰ0ÿÿÿÿÿÿ¤è1è1è1è1è1è1è1ü1ŒiŒiŒi8Äiì°jlü1GÛü(kØmmmm onxq´,r\ÆÚÈÚÈÚÈÚÈÚÈÚÈÚ$CÞh«àìÚè1$uènèn"$u$uìÚè1è1mmèÛôxôxôx$ulè1mè1mÆÚôx$uÆÚôxôx*ïÌ;è1è1â×mk °9–»12ÈŒivè*ÓR‚ÚDÛ0GÛ|Óf;âxw$;â¤â×;âè1â× ˆr®6s|ôx²sdtˆrˆrˆrìÚìÚœxXˆrˆrˆrGÛ$u$u$u$uü1$ 2$D2DˆPü1 2D2ˆPü1ü1ü1è1è1è1è1è1è1ÿÿÿÿ  Intel® Trusted Execution Technology – Launch Control Policy Linux Tools User Manual Updated 11/28/07 Information in this document is provided in connection with Intel® products. No license, express or implied, by estoppels or otherwise, to any intellectual property rights is granted by this document. Except as provided in Intel’s Terms and Conditions of Sale for such products, Intel assumes no liability whatsoever, and Intel disclaims any express or implied warranty, relating to sale and/or use of Intel products including liability or warranties relating to fitness for a particular purpose, merchantability, or infringement of any patent, copyright or other intellectual property right. Intel products are not intended for use in medical, life saving, or life sustaining applications. Intel may make changes to specifications and product descriptions at any time, without notice. The API and software may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request. This document and the software described in it are furnished under license and may only be used or copied in accordance with the terms of the license. The information in this document is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Intel Corporation. Intel Corporation assumes no responsibility or liability for any errors or inaccuracies that may appear in this document or any software that may be provided in association with this document. Except as permitted by such license, no part of this document may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. Contact your local Intel sales office or your distributor to obtain the latest specifications and before placing your product order. Copies of documents which have an ordering number and are referenced in this document or other Intel literature may be obtained by calling 1-800-548-4725 or by visiting Intel’s website at  HYPERLINK "http://www.intel.com" http://www.intel.com. Contents  TOC \o "1-3" \h \z \u  HYPERLINK \l "_Toc176025230" 1 Introduction  PAGEREF _Toc176025230 \h 4  HYPERLINK \l "_Toc176025231" 2 Commands  PAGEREF _Toc176025231 \h 5  HYPERLINK \l "_Toc176025232" 2.1 Pre-requisites  PAGEREF _Toc176025232 \h 5  HYPERLINK \l "_Toc176025233" 2.2 tpmnv_defindex  PAGEREF _Toc176025233 \h 6  HYPERLINK \l "_Toc176025234" 2.3 tpmnv_relindex  PAGEREF _Toc176025234 \h 8  HYPERLINK \l "_Toc176025235" 2.4 tpmnv_lock  PAGEREF _Toc176025235 \h 9  HYPERLINK \l "_Toc176025236" 2.5 tpmnv_getcap  PAGEREF _Toc176025236 \h 10  HYPERLINK \l "_Toc176025237" 2.6 lcp_crtpconf  PAGEREF _Toc176025237 \h 11  HYPERLINK \l "_Toc176025238" 2.7 lcp_crtpol  PAGEREF _Toc176025238 \h 12  HYPERLINK \l "_Toc176025239" 2.8 lcp_writepol  PAGEREF _Toc176025239 \h 14  HYPERLINK \l "_Toc176025240" 2.9 lcp_readpol  PAGEREF _Toc176025240 \h 15  HYPERLINK \l "_Toc176025241" 2.10 lcp_mlehash  PAGEREF _Toc176025241 \h 16  Introduction In order for Intel® Trusted Execution Technology (Intel® TXT) Launch Control Policy (LCP) to function, the Platform Owner needs the ability to establish a policy on the platform. The LCP Tools described in this document allow end-users to create policies and provision a TPM with the policies. This document does not describe the Intel® TXT Launch Control Policy functionality. That will be provided in a separate specification to be released shortly. Commands Pre-requisites In order to run the tpmnv_* commands, a TPM driver and TSS (TPM Software Stack) must be loaded. On Linux versions after 2.6.17, the tpm_tis v1.2 TPM driver should be available. It should be loaded as ‘modprobe tpm_tis’, but in some cases that does not work and it is required to be loaded as ‘modprobe tpm_tis force=1 interrupts=0’. The TSS used does not need to be fully v1.2 compliant but it must at least support the TPM NV (TPM non-volatile memory) commands (Tspi_NV_*). The latest (CVS) version of the TrouSerS TSS has this support. tpmnv_defindex Function: This command is used to define the TPM NV index where the LCP policies are stored. This command can also be used to define non-LCP TPM NV indices. Usage: tpmnv_defindex -i index [-s size] [-pv permission_value] [-p password] [-av authentication_value] [-wl write_locality] [-rl read_locality] [-h] Options: -i index: UINT32 or String, the index value to define 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001 (INDEX_LCP_DEF), ”owner”: 0x40000001 (INDEX_LCP_OWN), “aux”: 0x50000002 (INDEX_LCP_AUX) -pv permission: UINT32, the permission value of the index Default permission value for indices: INDEX_LCP_DEF: 0x00002000; INDEX_LCP_OWN: 0x00000002; INDEX_LCP_AUX: 0x00000000. This is optional for the above indices but required for others. -s data size: UNIT32, the size of the index Default value for indices: INDEX_LCP_DEF: 34 bytes; INDEX_LCP_OWN: 34 bytes; NDEX_LCP_AUX: 64 bytes. This is optional for the above indices but required for others. -av auth value: string, the authentication value for this index Authentication value for the defined index; it is the password for the NV if the permission is AUTHWRITE or AUTHREAD. -p password: string, the TPM owner password -wl write_locality: UINT8, the write locality attributes for this index -rl read_locality: UINT8, the read locality attributes for this index -h help, print help message Examples: tpmnv_defindex –i 0x00011101 –pv 0x4 –s 34 –av 123456 –p 123456 tpmnv_defindex –i aux tpmnv_relindex Function: This command is used to release a previously-defined index. This command only can be used by TPM owner. Usage: tpmnv_relindex -i index -p passwd [-h] Options: -i index: UINT32 or String, the index value for releasing 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001 (INDEX_LCP_DEF), ”owner”: 0x40000001 (INDEX_LCP_OWN), “aux”: 0x50000002 (INDEX_LCP_AUX) -p password: string, the TPM owner password -h help, print help message Examples: tpmnv_reldndex –i 0x00011101 –p 123456 tpmnv_defindex –h tpmnv_lock Function: This command will lock the TPM NV. This command is specifically used by platform manufacturers once the platform personalization process is complete. TPM NV lock is a one-way operation: after locking the TPM NV cannot be unlocked. Usage: tpmnv_lock [-f] [-h] Options: -f force Lock the TPM NV without warning. -h help Print out the help message. Examples: tpmnv_lock –f tpmnv_getcap Function: Display the either the list of defined TPM NV indices or the attributes and contents of a specified index. Usage: tpmnv_getcap [-i index_value] [-f password] [-h] Options: -i index value: UINT32 or String 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001(INDEX_LCP_DEF), ”owner”: 0x40000001(INDEX_LCP_OWN), “aux”: 0x50000002(INDEX_LCP_AUX) If this option is specified, then the public data of the index will be displayed. -f password: String Display the TPM_PERMANENT_FLAGS and TPM_STCLEAR_FLAGS contents -h help Print out the help message. Examples: tpmnv_getcap –i 0x00011101 tpmnv_getcap lcp_crtpconf Function: Create a platform configuration measurement. The produced platform configuration measurement will be appended to the input file in binary mode. Usage: lcp_crtpconf -p PCR_index1,PCR_index2,...,PCR_indexn [-f filename] [-h] Options: -p PCR_index1,PCR_index2,...,PCR_indexN Index values can be 0-23. -f file_name: string File name to which the measurement is appended. -h help Print out the help message. Examples: lcp_crtpconf –p 0,1,2,3 –f pconf_file lcp_crtpol Function: The command is used to create an LCP policy (and optionally policy data), which can later be written to the TPM. Usage: lcp_crtpol -t policy_type [-a hashalg] [-v version] [-sr SINIT revocation_counter] [-s srtm_file] [-m mle_file] [-o policyfile] [-b policydata_file] [-pcf Policy_Control_Field] [-h] Options: -t Policy type: UINT8 or string 5 strings are supported for the reserved LCP Policy Types. Strings and default policy type values for each string are: “hashonly”: 0 (POLTYPE_HASHONLY) “unsigned”: 1 (POLTYPE_ UNSIGNED) ”any”: 3 (POLTYPE_ ANY) ”forceowner”: 4 (POLTYPE_ FORCEOWNERPOLICY) -a Algorithm: UINT8 or string Currently we only support SHA-1 algorithm: POLHALG_SHA1(0 or “sha1”). -v Version: UINT8 Version number. Currently it must be set to 0 if specified. -s PConf file name: String File name of the Platform Configuration data, as produced by lcp_crtpconf. -m MLE file name: String File name of file containing MLE hash values. This is a text file that contains one SHA-1 hash per line. The values 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 lcp_mlehash command. -o policy file name: String File name to store the output policy. -b policy_data file name: String File name to store the LCP Policy data. -sr SINIT Revocation count number: UINT8 -pcf policy control field: UINT32 -h help. Print out the help message. Examples: lcp_crtpol –t 0 –r 0,0,0 –m mle_file –o policy_hashonly_file lcp_crtpol –t 1 –m mle_file –s pconf_file –o policy_unsigned_file –b policy_data_file lcp_crtpol –t 3 –o policy_any_file lcp_crtpol –t unsigned –a sha1 –m mle_file –s pconf_file –o policy_unsigned_file –b policy_data_file lcp_writepol Function: The command is used to write LCP Policy into a (previously-defined) TPM NV index. It also supports writing arbitrary data into a specified index. Usage: lcp_writepol -i index_value [-f policy_file] [-p passwd] [-e] [-h] Options: -i index: UINT32 or String. Index for writing 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001(INDEX_LCP_DEF), ”owner”: 0x40000001(INDEX_LCP_OWN), “aux”: 0x50000002(INDEX_LCP_AUX) -f file_name: string File name of where the policy data is stored. Mutually exclusive with –e option. -p password: string, the TPM owner password -e: write 0 length data to the index This is useful for special indices, such as those whose permission is WRITEDFINE. Mutually exclusive with –f option. -h help Print out the help message. Examples: lcp_writepol –i default –f policy_file lcp_writepol –i 0x00011101 –e lcp_writepol –i 0x00011101 –f policy_file –p 123456 lcp_readpol Function: The command 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. Usage: lcp_readpol -i index_value [-f output_file] [-s size] [-p passwd] [-h] Options: -i index: UINT32 or String. Index for reading 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001(INDEX_LCP_DEF), ”owner”: 0x40000001(INDEX_LCP_OWN), “aux”: 0x50000002(INDEX_LCP_AUX) -f file_name: string File name to write the policy data to. If no file name is specified then the contents will be displayed. -s size to read: UINT32 Value size to read from NV store. If no size inputted, read by length as this index defined. -p password: string, the TPM owner password -h help Print out the help message. Examples: lcp_readpol –i default –f policy_file lcp_readpol –i 0x00011101 –s 10 lcp_readpol –i 0x00011101 –f policy_file –p 123456 lcp_mlehash Function: The command 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 lcp_crtpol command. Usage: lcp_mlehash [-h] [-v] mle_file Options: mle_file: string File name of the MLE binary. If it is a gzip file then it will be un-zip’ed before hashing. -v Verbose mode. -h help Print out the help message. Examples: lcp_mlehash sboot.gz        FQXYZ\lmÍÎ+ , ‰ Š ë ì T U ¶ · ~  Ü Ý < = ¥ ¦  ] ^ ¼ ½ ïáϻϩ•©Ž†~vmcmcmcmcmcmcmcmcmcmcmcmcmchÞ\h™-ÏaJo(hÞ\h™-ÏaJh™-ÏCJ$aJ$h² >CJaJh² >CJ$aJ$ hyg&h™-Ï&hZ@h™-Ï5B*CJ(\aJ(o(phÿ#hZ@h™-Ï5B*CJ(\aJ(phÿ&hZ@hã8:5B*CJ(H*\aJ(phÿ#hZ@hã8:5B*CJ(\aJ(phÿh™-ÏB*CJ(aJ(o(phÿ hô_’h™-ÏB*CJ(aJ(o(phÿ&AYZ[\ F P$©¡ªa¶óóóóóå×ÎÉÉÁ»»»»µ°®®¬8gd™H$gd™H$gdÇ$a$gd² >gdÇ„Z`„ZgdZ@ $„ZWD–`„Za$gdÇ $„ZWD–`„Za$gdZ@ „XH$WD–`„XgdZ@°8Â8ýý½  OP€ßà…†defˆ‰ŠžŸ ¡¨©ª«ÂÃÄÅ÷í÷í÷í÷í÷í÷í÷çÚ÷ÊÚ¿Ú÷¶®§ ŠxŠeWhÒ#-h™0JmHnHu$jhÒ#-h™0JUmHnHu"høYCJKHOJQJaJnHtH+jhøYCJKHOJQJUaJnHtH h™h™-Ï h™hã8:h™hã8:o(h™h™-ÏaJhÞ\h™-Ï0JaJjhÞ\h™-ÏUaJjhÞ\h™-ÏUaJ h™-ÏaJhÞ\h™-ÏaJo(hÞ\h™-ÏaJÅáâãäåæòóô234567?@A[öè̹èŸè”…”t…i…¹Ÿ¹èöèM¹èŸè”…”6jÅh™h™>*B* UaJmHnHph`¨uhÀ4mHnHu jHh™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHphÿtHu$jhÒ#-h™0JUmHnHu6jËh™h™>*B* UaJmHnHph`¨uhÒ#-h™0JmHnHuh™mHnHu[\]^_`abc€‚…†”•–°±²³´µ¶·¸ÔÕïàÕਚ‘šuš¨šjàjYàÕਚ‘š j<h™UmHnHuh™mHnHu6j¿h™h™>*B* UaJmHnHph`¨uh™mHnHuhÒ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHphÿtHu$jhÒ#-h™0JUmHnHuhÀ4mHnHujh™UmHnHu jBh™UmHnHuÕÖ×ÚÛéêë     )*+,/0>?@ZäÑéÞž~sÑ©ÑÃjÃNÑéÞž6j³h™h™>*B* UaJmHnHph`¨uh™mHnHuhÀ4mHnHu j6h™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHphÿtHuhÒ#-h™0JmHnHu$jhÒ#-h™0JUmHnHu6j¹h™h™>*B* UaJmHnHph`¨u¶ `±Y«ÿR¦¨µÜ{„“óᯱÀË^ýýýýýýýýýõìççâÝØØØØÝË„C^„CgdÇ „¤„X^„¤`„XgdZ@gdÇgd™gdZ@gdÇ„`„gdZ@ & FgdÇZ[\]^_`ab~€„…‘«¬­®¯°±²³ÏÐïàÕਚ‘šuš¨šjàjYàÕਚ‘š j*h™UmHnHuh™mHnHu6j­h™h™>*B* UaJmHnHph`¨uh™mHnHuhÒ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHphÿtHu$jhÒ#-h™0JUmHnHuhÀ4mHnHujh™UmHnHu j0h™UmHnHuÐÑÒÕÖâãäþÿ#$%&)*678RäÑéÞž~sÑ©ÑÃjÃNÑéÞž6j¡h™h™>*B* UaJmHnHph`¨uh™mHnHuhÀ4mHnHu j$h™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHphÿtHuhÒ#-h™0JmHnHu$jhÒ#-h™0JUmHnHu6j§h™h™>*B* UaJmHnHph`¨uRSTVWXYZ[wxyz}~ˆ‰Š¤¥¦¨©ª«¬­ÉÊïàÕਚ‘šuš¨šjàjYàÕਚ‘š j h™UmHnHuh™mHnHu6j›h™h™>*B* UaJmHnHph`¨uh™mHnHuhÒ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHphÿtHu$jhÒ#-h™0JUmHnHuhÀ4mHnHujh™UmHnHu jh™UmHnHuÊËÌÏÐÜÝÞøùúüýþÿ #$/01KäÑéÞž~sÑ©ÑÃjÃNÑéÞž6j h™h™>*B* UaJmHnHph`¨uh™mHnHuhÀ4mHnHu j h™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHphÿtHuhÒ#-h™0JmHnHu$jhÒ#-h™0JUmHnHu6j• h™h™>*B* UaJmHnHph`¨uKLMOPQRSTpqrswxƒ„…Ÿ ¡£¤¥¦§ïàÕਚ‘šuš¨šjàjYàÕà¨A/jhøY@ˆCJKHOJQJUaJnHtH j h™UmHnHuh™mHnHu6j‰ h™h™>*B* UaJmHnHph`¨uh™mHnHuhÒ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHphÿtHu$jhÒ#-h™0JUmHnHuhÀ4mHnHujh™UmHnHu j h™UmHnHu§¨µÇÈæìíó5ANPgiw¢¥ÛÜ{‚ƒøôåÕ寶Æå¢å“å„å“å“¢q¢qa“Q“MIhÄ"h±hÄ"hÄ"CJH*OJQJaJh™-ÏCJOJQJaJnHtH$hÄ"hÄ"CJOJQJaJnHtHhÄ"hí#gCJOJQJaJhÄ"hÄ"CJOJQJaJ'hÄ"h™-ÏCJOJQJaJnHo(tHhÄ"hã8:CJH*OJQJaJhÄ"hã8:CJOJQJaJhÄ"h™-ÏCJH*OJQJaJhÄ"h™-ÏCJOJQJaJh™-Ïh™-ÏnHtHƒ„‡ˆ’·¹ºÆãñ¹ÑØÙÚÞàá®°±·¼½¿ÀÊËÒ *J\^elnostŸ§©«ÈÉôøùüøôíøéôéôéôøåøåøôøåáåÝÖÏÖÝÇ¿»å»å»å»·Çª›ª›Žª„ª›„ª›ª›ªhÇ'üB*aJphh"Åh °B*aJphh"Åhb NB*aJo(phh"Åhb NB*aJphh"Åh—@ÔhC :hC :5hC :hb N5 h™hb£ h™hb Nhb Nh™hÇ'üh3G¶ h™hÄ"h4;hÄ"hK+4^e­ßù9¦ÎôRy–³Ð?[uò娨ò˾¾¾¾Ë±¾¾¾¨Ë±¾„Z`„ZgdZ@ „H„Z^„H`„ZgdZ@ „ì„Z^„ì`„ZgdZ@ „;„Z^„;`„ZgdZ@ „„Z^„`„ZgdZ@ „¤„Z^„¤`„ZgdZ@ „¤„X^„¤`„XgdZ@ù89Pm|ƒŽ£¤¥¦§®¯°±»¼½ÊËÎÏÔÕáâãðñôõøù.1RSZe‡ˆ‰¤¥¦ÁÃ÷óïóêåêáÙêÙÑÊÆåÆÊåÊïå¿åÊÆåÆÊïå¿åÊ´¨´•¨´¨ŽóŽÑÊÑÊóÑÊóÑÊó hhJÇh"ÅhÇ'ümH sH h°‚h"ÅmH sH h°‚h°‚mH o(sH h°‚h°‚mH sH  hb Nh°‚h°‚ hb Nh"Åhb Nh"Åo(hb NhõZ o(hõZ h°‚o( hõZ o(hÇ'üh"ÅhC :hb N58ÃÅÌÍÎÏÐØý?@ijklmsuƒ…†ŒŽœŸ¥§«¬±×éêì,0:EIVWX[ ¡¼Îë2\gxy€ƒ…ùõùíõèãßÚßãõÒËÒõÒÆÒõùõÆõùËõËÒËõèãßãßãõ¿·¿·¿³·³·¿õèõ¬õ¬õ¬õ¤Ÿ¤õ h"Å5h8(ëh"Å5 h‚{qh"ÅhÀ4hjhåh"Åo( hjhåh"Å hzi!o( h¯Xóh"Åh¯Xóh"Åo( hÇ'üo(hÇ'ü hÉR‘o( h"Åo(hb Nh"Åo(h"Å hb Nh"Å=u¬ì,£Ï]yƒÅÝí÷_gŽ˜ÕòòåØòØØØØÏÆÆÁÏ¸Ï«ÏØ „¤„Z^„¤`„ZgdZ@„C^„CgdÇgd™„Z`„ZgdZ@„X`„XgdZ@ „;„Z^„;`„ZgdZ@ „H„Z^„H`„ZgdZ@ „ì„Z^„ì`„ZgdZ@…‹ÇÍÙÜÞìí÷$^_gnpquˆŽ—˜ÓîãÖÒÍÉÅÁ¹ÒµÒŧ–ƒpƒ–ƒ_SIDÒ h±o(hþc›h±5o(h¥P¿h‚{q5mHsH!h¥P¿h‚{qB*aJmHphsH$h¥P¿hß@B*aJmHo(phsH$h¥P¿h±B*aJmHo(phsH!h¥P¿h±B*aJmHphsHh¥P¿h±5mHo(sHhÇ'üh‚{qh‚{q5h±h‚{qh™ hk"€o(h"Åh"Åh"ÅB*aJphh¥P¿h"ÅmHsH!h¥P¿h"ÅB*aJmHphsHÓÔÕ  * ? A B C J L M W X Y f g j k p q } ~  Œ ‘ ” ¡ ¢ £ ° ± ´ Í ß ê û ü !!!!!!!!!úöñíåñåÞíñíñÞÚñÞñÞíñíÞÚñÞñÞÏÃÏ»ÃÏÃÏöúö´ö¬§¬ö–ƒ–ƒ–$h¥P¿h"ÅB*aJmHo(phsH!h¥P¿h"ÅB*aJmHphsH h"Å5h8(ëh"Å5 h‚{qh"Åh´F1mH sH h°‚h°‚mH o(sH h°‚h°‚mH sH h´F1 hb Nh°‚hb Nh°‚o(h°‚ h°‚o(h"Å h"Åo(1ÕB j ´ à ü !/!C!O!Y!B"J"_"h"q"“"›"¸"òòòòååÜÓÓÎÜÅܸܸ«¸« „H„Z^„H`„ZgdZ@ „ß„Z^„ß`„ZgdZ@„Þ^„ÞgdÇgd™„Z`„ZgdZ@„X`„XgdZ@ „;„Z^„;`„ZgdZ@ „ì„Z^„ì`„ZgdZ@!1!7!B!D!E!O!Y!Ê!Ù!" ","/"@"B"J"P"Q"V"X"Y"Z"_"h"i"p"q"u"ˆ""‘"›"œ"¶"·"¸"¿"À"Â"É"Ê"Î"Ï"Ð"Ò"Þ"õèäàÜÕÍÉÅÉÁÉÁɽ³½¬¤¬¤¬¤³½Ÿ½˜“‹“½˜‹˜½ƒ~ƒ½¬¤à½àzhái£ hQNW5h8(ëhQNW5h-ìhQNWo( hQNWo( h-ìhQNW h´F1o(hùhQNWo( hùhQNWh s=hQNW5o(hQNWh´F1h7&Yhûh s=hQNW5 h‡:æh‡:æhùh™h"Åh"Åh"ÅB*aJphh¥P¿h"ÅmHsH.¸"Â"Ñ"ß"é"T#\##–#·#$$K$p$“$å$ù$8%A%öéäöÛöéöÎÁÁÁÁ´§š§ „H„Z^„H`„Zgd² > „h„Z^„h`„Zgd² > „H„Z^„H`„ZgdZ@ „ì„Z^„ì`„ZgdZ@ „;„Z^„;`„ZgdZ@„Þ^„ÞgdÇgd™ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@Þ"ß"é"ð"õ"S#T#\#b#i#k#z#ˆ##–#¬#·#ú#$ $!$#$$$%$,$.$/$9$:$G$H$K$L$Q$R$^$_$l$m$p$q$t$$‚$$$“$¥$®$ä$å$%8%?%@%A%B%üôðìðåÛìåìå×åÛåÓÎÊÂλÊÎÊλλλÊÎʻλλ°¤°¤°¤°ìðì×–åŽåhåjWhÓ. o( h² >h² > h-ìhÓ. h°‚h°‚mH o(sH h°‚h°‚mH sH  hb Nh°‚hb Nh°‚o(h°‚ h°‚o(hF1h² >h8(ëhÓ. 5o( håjWhÓ. hÓ. h´F1h8(ëhÓ. 5h‡:æ8B%\%]%d%e%g%m%t%ˆ%Ž%%•%—%œ%%§%­%¯%6&7&8&?&D&F&L&N&O&Z&d&i&†&‡&&’&“&ž&¨&¬&·&¸&¹&º&Ð&Ó&Ô&÷ðèãèߨߨÔÍÅÍÁ¹µ°µ¨¡—ˆµµµµ—µµµ„µµ„xph-ìhhbòo( h-ìhhbò hhbòo(h´F1hù 3hhbòo( hù 3hhbòhë6éhhbò5o( håjWhhbòhåjWhhbòo( hµc o(hhbòhë6éhhbò5håjWhåjWh±o( håjWh±h™ håjWhÓ. hÓ. hÓ. 5h8(ëhÓ. 5 h-ìhÓ. h-ìhÓ. o(,A%]%g%‚%%%§%8&?&‡&&º&Ô&é&'#'@'J'q'}'‡'ø'ÿ'R(òéÜÜ×éÎéÜéÜòÜòÜòéÜ×éÎéÜ„Þ^„ÞgdÇgd™ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@ „H„Z^„H`„ZgdZ@Ô&è&é&ó&''$'>'?'@'G'H'J'K'P'R'X'Y'['\']'^'_'b'p'r'w'y'z'|'}'‡'ˆ'“'›'ž'Ÿ'¥'¨'²'÷'ø'ÿ'((( (Q(ü÷ðüðìäðìÜ×ÜìÐÈÐìÃüÃüÃü쿸°¸°¬¤ › › ›ü ü—†~†~†hâGthÙ?³o( hâGthÙ?³hë6éhÙ?³5o(hÙ?³ hµc o(hµc hë6éhÙ?³5h”+Êh”+Êh±o( h”+Êh±h™ h$Ïo(hù 3hhbòo( hù 3hhbò hhbò5h8(ëhhbò5h-ìhhbòo(hhbò h-ìhhbò hhbòo(h´F1/Q(R(”(•(µ(¶(¿(Ô(Þ(ß(').)9)?)T)U)Z)[)\)d)e)f)g)h)j)z){)|))‚)Š)‹)Œ))Ž))˜)™)¡)¢)£)¨)©)¬)­)®)°)±)³)»)¼)¿)À)Á)Æ)Ç)Ñ)úïãÜÔÊÆÁƼ¸¼°¼°©¼¸¼¸©¤©¼¼•©¸¼¸©¤©¼Ž¼•©¸¼¸©¤©¼Ž¼•©¸¼ h¸ h¸ hçNyhÙ?³o( hçNyh¸  h q¯o( hçNyhÙ?³hb Nh¸ o(h¸  h¸ o( h´F1o(hÙ?³hë6éhÙ?³5o(hXRhÙ?³o( hâGthÙ?³h¥P¿h°‚mHo(sHh¥P¿hÙ?³mHsH h°‚o(8R(•(¶(¿(ß([)|)£)Á)ò)*V*h*¤*¿* +#+\,y,Ÿ,À,è,òòéÜϵµµÜµÜµÜÏÜÏÜÏÜÏ „H„Z^„H`„ZgdZ@ „„Z^„`„ZgdZ@ „ì„Z^„ì`„ZgdZ@ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@ „±„Z^„±`„ZgdZ@Ñ)Ò)Ó)Ô)Õ)×)ß)à)ð)ñ)ò)****9*M*N*R*S*U*V*]*g*h*x*£*¤*¾*¿*Ð*Ý*æ*ë*+ +"+#+%+[,\,y,{,˜,,ž,¯,¿,À,ç,è, ----:-<->-X-Z-a-b-d-üõðõëäÝäëÕÑÌÑäüëüëüëÄÑÀÑõÀÑÀÑõѼõ¼õ¼Ñõ¼õÑõ¼õ¼Ñ¼ÑõÕѵѵѰÑÕõ¨£¨ hÙ?³5h8(ëhÙ?³5 hÙ?³o( híkŠhÙ?³hšf¶h´F1hçNyh¸ o( h´F1o(hÙ?³hçNyhÙ?³o( h¸ h¸  hçNyh¸  h¸ o( h q¯o( hçNyhÙ?³h¸ >è,-3-=-Z-d-¡-ç-ø-.G...š.-/4/w/€/®/0B0òååØÏååÂåòؽϴÏòÏòØØ„Þ^„ÞgdÇgd™ „'„Z^„'`„ZgdZ@„X`„XgdZ@ „ì„Z^„ì`„ZgdZ@ „ß„Z^„ß`„ZgdZ@ „¤„Z^„¤`„ZgdZ@d-i-k-l-n-o-t-u-}-¡-¦-¨-©-«-¬-ø-ý-ÿ-.... .".#.%.&.).1.5.9.€.‚.‡.‹.Œ.Ž..˜.™.š.›.¦.®.·.».Ç.É.Þ.ä.å.æ.ê.ë./,/-/3/4/ùñùñùíéäíùñùñùíùñùñùíùñùñùíßíßíÛÔÌÔÌÈÀ»·³®³®³®³ª®³ª³¥ª¡“»hþc›h±5o(h‰zh¯SÅ h‰zo(hšf¶ hµc o(hµc h“Rº h±o(h‚{qh“Rº5h8›h8›h±o( h8›h±h™ h q¯o( h¿xo(h¿xhÙ?³hâGthÙ?³o( hâGthÙ?³:4/9/=/>/@/A/r/v/w/x//€/œ/¢/­/®/ñ/ø/00000#0$0%0&00010>0?0B0C0H0I0U0V0c0d0g0h0k0x0y0†0‡0Š0Œ0ž0Ÿ0«0±0Ë0ùñùñíùñéá×áÓËÓÆÁ½µÁµ®½Á½®Á®Á®Á®½Á½®Á®Á®£—£—£—£Ó“ÓŒ„ŒhçNyhÙ?³o( hçNyhÙ?³h¯SÅh°‚h°‚mH o(sH h°‚h°‚mH sH  hb Nh°‚hb Nh°‚o(h°‚ h°‚o( hÙ?³o(hŠ[hÙ?³o(hÙ?³hó ÝhÙ?³5o(hó ÝhÙ?³5h±h.%=h“Rºh±o( h“Rºh±4B0g0Š0Ÿ0ñ01B1¹1Á1Þ1è12-2a2n2y233_3h3òòåØËåòåòµµµ°Â§Âå„Þ^„ÞgdÇgd™ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@ „;„Z^„;`„ZgdZ@ „H„Z^„H`„ZgdZ@ „¤„Z^„¤`„ZgdZ@ „ì„Z^„ì`„ZgdZ@Ë0ð0ñ0 111%1A1B1Q1U1s1t1z1…1¸1¹1Â1Ü1Ý1Þ1å1æ1è1í1ñ1ò1ô1õ1ø1ÿ1222222-222627292:2`2b2g2j2k2m2n2w2x2y2üøôïôèüèüáüáüáüáøÙáÔÌÇÌÀ¸À¸´ø¯øÀ¸À¸´øÀ¸À¸´ø«¤œ¤œ˜‹‡hZ*É hZ*Éo(h‚{qhZ*É5hŽ+öhŽ+öh±o( hŽ+öh±h™ hk"€o(h:M×h“Rºh:M×o( h“Rºh:M× hÙ?³5h8(ëhÙ?³5 hÙ?³o(hçNyhÙ?³o( hçNyhÙ?³ hÙ vhÙ?³ h.%=o(h.%=hÙ?³h¯SÅ4y2z2„2Œ2”2¨2«2¬2­2³233333 3!3#3$33343B3C3D3M3N3O3X3Y3Z3^3_3h3„3Š33•3–3Ù3à3ë34444 4 4444&4'4ùñíñéíñéñéùßÚÓËÓËÇÓËÓËÓûËÓËÃË·­©¡é©š•‘‰•‰‚‘•‘•‚•‚• hb Nh°‚hb Nh°‚o(h°‚ h°‚o( hŠ[h‡oOhŠ[h‡oOo(h‡oOh[(Th‡oO5o(hŠ[hZ*Éh5[.o(h5[.h‰zhZ*Éh±o( hZ*Éh± h±o(hþc›h±5o(h¨1ƒhÑ+Ìh[(ThÑ+Ìo( h[(ThÑ+Ì3h3–34*4O4r4‡4ð45e5‘5™5¶5À5æ5696F6Q6¾7òååååØåØåËØ¾µØØØ°µ§„Þ^„ÞgdÇgd™„X`„XgdZ@ „H„Z^„H`„ZgdZ@ „;„Z^„;`„ZgdZ@ „ß„Z^„ß`„ZgdZ@ „ì„Z^„ì`„ZgdZ@ „¤„Z^„¤`„ZgdZ@'4*4+4042434=4>4K4L4O4P4S4`4a4n4o4r4†4‡4‘4¬4®4¾4ï4ð455*5+5d5e5~55ž5´5µ5¶5½5¾5À5Å5È5É5Ë5Ï5Ö5ùõðõðùðùðùåÙåÙåÙåÕÑÊÕÑÅÕ½ÕÑʹ´¬Ñ§ÑŸÊ˜‹„|„|Ñw hk"€o(hZ*Éh‡oOo( hZ*Éh‡oO h‡oO5h8(ëh‡oO5 hb£h‡oOhÎÜh‡oOo( h‡oOo(h>{Úh‡oOo( h>{Úo(h>{ÚhoT+h‡oOo( hoT+o( hÎÜh‡oOh‡oOh¨1ƒh°‚h°‚mH o(sH h°‚h°‚mH sH  h°‚o(h°‚ hb Nh°‚.Ö5æ5ë5î5ï5ñ56 666686:6F6O6P6Q6R6\6d6h6U7½7¾7Ä7Å7É7Ð7Ñ7ã7ä7í7ñ7þ78Z8[8]8^8k8l8y888‘8˜8™8›8Ÿ8üõíõíüõíõíüéåÝØåÑÉåÉÅÁѷذÅåÅå¦ÅåŸÅ—ÅåÁÅ埈€{€° h{#?5h8(ëh{#?5 hb£h{#?hÎÜh{#?o(hoT+h{#?o( hÎÜh{#?h[(Th{#?5o( hZ*Éh{#?hþc›h{#?5o(høYh¥P¿h[(Th{#?o( h[(Th{#? h{#?o(h‚{qh{#?5h{#?h™hZ*Éh‡oOo( hZ*Éh‡oOh‡oO0¾7Å7ä7í7þ7[8^8l8t8‘8›8°8²8³8µ8¶8¸8¹8»8öéöÜϹܬöÜ£¡£¡£¡£„Z`„ZgdZ@ „H„Z^„H`„ZgdZ@„ó^„ógd¥P¿ „;„Z^„;`„ZgdZ@ „ì„Z^„ì`„ZgdZ@ „ß„Z^„ß`„ZgdZ@ „¤„Z^„¤`„ZgdZ@„X`„XgdZ@Ÿ8¯8°8±8³8´8¶8·8¹8º8¼8¾8¿8Á8Â8Ã8üøðìðìðìðìèØèìøjh™UmHnHtHuh™hH+jhH+Uh{#?høY»8¼8½8¾8À8Á8Â8Ã8ýôôëôýÞ „ß„Z^„ß`„ZgdZ@„Z`„ZgdZ@„Z`„ZgdZ@:&P182P:pã8:°Ð/ °à=!°"°# $ %°°R°â ©`!ðLeƽb ŒÔÔ«/d×ÄÝaµ•bfM(ÄìëeþxÚì½ËrcÉ’ –UÓš8‚ÍØìdÒâŒF5VÙ²"Îçà lÔeIÜ›së‘S¬{»®ÒÊ($‰dò ° 0 £Ì´“i¥å|€>B m´×GÈ´—If2i!4òg„Gœs@棺o«›‘Iñôðððp÷ðˆøäQïÑ£¿—ý—Ÿ>úþÏð~¾€ÿÿüïÿ£GO}süô·Ó£§ÇÉÁw_÷ýáÑ,ùO!íøÿ/äï~š¦üóïÂÿÿëSÿýO°µO~ɱCÿæÓ°½Oý;ð÷ÓO°6ü´ÿÉ¿¿ÿCøÿúoÿ-çüo0ñ“?ùô“G¿^\¾Zl.NçöþÕ¿Yý“GÿÝû¿¿þà’þ¯þÇ/þ”ëüTÊÿcjñÑ£ÿžÚüäÓOÿ£ã·ëÍâêÑ#ÌûèÑÞ£þè¿Æºý[øù¯®ÿ‰Àô÷èïÿõ DÿÞ§ÃOþõ'øé~ú?þ¿ý}ÂÏ?ô)`À~ôèÿ¡ÏŸ=ú_?ù_>ùì›cÄÛÓ›Åüêùå"yv¼z±Yüœ¼î§?õ÷××'ëù«EB¿Î/’Áúåêõõü|‘lï0ò¬OnÏ?¯’ªJÎ.N7”ÏE>_œ_,±&H9y¾zsò&KR®ÊE½•¨ [ždigÌ“ÑHà8_.N6/'˜z{³H^Ì/× ­æúäôòâ:ˆ;˜&[”ö6Y¼9})µÃ÷7î»~¹‰r¼>ówý½õfu}½8K–«Ö‰ímnnOwÉþâ µaìôÕTŒ1o1ÐÍ8¹K­7qÑ Ç/>c> f̧¿`{ÊÚÿä“(üý¯?AÚçø>ÆÂÔþ'Ÿ~ú©ŒRo›ð 3)\­`®®å4¹¹¼XbDš%HDO²,ç& ür³bó’ð ãÓlÓ nø7KæggáX‡]†þ^¢ƒý¦‘g}û<±³ÇN8L;»xÕñ¶HP|·/®ƒÒ~~ãÛ·pI»W·—\Îuîç·¾1 „4b ¶m Pps3_®/ç›…kK« ¿€ã»d›&n§2Åò¬¿‡kRÃÿüþ§ôÙ?}züÅälõ|ñE±Ÿ&@3üÐÿì³`‡›ÕÍ— ¥&O./o×Ð8D}þý㤦<“'õ‰äûÝâf}±Z~™dÙ~J‰3,üù×ûO÷“^.žÏo/7£ïÉÁêêz¾|û²ÿp±¹\@‹åfqyrsþü$KÓýÅõú±ÕBÇ¿L†ƒ¬¤4õe9J&ß@†éêvyv±<Ÿ®Þ|I]G¾9Aʯ/¾_¬[’³ý"KËdTíÒ 3®No¯ËÍÓ›Õéb½>X]®nÖ_&oçËä`öËÍ<ùýâòrõ:™^ÎO6EŽo¯¯//gÐÒêöJ™\C-ëņ±wr¹xµ¸ÌO&OÊ$ÛÏDÏâ³üꛓ_ÝÌÏ. &HNãdªÀyrp@-Ðõý¢5›&i­=ß).aIÕ-©ë—sÄÔP+@PÙÉìâr£z5ß$Ã}Š+®ß®.@~æè'ËÓËÛ³ÅS@ÔâŒÀ^cÂè„>/6¨ДAëßÿjjqþ¥ïçϾ‡e“:#ÿÓc¢·Š<^\Ï9ª‚Z |Žh9\¼º‚L‰Ïø¨§ß]cÄš UH tÆð·¬v¾ÈðŸÏÖü„Ÿó¤H†ÔÌÓ§‡ØDÎéUš KHÍ%ÖQÿç$âï‡ÅÕ5Îr"Ø2Û/“¢ÞÏÓ,¾H^Ê÷EQdûY=„ªò²Ø/‡ã:0ÈYY%E‘îgE:ä2žØ¯.¯¿Lž0fx2›ñhOn6Ç ÃÊsšæ¹Rqò÷·—‹›ß./6€ÊÔ•˜]ÎqX-nè7gøa~s¾Øà,¹¼Ý·¨SIúööêëùÛÅ Ó2–ï®ËV¿#辨«d<ÆÖóˆ¿)k }Ê+ª}” sß–ÃRZÎí§@tßÝ\€öåy|1¤iÁ$ù«›‹3O‘£<©ù¾_›ÿcýÇ'ÐÙÍf±ˆG'?¼¼½z¾œ_\B ´ü‹f×¥?à\s¨¼¶õëÅ›dúvƒ3Öû~ª Çøûà@c‹ÿ¦¦§â(i©ªÂ\€” c®ªÂ\U5›iã1æ1Ï~°ôxŒ¹ÆcÌ…Ÿð7æ:8À\XòàS0Ïl†©³YUaéÙ Óg3.Ã3¼ ·È©XRÓ @;þÆ\Ø'ü¹°OÚSNÃáõ=ÂߨoÅ—Å>áoü†=ÂßXã‰kÆáoì7þÅXì¶ÉØäö1ö cžÙ ãt|rÆ1c‘±„¿¹$÷œ¡gØ6n!×1Òüƒ¹°økâä^sþÅ\Ø?aÆ —Åþáoü†½ãñÇß 9ÆàoÌ…ýÃß<ŠL%ŒWn[T@È•~tÌ>Æ:æb¼)^¸ç =BÎpq»\³ŽçÐ̃½SÊÄÞaiî5§bÿð7æbúÆþ1N¸,þÆ<Ø»þgJÙ:wsÜS·Ò°ÒŠRBΔ´ óBÇ”ñÎÐ1Ö¹]ÆB®#¢}cØ1—¶ÎµsyN熜g&S39ã†k˜ÑÓ¯Ÿí\¦ÿ™ÎV?³Ožö™º•î=ýaiOC:Óý(+–ý8 DŠI,í±¡°*¼Ú.×Ë%³,¥üË\1“Ÿ<çÿ—†CþîÿòOÿ³²äÿ—F#þîÿòO]ó÷ºÖ¶kù™L8ÅÿåŸé”¿û¿üÓÿìðcü_þ9:âïþ/ÿ¤î‡ù9ŽþæqåïúÿBÿòáÁ°œÎŸïøFæ°:œÍ&cü?×É|†ø#ø[OÆ££ÑQQU>ò9„0Òÿ!:,Ò|VNÊI=¬‡PFt2•XS±Ì•ã¿î?•b .ùŒu! åa¨‡;ÚIÝ#—ã(̩震ëEª˜Íêa9Ég.¿@iûR—ŒÁ †zXÃÌöO 8,*ÄB™r 14ýϰþÑÔZϳ’1µ¹œò7Ÿa=CÄÁ¬.¡ö#ê·à‰q4‘Ìf¦¥Ch©6aiê'µÍõbïf‡9¤iŠâZ"L„ƒ±–` ;^£#ÈŸaE©ÐsíEÊt”µßåb VnOò•R§àk,0|‡rEÉmµäQˇTpSTÔ×±û&5Ç ¦‘Î  g?Xz4AÆ!ÏóãØãè9ö iaƒÐâ{“¹}¦‚<—þ”Ø @žs;Çu ~eè‡q‚­–¸„1ŒË*¢ƒ!ÍRèmF#«=ÒZa¦TŒW„f‰Œ Œ÷ÑÌêú3¦jœa?¶å°ÂâˆqBí œ”:øb¥ØŒ ÏÀ#ÄÒÉdŒ³¡â^Øž`~¦8¢à*ê Õ‰ó >•¸~ÈÈËÈaýˆ÷ºäúqžÖ%ŒÜÌÁ¤cÚÿŒzPûyuNeDܸåS†)ŸÑ¬‡±£fŽ£UWxИj1Vi¨=êÇLç#õc,È|#<Žcúa ˜ùïÿæR,my¢´‡µÕ!OËmïh¶—œo;‡;cžùLòײ*ŒÜ,(±Í–•ë(ÝŒó|îÐR$ÂIòP)Ú–<ù9Fð•ºnîjì7b#¹> å*î¢UÅGj‘lŽÂ }Ì,½Äëq)ú‰fÂÔR?Â…|ê9’ôŠg°r)žÔ7‡#Z½eç8í S]‘RiÊÅp"Ž9'¯†ö»@9öAÇ[sÁ¬8™‡íT2çؤ9vä)ltäÖ£*Ä%s ÌóŒqî!ò8‡ñlbrbÇ©0Ñ+U:Ì<“G–3q¦mËq0GÎ-9Zþ3c~$t>RØ\#]™‘6yî;î3!ÙÍR£ŸŸc/í0÷X®Ä˜ª½ü¤cS”<{o–ÏCºÅÒ_¥+p»±âÎq§RǤ‰;^K<%¸Ú2°’•òÈ’PjÊRjÀ džjiõgùFÇ:­ÍJtÍçOÌt­.RCL©‡ŒS[®ñÿHg´å‰¸! £#ŸSg 3ÑAmÖã€/ Ö#´X<´Xt¼ÍKÛV:>’ºb®8R.ìi“g qkIõNÎhÖ áÈísy—Ó•Èþç~3.ƒÙ\Y„º ›º"²Ü`´…;ÆøÔ1GªTž¯£4#CèÖ ·ö`išÉµ§j­îâ„–ÎǺ†5±§6r%Ã4Ó•ÈKRRÊ`ÏÉ G,Ý Lžó†s/ïSº Êp>¡5”¤=åÛæyö‘—Pˆ·LüšG’Ts¿.ÞçùZ“û¡¤‚úœJH\Iú¤é*äJ—œYH/©Xjĺ˜Bi¬¾´ƒ †Í¿¡•Ös»²f›¦PúQTRþ›;læ`;Ù›SåŠLS¹_c 1[w±,ê¼ò‹­;°Ë ¿E}vx4æõ´ÿÙgGË3ÜçåO«+Üa_ëðÓ›Õåê\¿©«È}ž"{Þ3¦áˆ“ 'Ž8Þ$å~š|…“<9ºº½$¿‡ÇPÜ{æH}¡3Íçép¥ƒqñ8ù³¬®ßÞ\œ¿Ü@Òç“l\¾ÈÆãJØ+s½Y,–³˜…Û=·U°ô~=¿|±Y-?¼½^Q;ŽKa‰ÛÅòô­ã½aþ<Êÿ+·ûÊ”Quzl@*ʼnõVé(K‡/’¬Â˜sêKi»Qÿ˲¦¸D˜’#ÄŸÖæ—;•í:ÓósÇÎt&i¢‡ý,sôÀå8Š(ô{Ë4qsB Á­baPq˜z:JâÂUãv,³iï¸OŽÅ_ÇåâtóbÕQƒ&FˆÃ¥–Êà7·Îl˜´–ÒÇp…¹šÿ¼ÐªBöNŽæ>É0bä<š¬ÍÕävÜ‚_Œ÷@?s¨õK[¾)í'bRÔð9¯#-Mòoý€íÍ—oiMýŠ ‰Gÿ§ÉrѶ֛sÌ}ާ€öÂ)i!ó› ¡mµ‹g_Û—7«Ûó—\±k'1ðÙ²fÚ®®¬®½Z_l[½ŠÛQÜ®TNïNÅôöÔ9€(ÿEŽªò»¢rpúv¾ü*Ù½ŠxWì‡ÿU²«3šù-9ë•ìêšæ}Žý_%»ú)YýÀ‚ø¾ÆL°”•p|Ú¶Ô £Êÿœ’á$»¯S že2º†cßI¤\%‚tMÕ&÷ºµKsÈàÚb¿~«]þê›ÄBxÊ¥"õ1mS‡ƒ¼Œ«_P{|wÅÊhžq·ËHñ¤Eª‘í¸ð+ÜzžoϨk@Ъ…®;ë’ô79þåê9N _ë1¹x:_¯¡Üzå9Ÿü `á¤*ã5PBAÔzopòââòòøOk_¯6‡Ú;Lº™_]w$-6‚YÎX®èî.ÏzD4,:‹ÓŸaZ±øß\w˜s0óG†ÇâêžQsî”ËÇÍý"­pÏöÕZ ˜³'2…SÇ·a},þbë&6´K¥ï!–A8´P^E/*l““•oâZ®è„ q1<=¦oÐ{’¿ðÄÞürD@˜ˆëób ž„ÁdH/F»¸z{Ì|»×«qÒQ{Oç7WkŠ;¡PD…˜j”ñ9¦2Lá—Ì.ó\z Dx`ªƒeb²Áàänúï¿›_@ÞH}(ÄàQ‹šU_GÕ‘¿[L7jUeWô"%×ê¸Ä²†IcZö..–®ÚÉëU7¤ØýÄWl¤¶«·ß»5ÍjŒ¬H“}òú%0,:µ-”@w’hY§?wK´ã(ÐSŸ—<Õʘª ЮƒD#r;õ¨(Ír̸Šh2±N³,X—¤ã*F¼zÌ‚šaX-h±Á¦Ò³¬“\˜$HàHŽÉÈ/™‘¸%œâÔÔ|3'nf˜_-âT=C°&‚)V"°¡“ƒàÛ7Á·ßß~CßÚaánHp¶>Yþ¬ȼ51<ƒM‘¨ùNó=,– ÊFhˆ"™ÁQlÐSCìð NÎÖ›ä͵í’öÈtÅ÷AßÛͨ@ÈYˆ©1:ŸgΛËÅò|ó²Døw{NÃ~©ÄÚÁÜ›©oBŒ¿1ƒñ&¨7ñH¾i ¶)®_ÄÃÜ3<‡g]‘tl–—A4‹bW&K?4Jzý.,prz:¹ÁãlåW§æòÒ¥ZÖÓ=Ï­öáxÎ#ðÇ›Õ5S å:Þ¼½\ˆ‘ 9Òž.pœjc¤8ìY[i³Cñr4Qpý;UÒRÄí5 ¶Ü#þmkÉžB‘*yD°SÙÏÎf¯†XK²çí•c¨˜PÏÕ&UòE®Õ>ª¢@y+®™~«%áC€ñBÁàÄÎEȉ)ó¬çìû8ö\–Y&.ŒJRç‰ÌQ·¦Jµœ®|$+±pÕ<Û’áĚꄟÔbõ¶§”Ö´8Vmu}eøHçÂ}+VìÊJ.ÝþajP ž2`¥>[Ü RŠ`Dh•)¶§rTœ R6ÍFéGÀ°¸›KXåAõs udÏÛ³+—g¡P@¢ÂÎö{q Ò²•n5>E`•_ˆÑ­®bþrÌʘã™r~ÃfZ‘”öˆ‘h³gJÐî¸`[QT““@µJ/µÙ~“è”ÑÕáxHÀ=N¿Ý’dÛ)·MÖ–¹ÚóÔäH "/²w¡4(UûÉÇ‚RØr¡fH–vDÌùFÌîgA¼*õâæ½  –²™XÒ¹?2¨ŒL ‘—¶$Wœò' ý1veúþÝ«k³*‚álÚ5:æÓ}Êo>tJõäš™hHjë¤êžUae®6;½Ü.c€‚hfõ4ç$Eвý…æ—N1]7¿ÓÊM¸OÊ: ™Ýz ÔNŽ•UCÅï2Ý|zj Èž…ÑT“AU`ýøÇuñæ–D”¶h¸C!pZò’/¤ùÇÃÕ3:`€“@r›ß-‰QU6‰Å…Í¿D+*˜>ÆöžªèdF¨÷;} z±œ?¿\œ_­V›—Ç/çg+Û÷P¡•÷ÃT×F«9Á¨UÒ~—³MèD>·æó*Ô lÍå¯úÔÌㆨ§cûr±n±»™DOq’âúmA3øz†R“™j¶RCq—¹jzKU«4ÉF’CŸ^ôá¬[j3=VhÛícm>b$jóš?±Þ–ínI ƒºð€Nƒé”¶½^¬çGŠ~¬éª¾­„-Öý%6¶Htà ñÖàðíã;c"#0F îq={F|lîH ¯¢%1lë.Úº 7YФ~r¶8]-¾]Ý\õž¥IöU£ÑOHùHzϲ$•”H) ,e~‘RÙÀKÜüÝØíDeŠ.+Q[?ã¹u±<¼Xo€Á-œ]Ü*-q=·gv¾`‡#&þ¾¨×(Êm ~ÐîüÎ:öK¹‰]ÂÛfI`B–L*„+OŲ̂´Ï$–¥C¹ûÓó˜v25†*û†ý†$jz±Y? ·Õ–¸{)ñ¿^àž¢~ûó‹³ÍË qØÆÁ¦¡ÞÀPœYC±ôKXE0òNißRÑ©&㸀‰ilphu}'Jo[}Àz!}L*ðƵQÖJëÍúͬ+7y(u³,´ÏjŸ¾ Ì-½Ðô`¬´ê”â8Ð\Ù¼gV.Êq5㨷±ÁÑ8ßzFÓvZ‰•0§<Ôž6F”î 4îDcªëíĺÕN ‹^_øpæûÂçÆäAàÉ­Š„.ÿ`袙HµA­í“󣎥ÁŒ)c™k¤oø"b8¶,* 6³b.-+Ó’!놖(ZIC0‹S„)*÷°a´Ôà[pZ9UìÄÕ¸»F*3D—.Έú½{ üf£n.Fxô¢eCeêÒ>yTþ‘ oPþ; 2Ö©CëV,6âõ‘ ¬³Ì‡hز¹cpâWŽ$Ð>“€R¦ÛÆ1ñjynª-Ïd¾<ûS³¶ú´SÖǪù§¦ø˜8ŽbŒsÏ_‹”wf·é%sÙ öÜ}¨>5`ˆ¾7m˜úˆàå ^©Û•n³Ì¹%‹±­‡‰¯ÝLXl5E/×,ÐV~à~|p9ǘLµ›Xs6ò5÷²´­n³ŽF½§30.?ºîæÍâAûÜ£Œq{:Ú€ñè ¤"hwØÚîèžvëÝíVmíæA»Ek»Õ=íŽv·[¶µ[ÞSgµ»Îa[U=ûŸÛ’Ïû]Ç2‰=¾r×”Aš«—NTä;Oš; ¬Ò»MfgÔÉ’ó ïRC goð¦zZ·ž=¿\ˆÍê'w”Å섇Æàä MžÙVr¶öƒôd7P¦†½{ÜÝ 3MZûÖ.çdxÈ ñA5éß–þ#¢ø—¡Ü96…îÑ¿É:G${àˆdFÄêúìa£Ã^¼&‹WÊí@´ZØü.{l= |·ä2†ã/ØõLÍs¿ÊÝGœU{üJF‘8Bn˜ÓçßSžcËÈ2~ûTöíq¬¹¹³óÐFÛ©qÚaû;q®üÞ‡#¶þ5íƒvww»×{w¡·z~|ï¶—CÓ{Xõ/çËåâ’íz¾ãîTšvJ§äZÊÙÐÝs ’N¬ø"Ò;ÝzŽS¾éLù}gÊoÚR4±)Ê’Mñ¾”ô8§NK ü94ÙÝ[a¬Š‘âé%û•›Æêƒe=u‡‹Í.¦” =·œa&D¬Ø“lI(ZE½Í)"5IãØÃÈIOz‘ÚÙÒc™|΀„{Bˆëqà+Œ¬J.‡qM‡G¿^¼Êç’!23›4{½¿¸]ܼåé‚_}Îï§›í~lÎF}‡§˜›«³ÛSHSCãì¯k;ÐÓÖ“ ‰_oµ½“sÎ3÷ií>»OÏݧéÖŒ\ä;¤ž$oÎ4o›o„äR&Âm£µ_þ”õ_Ë k{ÀÚåä NC©, ÁlŸÎ2æÎ<ât’7(ÝJJm3žaº]¢qjk¯j»yˆÎÏtåÐë†]ʺš7È©?Wä]ŠÏÒ]ã–2£§µÖø¾µñÒ¤§Ötæ½õ¼{²·ƒašAø0IvÍËË2ÉË*á›ýTzi±,ɪBéî ~A.Hã{§×Ãh=_ÜWÑ\S–H³Bè8P$Ü5j]ãQx:ª -üÎ+~û-WÄ×OžÿV¼×Âè ãצ ÂÕšðæ*Šs‘¥í"4ø|…{>ÇŽvYÙMÀ­ê^JVB‘–)±xz¬d¦’õK:ŽÂ ë ‚– Â¹Ë9Å´&ï`¡Á;pMéXÃMƒƒéiÔÊôTtIÚñ‰K:h™´xŸ»s-Þ×F§ÕíúåôØ{ב»;‘Wt\ÌÞyGÇQK…¿½A'«¯4HÍòõð<îá9[ìSòàäPô-w”Ówjé=‚êÒÆ–ª•÷ 0F­^4ýgœÂÔÑžUBSÑÿävbƒÏ¨ñH‘8§À¦W ^˜AW1©ª\¬1ol†'óœAMް6ú ¤³¢+“,†Šà\Ôb…/7f9ajÖÑZ'~àšŒ¾ç Ù$0« oÕ’'ÇX1Ó÷äál<Üehö+p5ó}#º³õPr¶/FœÈ LUñÍ]—SDä}“÷Õ¶‹uÔ_3 yŽéñ‡~äóKd^3ççËNÚ°êåf¾ýõ…›moÌgá×— Ó&M^ø”™>y…nð¦—qÓL!;ï bç¯d`ˆÀ‰µÅ5óÜ‚ú ¬¡V¡µ&ÉÆÜ«´Ã´ÃàŒe2ý 2 ­½Ž¹Îåö~J ÈTI2Ó•&KˆÜ[sÔý^,?»ò\™íûÉdÑÕ~¶”tp÷€5u¸-®ó$„"nÏÝ>ÔŠiŒŠ©¢ÂìDØ;“à~ÀžÛHS»á’j/ÌivÓêú[kTò«Y€lnÆ$„õ¥£ã™“Kаz‹Wn¼=×Ñútܽك,8:½ñµ(G°úì‰cVü£°b\åòÙ¼15ÅϘH0ž‹àê Î4Ýh¯dÂ:qT2[qÔžDo=³nYHe õ¥à`}°KévÂ]|àƒ‰š„@¨2ÆàòU6¹ÞžH8NìR§«R*ïøåâòrmL &’': GóÆÉ¢CiZÍ:\•¿ÚÎvÄy\U‰õã=êtñÊö_Z«±:êÀgÚ²~ÀÝ‘ƒ`û÷Gìnúî˜ûÜ#9®Ü“Cš\:•ÄD E˜Æ¼æ4ðN»jDùÓVˆßM}† ŒtY ÍöÑjËô/¤Ó)¨bnæ&ILÈë;’Û[[ógñàÞG¼tZë¼¾€\¬_®.Û*†9ª4Mâ^¬ÝÕÉ÷ÔÔ–1+›ž®–x3óî±YÚæ54wûœw±¾ûMB¦‡¾°O—¤p5/n…÷’ •ï²0ˆ•0‘ÅjºZˆ·äOÀ÷¼É…ÁbŠpûÜDQ!eÐ%6˜‰T;×EB…ÖÞ4bÖ5ç+szàfeoƒI“T 82uP©QËÅy˜Ûh8§—+¼1ž[k»ÀÎ-ƒ1VÐÂn.ô¸7gåÃK¸ÝÖøÉó·Ä AÚÀm½mçù¼ðxží‚p¹œ¥lÒÆ³±QÈŠ‚ï Jº uöwB0qò‘‚è èMYŸÜ‘q Ãl¡3îëš°_8—ç=ãÚôÃÕõ»WUŽÃº\Wß½ª, «rh|תêÊÝüÐåÒ?@Ôbd ÒU_’6¸xÑÈ µG™³83éœÌO_]ø„ VgïîïégÂŽÉõúÚåùI?¨oú®»wžÇ-.œkñu÷Ö#¦ýâÿö[ÿÛ/ýï¾ñ¿ýÂÿÝöon$ ¯sjeûw¸þÊFÔËxÎç.™mXàdßeo'ß¹›Ž[JyƒâŽáâ:¶zåK½ÛE~äÉ¡‘'Ù¦wÛÐlE6.ÿlÁÆíçÏn—§ë YÎÃÞšŽ,qu»åR´Ý&¾£ïiÂÅ 7¯æ—ÎG#ûE ñ8´ †Ã~Ñ¢<*¢¢•>ü½çÌyd¢ð\§ë⇠çÏŸ,ý÷v™N€>ÓË[È#n-ØP‡Ý¶È·m‘?7#²w¸öäè¼¼]u£pÇ|VWó ¯Éˆs®ãAÓ S’`h4éˆP ^ìßgÑ~æàèÍ=õžY Wúýi/.ÄÃÜYC3“RlíL>cAjŠ7£”üé>"4÷ZnÒB¾BäÎõëƒH\ÙÕ»ÓyPò=ˆ]Ê3­?„îµ7_ƒÄp)‡Y‡’–IQüݤøè“Âqr?=î¸yà†‘†þm#ÆOœ8~¨©®`æ°c£nMˆ¥ïþH¿$W{»ç^ï3ÖÁ­¿^ Y5ObçH㸺+nk9Vø{“/,ïÍ’î<ï’«»z®_Þîä·Çg3‹y€—‡ôP/Gö• ü|ÂO*Ï Cu]5ûè±íËÚEÑp…pXȤ²m»fú$8bäÎ YKáLÖ:VáÓ%!Ô^Äÿ˜wÎá$•ù-³—ìñaâžìÈúöáY¯žõ4Ϊ¸m]×Í]||Îʡȟ¨bYÌ™<ö”—Á§ÉaÎŽy$»ôø¢ÀïÔ×:\$½·¬^ÊÅ7 ¡^½§•W:Žc·AT;Т lÈT冖åuð-s´Õy"-o3ÃíP›Ûº¯z‰ æ>»x%Hhc=­lpÝÁ¯T‹ž¤ées9²hËíÞœ÷·f™/ýŒððpÂQ7ů¡U8t=&[ë¼/Ì /•» ÝÑЩ»E2—Û’#ëzñŠÙ¿‘ÓvEW#£¤Ó6~1‡—¡ˆyz|/oÛzÒR½[&¸Z·´„§¸bó„s?޼ȔÓe¢JÚïDíºìÔÜuj—TáE]W†Ç$]B‚µÅ<Ä‹Èsês´)ÿ¾]Dì»è¸2´Ó]÷…~ôJÛ›klmwÝjZ£špäþó{ÎB>à-‰Ö‡$Âã(­ÏJܵ=¸àlŠv¹r>·ñê°{,V_òM†mL]Ï;Dà&Ö¹BjY<~þÀ?~ÐÚ°»?ÕÎþöñ`ç[Ög¯Ø6^spК¸àudûlƒÅ^tè3Fa8ZËEô<†¹žˆi·í¹’®›gÍë¶VÚsÓê½í8õÙc×ú{/™»{Ï÷ÆZÞ ³üªí¥U÷šFÇËZv@vLÿ– Ü}…n–7g¶9çÑzÎôCŒvž½ÿxèG?›Øyñþsˆ8÷ž·àŒ‚Üt¶Z†šÞ …ñ®½ÏŒqî}Ž»Þl;NjéÄ&D*½ÖJ¯}½mFнà5ÊèŸlb¦¥gµ53DI:Ë=ä´DJ„§-Ê«ûKtTÂxB±×7Áózîx˜&‹?îÍpÎÁìr6‡/Ÿ§4ÿ4­Ûj>ÿf~ƒ÷a†'ÊPäÑu‡ó9@YÊHy[ž_É‹áó/nn€-è;(> ó&ÀÎ ÜÈ‘u½‰Ïñ/ã{â´~ÇÇšwðÙÒ÷,ÄÅìtµã[»£'©óT NˆÌ-܃m¼‘§všŽHˆÆÙ={…Æ­8J¢Gö²ðL3Îè37åáXqél¦JÖEa|/Ó¥ÞÝ"Ê(½Ý¸“K/ü’)ž ŽzŒÈHàžòÙav†ó2¸ø-; Ú÷|]†BÆäy,ÙäüçeíÆQöëêÁÞŠTÕ€˜ñ?Ø@LF¦ÿ%jwjÂ/PùÀ `œ¤:j¿D—¬’òKÔoôž_fDT¹ùèµ·[ ¯A¸§†©63Q5]÷«úûov‚¼ê/:ÀîËl¹XGn%à&ñ£acîº[«´µÜ’¹ó\y ’àò·c/dT˜ÎˆÿŽ¡üÁ¢"¸+&ßüÃx†ê8"~ÁCI¹áÃOœÆ,’Žäú?±ù‡Í°w›`^Oî0µù~‰+ò0ÂUKgxˆ)‰t#×è"p5—óÏkòÔTQ0p!m;¨g–2jFtá²nÈ>¬#Gç(Ãämdï9W-\7ã²)‹†Ú2Ù;ÌW’ùâ O)Oò½8²ð‚¼³÷ ½¿³í;K§¹BsªË¢õDƒ¾B®ãÜè€n1SvæøÆ‚ßšã€s”Íî¨rp;jc,ÂÞ°{å_öÊ{±WÝ‹½Ñ½Ø«ß{~õ÷+Jcá/I ÷œtO¿*rñ–UÄÉZ‹È"ÈÙœ%Ïç¢KÔzD«Á2ª±uúuö ß;äæÕÚV§«ë{äÅÞ<EMלžê–ËÝ…ää=&—3z„W-s»²ÎŽÄ‚G ý”Á­2Q7îltÞvÛ³ë[§p6Ð;yóhòšW]u²4sûKßù¿éÌÿMkþßwæÿ}kþßtæÿM”¿«—|BçvÓþjù;ÓMËKYŽK ŒõÉO¾P&=Öìõ1Û÷¯à ¬ ú «Öè-QÎÈîVWg&¸ígÆÓ€€Þ] ßDŸÝ¿ÞÉ-¨QGþîu$~~4ª+>¨ºÄO±FÍÃ÷©y—CV£…òc·° QÕ/ØX?%F%=·Ã¹M(t™€2ìòÈ¿÷ü½kbr2&6Ù/…ëÉòJ³øœ¿øjé BJZ«atmÒ9mu½¹¸ÂSÁ­iÖ”*‡"¿—Ó‘ÔÞ8xñàë du¾Æ“q%qµÓ’ˆG#˜> :tgOG’ySjØ/‰¬#º.½¹V·E€«/'Ý “*Ùqù9´Ëºx$9z¥º#O·¾EoO"öt rËfZÆóÉí·>ã2)=£ I®/|{€Àj83Á°ßXÞõP²ßæmyí‹¿×€¢è48‹ÄS×ô¬óžžpæóÍj¢!a1Üoks©¡þFîlH,€êêÐ#T’¤MHêQ8)÷ÜÕí ¯Õ`ІjƒœyØ,µƒÿ¾³ÔŒ¬©ÎîŽ kJø ëÊ*1ÌNÞL¨ÂæA³Áó[)ðöAâÑ…:và¼'¶ÚåüÝ­ö³ì ØÛ[{Μ‹3’vy?“ÿòºS|HÍ“—H‹3 {¬$ôIìttO–?k ¶»¾C5⦫'¢Ü¡"Ç4ôr´°!k†Ç‰”†a‹3»·ÞÑׯ¸ã›E;¸s7»Fîê?³iän²ˆâía£J¦tÜM¸A[KóR.ÞƒAkm °vQ鄎[0@òNÉ€¶J^½IÝã¾Ì¿T5¯õXcà¯æÐf´œéÙƒà¼(nµèüä¿ñªèU ð)Jç^X#æf‡"«ë+ºhmö+WËÜ…§øÈ“ÒÏfXoy&¼#°TÝ«ŒOÆè„ai¾“w­Ýô}χ&Ðds¼Ø|ÉO<œP³$(ŸLžTI¶_$©}‘¡-“»oï¸'oY°ß,¹X’èuOo=±·»#SlÍ®:´¥…û[Á•÷[}œInÇgšR²Ô It ~"Û]wIxŸ:€‡Ž+\„Ý× ^“mïÈ74/[@ÝYƒk$Jæ ìé-…‹×ø²H✬ù‚¶Ó¬“Û&¾Þd^Q,{íûHoñq89ý·,øÖ *>Ó•ÁC¬ë æùí øÜur¾¹8ç{@ô.<(yõöç þ›Í,Ã6êÇ'G$ðv›Æ‰ÑÃg9]áe& ω|ŽO®ØXv3=@K‰–3ãO/Þ,.M4 â¯ø¢Jûç ³¾Œ#…пz>Ðk“wvq¹3Mo_¼XÜdm‘y[dF¢öþ4*Ä€;6`ŸÚ ’ÉñËÂF‡\¿¾XoÌÕvÈʧ•9¿Ò¸ð,ÙFOnÜmwÍJ¨ƒÓíU£þ‘ÍÓÔ½Fzß릦Œ÷4‹8v€½3}fCÛûAäE• Õ¤Ñ¦•Fz®PªÅ@âÔKlzk¥y½0bx ô’·Ñ2ȇ’}²ÝÛ%†šciî¨ÄÜeMìùNé'vß6E¢—4gÚ7MäÚÄÙƒ>ÜRÓürÂÔd.Œ“ÿºFãÁ+Shy{Å"š4o¥é©:†i¯% îë¼Æ,…‘3ðsŸ:󇆛eï²pá–ÙÚ­\;` ˜’Ãþˆ>´ô«°)ö¡½ö*=aÏ/ /­ÆñݬœÆdДpeÇûÀÆÍÿÒœQ§7QZšá5+8Ö>¿Û¾víé)‚å¢åUã–þãZ]¿ãÞû¶’Ì|'A826SFÉXÎû©Û;é(¢Ø¤Š£‰‡[·Ì‡ØóÕ7H6ã¨1>‹fšs“–-Ìnä•¿ôÌtÔ[”½1!%3çÜ»:©Õu½;OkÏGgé¾]ÁU²5Å-µ©6ML¥H,õä{f‘mÑ7Ó¨{ØZ·¿y@*ѲïLA›i˜÷ð=ßys¶ƒởÛx–ŒÖdi=®äÈž®7L? ™°ïÆm^ÖEüš™.q™'}AÜdå—‹ÜÙððR5m5a/:6Ýß²¤çìL¢(Ù6Š5l=´i—W²3è½:ò ]°|ëèi"UNo­é›w˜KSƒ£ìlaj4Jï¯nïoÖ>÷Šç××—oµÖáŽÎ½S»Cl#lÊDɹr~q}Çõô´ƒáõüòg `1àR|¯)aš¿$„™–½ærëŒs½^Ñs• 8{=X6ˆs'zü7€ )]9ß Ô0jØ Þ?ÂeAëè8šÝ¼žF“&=.´$Bˆ·”{æß˱ÛÏtq…FÑs/¯.>†ÍÔ±', “ƒ¦A[4ŒÚ ÔÆq¾Q4ª/=žo¤øE½7‚¹ñ0ðHTßöî5Fл‰Æœ™ZAŽdöºé#wd4QÏ÷DÈŠ“sCAtˆ|(´l0xmÐB™k Ìñ1Ž`¦[ÊrCûFµN†Ýü­³Q=/å©%ñ¤"i¾™aNÁw<Éô¾'ëºÜÿÅvíùLæ8]d»$tëÛç|¬Ñ¦»Ú³i^C6®1ew¶ùßm›DæL ]ª ïZ¶u­qSY`¬ÍTŒS-±0ûMíeøRSÁÚ;T Œ#0wþšÞÝmÅËÅ'Y½—À”Ë6†ØúÙ8\œÝÌ_;<–Ï/Rh©íî!{OB߆ö‘7Ú¯ª¦“Öo%¯­YL ¬ò(ºI¨ÆÞ…—‹{U¦žƒ4‹TWît|G³"o¢kÁK¬É¹WSw“=O¯WRʦ¦L sÓКñšQ(’q0%ÞEFQp4dö̘ƒ‘Bâ7ÍâȬ“6b>2Ø-óÍYÍÇûlÜ×¼VrðÅ`_%|.Z`¢¥ãy€DÚú:}u“äi†žÓþFÛgÖ†åŠ{¶'×V×çžÜýD¦wIUÄ€?% Õ ý4L[î‹3Ó.[}gÚwœ6ö©v–­@¤XÇ=͇'Ñý8øéã& ýÕ'Wbn×q3ã. Åù=³6é޶ñ¹Xºê O¸Ê«dÀeÌm» ½‘àÎfž>Æ`£Yõa\:&4BQí»·Ó 䚫ܘ®,¾‘Š¿ÀýŠ­3B1ãÃRV3“äØ Ö†i'?DÌëA#ÀĽÞ‰‰%dHwÛ ïCŠÒ r×aìx¯&6í?wÆêd-1—‹EÞ°qÝŒo6î’všrZ  «Æ(PL Ýÿ$å=ìW-€¡Õf\P²Eh5ܳ·dzèÑù;€DàÓ'ÑB3’µH©ØH›ÑÈÚž´Eiô¢f<ìÝ«¥ÊG »|  ”îŽ^dm ¥$ÇÍèˆJ¼Ä»%©mwòH|Ù }Z üf¹Ÿ?nC\$txŒp-Í1J½ÒÖQã%—ºKr ·0{=“i/šÜ9‹*äüøä[`XO„Ž]¤XçÖd |YBwÙÌz¹»¤Q6~}±n(,ü¼WÐTÔú‚¡­‡9†8 ‘ôz½.2vâGÿËkQä§d½r¬îãÀüB¨¥‘3ŒÌŠVsÚ/æ!¢Îêqeí³a§ZRbnì&eRRw ™#l.w]ÉŽ éDoL½É~P²ýüâÔÅ;’äDkZùñ×D‰*£AauRÛY…ÏjQZÉÁà vy{‘§WˆnKí.%œHký@‡!K‰õí}(aÉÁˆ=~ïð‚nÝù¬JE™ðÊ*ëdðŒ6öÿ qø~¡7ÝTºI?jØë#Aå5Iâ§‹‹Kz.ƒ®ð¼kf‹:¢Qh5°þˆ ž|{ÖË0¨Üºsb™ÐÃÒ‰"ÆÑ´î.›Þ,±•Mžè!éë¹YÌÏ^.Þè[CÀÏñ`G©F‘¦(`àEZŠ5~˜Ý½ÙÞÒDtðùgAÚ9} Šëb~ƒ’‡¨e Ø`r|ðäI]Ê>Ô´YÜ€$pðC£0‘ ©A€A"=¼-ý·Ý÷‹ÕõOƒZy e'Ð9,’¯Ý¹¼¡¥].›M#ltK¾œ—ãà6N#&Ã,ñ÷Û‘ŒèÓ ÿ6ÿÖv¦ŽŸÈM_ÜòÕK_½ö¿LH}\lÄ]ÿÉåå- {õ¿+Å_ÿ³Ï~¸Ø\BæÏ)Wbr%Ÿÿ8ùØiêý4™áª­]®ÎCAIúÒÕt#Š&6¬°ŒÙx<| 2#¦®®ßÞ ‹‚¤Ï'Ù¸}é5דéu<‰ws½BkÝY2¿ÇBëúµ¸yµ8{¬nòzl¯ÍÙ…ø”@Ôñ“WÈè³,çx}õf—ºÁÉW¤#xäN«à+­ß«¥~½~±çÄ×z•Ô “‚´?„‰SW—sq¿œœ­ðv3ùzúB“½JQ`ƒ~g®7ÞŸœ.:¾i‹»úyÕ¿¹2O§ï ä!©ãÍüf³÷lo°H“Á ‚ÿ+ø¿À£­ø:/ü¿H÷~ JaBÞÆ .2û?*§ž¾ƒ“õË‹|(Õó7T稽ô±§>örAÏ ø¢†Öpwñjó&ŒXƒ¦Sý³4×z^¾½~¹X&ŸñX"^¬–zë-5“õéÂyìsÔá¢øêsÔ÷+„Åäì@£šp¼ŽYý1úÀŽù׃ÇÏ¡>­-ГìY†Oÿq̆øÕ":€€).¾mOIx-ïjÔõrsãÓñº²$÷GKG/È@‹—0˜1þÆ3Óç‡7žÎøƒÿ|ð=¾™“'ººF6é£Ï_øSÐ÷ÁѺÃí…s ⨋ ÄêE0›Aø6u¯ƒº×ͺ×qÝA‰Õ:¨{më¾F0ƒ3`nYi#®#Ê|qe«~q~ ¾®ƒ¬ë0-Ìza¿\®èvGêÁ×Óðt "äôæâÚÛËWfB—·æËëçæË©Ífæèó‹ ’´m¢"¨ & b~^¼J¹§{\”ucœ¡øæŒÞCðÙž“,Ï6¾Ÿú˜#|f ÐÅÖíR.ço7t¤ùNr¯Ä\Ãwä(z¥þ´ˆD/˯,=-¯Qt2MHÌôv3ÃC¨Í”¯çA,^“9[ݼ<|Ÿ¹gÑ ÏœÝ—™ocã£{í'÷â­G÷¼ªg÷‹voǯ‡ÚNæd ¾^«Ó+¿ÅÅ+½OTÐQI¡¾•6<Û—4ò±±syjomRÛ¤œ ÌŒW>¬™0²¡Ü–°evk±ï<6ÈwþèÝ®ñ!B@e°šîÉžw2&lwâ*|%q¯ ì=ôß÷wy%‰_B‰vzdëž;Â"¡©èåúõHžÂ¯I,œ%›6Ôˆ#ÑÞN"¦¤nN ³%ü*# ±ó0Óü-»‡Ü%§áyÎWEj· =JpOˆ,@ ‘,ã#T†È´í6È|‡JošoíÎ[·½ ½Ã¯ªý˜Ø\ó7j´ö>¥Þe×î˜Xw›öLJ Ie ÈÎå•ß>áªYA”›T{óúysÚ(u”j‘°©ÛH|лmòŠ?„&îõk%‰4©’B P+ѰÔßó@nký”8©<€„¾§Pá†Ï—«cêµÜ¸ÐkŠâòäï…v‡èx‘Àé&ë¸*u—t'â‘bWdö Λ5›”7WQƒà ý°º¾ÛlÖfôï/¦¤%·®˜‹G²­¸Î÷‰¿ª[ªÀç`‡ÙÔ±Ù„8ÞKn3¡É‘‘ìfRÏ£NDH FFw¢Ãâ¶2(¾âè´Z<Ûäù=Ço@´ änêÙA<†vÜ€ºØîí$ ¡ˆ˜ :;$ýéœâÎSœ?DS|í§øH§8Öè§øõçè&1?÷×Ö5{ÿnÆ6gl×Dý€ ˆ$…å¨ ¿lÝZòÒ¸Žáé×m@]ƒ¨é„Aý '§kð[<ëh^\µÜD¹;¦#v&ã+úMEÅJgá4}Ïf®/nwLþý¼$q†/¢¯Þ~wê…¯G{±Ø0œóL#eO¶OÕÒis€¸rÊ\:¬¬ŽÅ˜LQœ"^¹ŒŽÞaXX¬LŇ%lñ·\\Fº‘ÿ÷˜Åæn§Ah¾¯1Éæ»â|žSÓ…%ØiíÚu xïÖ»ëwè ä}×>B‘‡v²F=U œaŸa|ÏækþÏØ‰/TÑIÂE®3N“‚²hv“LêCÐþøÐøiâOçnN~#ÑW Y^^ÀMym +tû©ßóú·$¯ÐÅÊÍ’ã×ü—˜×¿Ü!±ßÒê+&oí–Z½3³äcõ[~ëæ&ÿ—k%çYeÜk(wrÊ]íŒRç·”õÌ)£v¦/°oõÛì¡`ʳ&×/•b’ëc–v_ÚKØ+ ×Ò1‡Žëá‚ÑÞÃÙŽ¾òJÂñ»vvýa]ßßÙõC:{¼£³ë¨³Çš0}@g¹Ÿ³Ä¦¦ÿÇ¿pïÒ÷鎾?ú>Õ„?'.ë;kgîŸîéû°üôç®G_{éÿŽlV·žüÖü‹¶!-‚ª‘|ÿª5ŸÞÖdýÓ[Ÿ—_Š}µ‡úÓßÚœübx”³Ñ¦Ã½mòPÖiWñkßÃ?ýsÿù?g¤_$D<Ü€5Írh¾;#G;E¥Z:ܳíòÒ-}vVµz®_®^ÓÞ ½üÍkÙ§ºô²$àî>•–^FßͺÐ{ö_iCKU¯]lIü”Xj¡º¾ãÔFWÔy.* ÿ 5yöÑñ´ñ\06[ßv÷®r ,3θR°pÇø)ž$bRWk˜7Ù[*Ül:+gµ¡ °¡Ù ˆ¸Ç…×nù¹†Á+`´¥Å, Ù Ýå¸tü ·¿|özZ‡;n^Xe¾äê ÖÖ;g-Ã…hë<Ù„bà€üÇ+5®Ì:(ôòÕé5Èñ‡F"Î8_ÀLC,‰=Að´Žð´¶x⬦֭˜Z߇)©© Wki”˜¾Ñ,w·¥[¶Pˆ/Ù2ǰ9+ô]xVZeäèhY|Hëä‹a¨ pþ€ö8=ò‰ú°¥*@„±ºyÏ×ßÌYñc@ë¿E4ñá2 T({Uü‘q‚7mKE+®ÿnîì˜;m cÑêúMŒþ-¦¼IT4®pÞzCSp´´àû8ƒ{çJùbŽqb´y*ü7Îdh°3´omëHë±å¢ÙÌ0„¹B[Sûù—îÝÏU½›7{7‰ ~óå’ö¯ÅeÙ;=Úµ$±GåVo–¹ck™½ AqøCÛñÉM¶-^‹´QƒfÅÀáÕ83îÎVè=[mÎóMQ¥{~â÷¦þzÐÊfu}½8c Øg›ôF9rŸD=>, £Ös×7‹¢~¸‚6|m=Ôâ>¡×“¨§¬x÷¦I\ÒÞ´òδRIÖ(íîÚíªƒÝn¥|{鬥¼Ú®ðÜ’Ânk=iC\=l›NÝm„tâ ZÑ›8”8l:Þ×3%JŽpÞÃãõaU Œ9»å®Â"BágHâ®~§—‹ùÄZºèÅzñ$ôGÑÇ3[(’|Üô É.Z4x …™Zˆ(¹q¹~|n²uèÂs ¸ƒÆ»rß!×.Û–êe2ø¤Àdp òu2˜%ƒçÉ`Êþ&]ÛÜÑÞìŽ]Þ6×ñò_¨Á7ÉGǹ† ¦Ïñ¾Oþ8m$žƒ““B§y®’mDœ&iʼL¶C“ƒ^Hùú9»K³j8rîäjññbYjºþùgxF€N–~ù£åÅ|GãDú0›Ö|O‘=qâ_È‘ÔÞD¥È?4#—žÞ¯›„ãÍ×têñýÆf¹íÑnñÈl^Ë2ãä—Á×ä*`K"yÉUÜß‹6g¢ÝÝÀ±ñŒŽ™è£ÎúÇß3‚#àÀÛÓùåb³Yøq³Å¾½æ —ûäÛÕò)jZÀì`¨YÆt;¹Þ‹cHžÉ‹ô~eð‚ç=OkÊk”ïø”uø=}Cÿ ÷õÌï½CCø¯œÏ)è î|“CHºóâdlßÓÀO®½Ë–,n_ÔŸ¶V9…Ly#“%x\VVËË·4’4›|ÚÑø‡-Pc‘ûžwë:8~Šº’ï§ImŽ‹ÿù °;—cÛÉwr¶iýxï3«ëûSâZAtJ<äÅ wçxH¼ú¥‰s'³a´jÐq¨Ö#i\ 8„vÊF’ð Ø»ðjÖÝrÖˆ-Àì›+²~)ê…KƺRϺ\D§þ^H%'?UâÁC›ƒ„æxÑe;ÓQÉEzP©ý3VT7?ô"@™6{.q‰ÔE^Šdù¯Žt_Ë1(ƒr²N#ó|hóäe.yðRɪÕçQõUjѨ\ñ.åÐóØ4Y¾Ù/Ð÷Ïœp£«•5üê$n©ÁÛ%Ÿ`Zj <,U( fú+Ðùð[å¸öçëÇòÄôPOKð%óö¬œÜª#—<Òõ9Xôå%—åòURºòä·T_h(ÏѺƶý­ÀT™mæž4ù `tÜì¥1„nÛÎqðìïñ‘3>Šæ7˜³r|ºŒOI†DWñøXa{›ïrœ0<(’&ÍÃæ†ïLÏBÉÀÛŽUÎ:fÍÃíõã}bá”ǽ‡õ Å;K,ÌÉJƒøD©?ý=²§>¢*2‚#I‡_FCü×zšÑƒÂ'ž‚ïጂv-ØÁ¹×$è”ï¨ÍŒø‹bWö0·”èn KZJ>DôY¿¤KDN&Oê$ÛOï¹/§NŽ9?^’ƒµD·ä¤m·ädù  Æ£{nɽ³d¬­á3¿‘d„üó>é(ÀCzŒäïj³ÅI)H8#œïõ¾Y¬_&¶wézóÑÜð¹•f¥ljŠBÒX²½ç¨~p뺻ô>NmóÿT.ÏâoÿÌXöYÁŽS¯wPDËËÅ‚“Cî²»,Ø€Œ¯`žÔ˜tD8¡Ãg1“8ÝY—‚ëî_Òn£¡Ùó­Æ5zÏ !‚pãu¬g¤ær…¦ÑÆÖ_‚h;Ä^ñr[âÄÞ|Ù¬ü-ÛNwtç¾^‡YáŸÜA~r¾8)Ò,ÝÏÒŠn¸ˆX_­V›—ËÅZ_^vôî§iJ®Ó>§Ôûõû¯äê:ó&Ñù‚î,Yßœª•#¾Q²ñ¤­-ú8Ut/\\Ó•¸Ðy‘ÆÀ0ñ5¹;öñbÝrÉ­6¢7Ïu¼Ðë wúìÒ3~á“þÿ¤ý%L‡›=në²ïóÃn–µd™™{ŠšäÚækÞ*9§å‚Z$v“5’ô¨:L˜]ÎÏ%Ž”tàÁkÊ…—›ÇWÎ`üµ¿f °½Q§|{âÚ]j³Þ´DñHûŠ6+ÌGÎ'¾6;¨º’R3¸m;È`u}¨rériI bfcJCÛºæ Ð4CàĽµ’¡¿$ßÜ;îo¬wÈ ÐE⊢¨׺íàÒ´®RoÞC½µˆ±y“ìÎS¦ï¶Òƒ™üšvsv=TeUÍ&3œ:²eˆw.ß>ÇûÃÛïÜXjm[ªéôjI§7¸¦Ö»µ¬iv+2 \Ãqõá&Z›tѤÍöw3ka}6‹HK ¼yY“è¡Ún¾ou’ ßäÓ²F6äÓóF:`ið í-ùŒE#£¥{Û= Že®>‚½ÃQîäGÜÏP%òö`nm ÷žFd<Âqˆ^[o°8rMþ¦à‘ðpøÆSÒç,•³ø!\ÿ¬‰ŽîBbêò‘æ’…8ín{²z³ý6{']™¥1nO_ÝXÇE¾Ù‹ü»ý%bøùNÓ\=綈¬ÿG;vcø9ƒËÕy_vfŽ›Ûë¾ßÀ‹ËɨЦ»+N€G›ÅÝèËŽRQ*,§ ! Ÿ·øÙJºb¸u#Âz[ìÈÐzÃnûMÆ“_}sËÓnÆÙ*'OâJÃçjv5o7Be{ÖÏðvÞ#»8[Üôw»ÕôÍG*‰£K弡õ&ë{)õÉÓË[HúÕÍêöúÉòŪ/»kOç¹—ß-ŸâÅ9Ó›Û52‹Õåã$Ì I\ &Þllîm@Þîú}EïU÷ˆØø.âõˋӶê[Ò];]ew68»œKpuÐW÷wgÉãSBe”a’«¼¥ÄîÞ^=_]^¬¯|Å&ƾ"` @,>[»jø«ìë‹W¹»²Ã);~h)öh L`umÐèbp§äÏç7×]Õ"t(9VŽo/ÐÁRµ¼¸Ö5F7röÛ½-wLœ<™.M²r‘/“Ï»Ä÷Î’s‰zÜoFÁRT&Ó³þ³þ¿è§e* £Ì”oVønUV&tVWüPh©ú~ÜB:4¡èšÞ@ÿ=àØúÃ2M¦‡Óƒét:™Ž§õt4­¦åt8-¦ù4Ì&G“ÃÉÁd:ÁŸñ¤žŒ&Õ¤œ 'Å$Ÿd“t<A8Œ§ãÉxÜ×ãѸ‚Pއãbœ³q:NëY}TÔÓj¨Çu]êª.! ë¢Îë B:šŽF‡FÓ´3êѨ?ªQ9B(F9„ °;ƒpTB8¨àj-B¶ Êj¡¨r!áˆÂayØ/Jèa ½(Hj/¡T‰?C„BGmáÂ!„ Ðÿ!toXcè 8ltHå‡üSPÈ%è°Ï\82áЖƒÌ„B|ÃP¸ÐŒš@1ýF4‡’Bü݆ŠB#¾o}hŒÃHB#¥ï’4ÔAhÆabC_>L%DÉaÚhXÒöŸìÁ!úéªð½«ì·÷*Mè·þÀŸ~¤@Ã2;øàphC?üúááãUxÄ¡¯>VøÈÒ° 3à{pÂ8ãX娿ØÌ!0ÓY™Z]XmlwHL¸†\kž›>ž}T΀gràëCàÕU˜}Ë °þ)°CX`Q€e-ƒ%¢ Ž\Š0‚5$XM¦À?pu9Íê”VœÖdà%¬E£>,I5,M¸@M‰ÁÂ’5«g°|erXÌ àù%-nXg=ÆŸ ¬{S`>‡p%œMRÙ$ëÃY@ÀÅ› —4¬–Ñ1-§°âË9„pa6™MS„œB06¥«?¥¥Vè¬Ó¨é)Õ3ÕåW‡.™0ó†(¯£0Þ&;Üϧ;ÂÁ½á0ýf„£‡YúÍ(Šô]C?ŠÈ>,À° “ÏN¦7¸Ü€|…ÂS0ލ,v„‰„qX¾/TÔÊÆ®@Æqqè0ùªÆA¨w ŠTØUô~y>ª¬­Ë¡ðÉù¼Æk'¦)H]é!„£tF‹M–å0BC «ld Ó| 2Ùav”Íò4ÏòD½ÏM¥ Rt©è"/ ËxX1*jà'˜à ô3=»la–žAö…;6ùcμQX£aŒ†-z¦èb_8b®¼PáT™ ±Àܱ?f}a{GÄîrâtÌåê>1¸)±¶#bjÈÐUÄ»ÆÄ¯ˆ71rÖËÄ(r£ÌðÓ>@è/ ÃHB%¡ìSÑáQѺø äQŠAÖÛ# ‡‡ýÃÇQ'ç‚G*†&XéÙW†¡Ï4ÒÈ‘ ‡Ídð“@ò…‘ê‹XJâ^´Ï­NHOQp=(Ô ý{2Œß5ô;&ïúQÄôCC_>Ëf)KG@c°:O@~¨‰Š™t‘S"ÂC¢¾ ÑÒYIT…””ÌúB%L5)W%)~8äéN ?‹t|Òðû-*¾SðE¿7Ú=éö‡¢Ý{Ý^5{Ðëû¤Ø³ZOJ½hô…ÓæD“G=¾&=¾>#ý5÷RÚIaï“¶>$==# ýˆtó)éå5)ã%©àùU„l„IG˜v„ƒ8ôåÃaG8ê³ö§}X?ÚBÖº~ }ÿ‘°#”¡ŠC_>Œ:B HZ1Fû"eDÌ‚bÚŽ‚3z8˜µ #*JZ¨ýg á7}÷qhËcMÔûŸð[&*)üôåK˜À1¡n>3AV (zi®ßÉÆîó„œ&N-F04g‘˜™À€qˆí‹-_uÃòåì^}cö: ©5³×ˆ&ØÈÙ¹†8É €#V-\éÐà4EýÕ&vF}y$2¯‘m rÂ2ÈÍ"€ã*|Hª* ¨WŒ‰ À*¢K¤Ù)½OÑ:šbJRº;Ò¨ÜÈú¥A1ˆ'¤÷ï‘MhfÙ°&¼£dÈ2!Ò€—CieAœ$’ˆ"`IŠ~‡}’ûPêc™%>–÷PÚCe˜E=óPÈc¸Å»™ˆv(ØÕ}QuAª D:èXœCaŽE9äIsU1Ž„8X @‚ë‹—‘6ª" p(¾ÍÈYµ¯& Û–¢£ƒ`3ƒõ©€uª„õjthuýÖ1”Ÿ¦(TáÊXhÛ@úgöT "Š“ºL°?G&XCIj‚aÀ}®½Eàd‘SCiB„‘ €Î¾“BÇ&LL°x ÛYÐÜOþ[ŠåñªaW†&À¼ïÏJ • "Ü]; ùHjç¨#;ÇÚ9ÈÒ‘ͨ¡ƒÍJÞÎZ9¼ÃÛ7J¢ªJÌjÒ˜:3* @j)ÁÕÐÍÖj5)×Îþ;% ùÈ 1¥E&'ñ{(YõIb¯I†'Z$ sÄè¨&tÕ?ÆndyyÔÜñˆþgÛô?P,‹¥²þ‡Še±TÖÿP±,–Êú»Ä2Ú 9¢•bJ«DM DI . )-‡´ð20êÓÀüŸYÿ‘0}`øVä=+%eª)Çc`GÀ㟱ÿ"q7æû‡wcÝ༉ÂÝïÆw€í¾¬¸Ûºb˜8ÔXIpÆ0ù{Ù¨IŠÅ0ÐTúžª}ÈR1‰ˆ^€U Tm’1âÀz3]^ðÛTЪ2 é€L+f´Ì¦´Ôæ´+Çût•Ø¥kgn™:“ Îx² õIb±eHk2‰W´2{3 ‡C GbáÀRs!†k}²Ðp &ˈ=zp8t{iÑ1Zõ‘÷{ÚLŠý{Œ„j°Ûe¶«ìÆ»ÝpF!Þ/ZwÅíy¨ÐÉ("„Ýv›ÜªÝF7»'ÑŒnÅ;™Ýt'âÈYÝŠþûÞdLo¼äö#Ó[Ñe|“%µÅt䤸ƒPŽë;AŽ…7Þ¥õ»0~ÕÜ<ÕxS‹ˆœÍmºÊF_ü &âm ¡–0r¡r¡ta(¡p!ï»í ¯IzÂUk’Û]ð¶5ÙeaHúôÇÿÔ.Œ$T.”. ](\=•¾Ñkiêbö„tW¸ÇèJÿàhG8ÜZú-²;ìÞj7Xî·lç#€ºÕ% #ôN*ø¾é÷+-Oã:Ð=̧.ÉË·:Œ¥scâYGLYƒß‡(ÉJF0HBGD‘‰5i懤礃£>F­›ômð€ëŽj”òâ­ô|gØý#ÃßÊ{BÕúîãhg¨w#BªCÃO‡âô þ©)¨ˆÂ"¹‘¸yu(®1f¸a3s|&¾29ùËâ3Ã~3%‰­‰®ø‡e¢‰8Ó@è‹OÍð)¶˜é® 뙳AåâmSˆÔT:{”úÞŒÐÏ´¦¾ïðK}/ëH¿Ë<Ò¢¥?È6Òo7޼¿mI=µÖ™ý꜠æhuPP£´:)d¤e«ÂÈèØSvY8d×qgÉÅua(Ä­TÊzöÔiÚGNÓÎH³bÝ ´«~ l£’E*–Q°¼z¥ºU¨Yy½ µª¼Q9/T¥2"L$ıèOhçF BŠ“Τ6nÔ–PWBã$¨I¨$õÅA5$ÔX;b݈5#Õ‹¬uWZ±¡Z}`Ô¡Éß ýΓgΚ2SªFD¢•øMdLÊÕwšèuFôz@›ý§Ç4)GĆ}"^õ¡ÎHg“ö¡xRoêÚm'©Wµn*¹Á¾ÙLyŸ© 7àfUàgïãMðvöþ3¤LËIêrÔüÏPýH2qß8"kîìš×$‰ÿ3¨Ýœ(C‹ .¾lÄ´VèsÇÁT ‚¬ŸÖÄkHÃNƒŠ#ò™1q&gݔޑÖ4d8`rVd´SÄíPC¸É”Ù+qaç½»#â#HCÈDÐQ ¡Í¹¾ðd(¾ç´+縉ç'cš¿ÊSdŽìÓ> 2ºëÆö¿Âl´º 6¿µVè.§]?Ô¯!¶ÜþýÝ è¼-l%aG(;BËOŸ~:BÝÆì7ýjÒÓŽÐq¦  <¯úæËQk˜µ‡.ÏÂþ(ë]®F˜cé¼}=ž9§AöÏ(Ž¢_Û©Ø»ÌBL„}gÏôMoÓT«¦·kªesb¬Ûjݤå·¸]«c¡·rz;§®ÇÞÖ©ÖNoïôÅäÙí€ÆØ"8²Àz_ƒ4Øœ¯Ù :1Ž×~3²0þÖ¼ 9 M?#6’àò‡Æ ÀcÂ< •yÖñK¶àd˜“´ùñxÓÞ>¤6F L-ò1Y`Ü}d3J÷‡%æ@t‹¥Ø/F©1†|@l╳áhá1ÐV,Ä4*m `\ÖêúïRÏ.³È»P¤3’”BGD嬮7šdÅã~šLú·Òä_BËH²äu2L¾Ižý”&gûã÷ý/†y5Ú/˜\Õ>ÒvrqY=܇eÎÄ~ijý|#ÿµ)ßçK/ Œïú|™G&—zü8«­÷«bìA€¶âèÖ•#Ë}PÛ1n´ËÊHâ`‚d‰bErÐçè1¨ô\&h÷Aûºÿ‚âGûY1’ô(j6*Bôx'¶Ô- ëœsËa&ÑÕ~Yæ9简Å%œ·yÑ´ ‘D¢G€®p¦” K™d…u5ãJÓ<-“Vp¤ãý¢¨àX÷cŒ†»b$ÑÀÖÎ[ã_Ôâ•㤠íP± Ñ©âa<Õ’7YMS޵Ò† Xø~óà•ûèáCat•;¢cT£Ëqu™k$tƒê­`FÆfãRŠ×ð]²fÃј#«¡+5ïá +V°†U.±Y>’*J4îr¬  Gæ9P¬VdͧJël(Œë\#OY•®ü0«$¹‰æ,´ý˜_;^¨[f] yæ9ÓÆf0%1P“VTE6Ú\ÅYÓ”(,Ϫ}àãcÎ9*ˆÂ8ºä1·¬!Ï Dsš—˜dA© çUÂùÊQVp$äJ­Ã}PXP깂á.9ï”_ŠÌ÷kž ‰3+ÈŠ†;.¤- V¹Ò,Y¤Y- âÔòˆdn‰ƒã†i&•¦Ð4Ffà sF.   Dv8.ˆØR¨j\HÞQ•YŽÆÂIÐÐ*Ý/ J(" úŠtLý¤§5×ZzÓ¡D3!‹tp—7F|š#Sf-h™•Dˆ˜Ú\¾„ÉGÔ±ÄxX«ý“Yr ¾–ÜuAK¸Ik·,r]*rG ¼fÇ¥0 ¨7•ëu]ƒb ß«/x¼³Ô­ŽÀz‘¸Àž°ÞhER¼ Kr¦£Z"SB%!UtU¥â{ µ)ºÜúâ°â0êçÈ #µ}˜S—væ¬ M1æ¹5„©ãE,þTøÀhÈ‚G„ÈÀ"Ï×2àЗB"G)ó®ô@ØP^×K̘#«4"¨qnIÎ*Úå¶tìMÈ*HÓ|,y!—ôªY 9+æÐØUP]ÃóGBKåÀMëqÁ¹ñ¸RÂ̘8c¶käxTJ2G‰,«©æ-³t$yA/)Âq¸‘k ¥ÕRY,HAcMFÂI ®f:¦¹Èó+sK=F:1/&sqTÊTÀÜ©¹7ÞɶZ¥+nµpk?øjxUE¸ñyQŽcÂ^«qô¦Ü ® “•™ðýîp a=`úO{6ï/ü®s'–4ð¬åæP©w;×:@g±haxN“)gþ½œ´5ÓéHWI~”ªè3¤•dؤo‹³ù+ô3:~«Åüö½3¨ÜP8 Ùµ¯rÍxQã纛#fë÷Tņ…÷Ý;óO‹5Ú nÊ.ÝȆ¹ÑoªIÖü=w…_‡ð‡§D3Ñ©¿©ÉÏ|àÜ ¯lÞ4éØ5¡Åv€ßéöEúilæ°òŸ›¿Æläg¹tE:qØ[ܪ5øÃ*#7å‚éoæç geÈž[¾@ˆxÚZnW¤2=»nìÖ&ýqTR†œA梢#ßÄ­ÑìGŒÄ„¥Èñt¡¼QãY¸¿Ø@a¨ÞÂ’p™Ï‚»»…}’m•ud¿àU†7jZ&‡Ü‰ðMó9Sucüw^ sv¾iD@³XÜhÐ?µõ{:ç±Îêˆs1ÜÇpéZÊÁL8  %vóøv„&<ÄFƒs-†¨F ¿ß°C¨BhIœtD n[?Ìi 3ôøL½ozB.>1PWý#l®ˆV íä«ÎãeÞÀ3Fu²§)ßròtyà·qZh`[Ì4CZdr×Éçgx:äPedåìÄl‡BpöŘճû¡Joyf#‹ó•öàIšVD‹N·ÊEX"_)~þìÔ´ wx8’j ÓýŒZ†‘Væâ°±Ž0GÂÚ,¹8=ÁzKô¹.«!ÕRbâp5M‘Quó úåÍy™|üÌ Ó5Û‰ÓÜÍY/ß—‰S-'êËÏv}–nüÞ|wŧ¥ZÞ‡_þlxúÍ!°\Y0ášBÞEuMÛqÙgå0·Ýª¡'E´Í °–\º3’§bLÓ83¦7Æé'c5eî¡®¸ö#4öߨo&ÄõjË21®rbŽ6¯°®Ì+ž¾T08wnJt>}ÍSÛÆà¡kšÍ,È ó¸lDRÒ±ž)Üôj{t2Ö€…/æàñ Œg_åÅwU¬f™5ð)x`9¦àéA§:´"ÂjBË襣ÁLè×Bä:˜øH³–+/„<]-yÌu¤ˆé1¡+Vh’‹}¾#p•»,͸©qOO®k…›È=a±¥?Tó-lƵ©Í¦¼Æ'ãÕ®œ÷(ùÐÜ‚î ·AŽà«­q'Û^Ó·>õß>î¯þ?+í‰Õïúï;Ýp[5'Ïz“¬ã…ÕQ ¶ß–rQ¡!Çöcz'óöÒdÂ=¹-õ‹ Äâ±q‚ŸØ^!{kùŠ2!¢ØvŸ… e§‚¥hѺ#€cârLŒm@™ȱ¨Ðho¤0v=zW7^†LëAFtïË$ü Çɳtà{1o7ïLG'~µÄ%­…>X“2¾‘~d9QÚ°}¤3‚†–¼Ù›k8Ï›ìe[Å; Òš+4Î6Ë|p-·úíë'ãÒÜ>:tõ•ÿÜ_ÏÿÆ-ŒëÈ÷õ#ÝM—jUöÞW>ç8úè¢?évØ#óý…ß{bBøBzÜö®8„ª¥Žû}™§iþm^^““·ëwþõ±Û&ß­ëÀnL+¡MÚ¨–Á"¤À=Çò­#f…C˜ó¶èzr~ä`–hÀ\Ç¡›øò'g©›°Pè:ƒ¢ö‘àg+áÅ¢´šjþ¹Ì°ÿ§5„4^›ò]+‘Ti¼ý¹°c"ê¹cÌ‹ûÑrÜF“ëÀ?‚fîóOKÚŸé#½@ˆ4‹Gsï÷37ÆöÑ$#gç¢Iæ;È4³SbFÚ[QäÒÔÅVŠ=áʶ‰sœ¬¥1Ü`qùg}@ˆ•24­]Üù²°ì÷mA61*ö¦R7´-?GÓ¿mý+·QÑ`ºMAZ‰DX­W ¦]éîKò< Oc° ¼ëÆ{ý|~ÙÁpþ‰Yv­4ĸDwBÀܦ¸Àe÷I㦠×%Åð\–Z¸ +'C»þ²œpˆåÌÍâ!½Å4aËooLW›‘¹Yt9›ã©%šV…€JÛE™/H&èȶ†±.Ú¤–yS'¢bî™û…ß?k¦0.–˜ySbz–ð`Š« Ô<9QtèUEóT,µÊ~†`犨­U'b©gjŽ&Þrža«y€§»rš,¶8˜»kâÈb÷¸*²ûr7 |¿œLN3»!žKȇþÊÉÊ fU…¯¬lÆüêŠÜ a?VY7ó@A¬ÈJ~ěР#+á2“>Û%«Îû}r]‘¢™“;áÙgß|Zþ•ù¶A¯ži‚ðÚŽ«Þ²_°¿<ÒqöˆphM&. Ûñv>Fö )&¬1*ÝjD:…ظ=Ü J ÏÊ=–#õ,ôÖ™(‹[¾_ÑKŸ '¸‰™)<˜}d3±d—-®)шßb³Ã ÷Öh8˜üÈ…Uò¼?Ò=?jU­î¾@Yk>já£Lvæ\Â1`9ðÀÌ4&Ó,Fµ}À÷{r!.Þ='ŸÔ1Þ‘cZ®¡bÑÂÊYAÒ§lPAG(Ø¿ >WV@ó¾ì /³³Ì­€G¿ƒ˲>c`rÛ-ÿ9%¶Z³òƈ‹l†Öþ ù-²°LŒ”Is%EÐØt}ø¬Ffj_½<œn*Åj[ñ FøŒýÊ—…‘üjˆÈ]æ°èB˜9LÓµX~B™±ß鯷F‘–=%d‘Tb¢Õ(KcÐW ûèé(s ´LË B`Æ”k¨–è'®5VÃô*ÄS9lcÄôŽm¦ÓŒÑôHúO,9óC3ï.N¿´¯Çç/ÿC‹ÿ Eu›!ÕglŸ³n×KüöQlÉ$ùûPV÷Bv~þgtåuaÝ”¡g¾}êÓŠ8+<³ð-›Ðí»pí ÇÌJÓÄä™.gn¤Œg½Ê)žíîZ5a;Ï&­À=n~¦&ÛæŠ`ß°:†Â*¨Ñ⯛ªRÆVž¡çÚ¢8Ñ~b4³ êfbFÈ»|=c)¸=œ¸§Á2NF×ÛÚbƧyÞÕl«ÌcVî’‰Gx<íéž&F!5&6Ö¾8¶¸­‰‹ÅÅ"ïÜeÈ„x¶]Ô¢y£ð”´Ègþ‰)ÏLEÝqØ£½Ò>ƒìAÖæØ*€×ÛÆàâBe†˜„Ÿ× —iK£ÒlÿXtŪu1;}!aÂÄ;´GæìJŒ:9K±®þ½VŠÇ¿BY6§_eIœ{bÂÅ™¦Ö?¹ð.µ.êYhÝ{˜‚£Xè^hÒO¬ÍÉTêÅ5&ëH˰DÔµÏë586°µ¹ðû^óY˜!dƒ¨9(ÔhmÝ—^1ÞpÆ{ìM“ØS¦ç¨S“ÈêT‹¸MNbÓûk¤ãû*ˆ¬Sû¨‘Î*PzuO“ãÉ»“bi*Ô3þü™KÌ”k'o»ï f5<&´Zy, ™ÙǶ´˜J|ÖvZXñ¡V¹²,û&*[Ÿ!äü·Lc FtÖ*‹Ã|”¸L`½{ÑÀž?^.ë³Þ?à;ÅMÃÕÃÅí{ŽÙU¥¯õÇñõ³W«Gøyÿ„\7dG¢êRfEd~ž wF¢Bk*™!» ì¼}Ë æjÒÂÌ'Gæ™)V)òË8HW‹2o$¸w†Í2+ ©d×*5ÖDªÂ %áék¦rèøûV¯§\˜Å >×3?r‰ZÊ„¬ÿMÜN^•ÅÜE#¦ ½â †*¯–ÎòL„Ĩ€²tŒÍr-'“i Þ}™%ÌÞh¬´aòÉ;Ä£0ý¥¬ðÀýIÆ«3“cGcÖ]&žœá]°Ÿ#ãìëû¹¬–òsK¸pÞáôz.,X±†R…°Û:AÌHübüÍkP»Êb>6Ë÷ÈYŒý˜ßwâ5V¢PYÛƒz[O×[Zr¨ûòªÃ¥%ÄŽyLo×q‰),ó…0ßBµ› ÛE¹¡/ûÅJ¤Å _¿Œ%é“—{¿?ÙÄ#1=N5bîG­"~BÕðù³cR[À„¨ÙüÐÀ§p6̽½áaºwÖ°åB{b3®iY‘‚GØvE=C¾€í  &Fõjæ­kBæ‘ä3§`.›m¸Õ«Ø²ÕE,uŒ*há6ðædv²° ÙBåD¿üç(m«Q«ò±[Uñ{ËLñL÷wªˆ?ªóJdk‡°ö©ªC60T]dvõ(Ù“êûuzjþ*¤š>«nÌ›‰…3ðü†©ù&Þ|:TÖh‚è}ÙîÏóÂ4ˆu`·ì¿ðBÔø6$™Ã¯¬>£‘ÿµÝs.±VÞ1Ð<]¼3èMG¤¡D Ë‘øåúÃ^58Ìd±WE”ÂëW~¼ìÔéí©ªökøýníg«1ºuŸ§7ëÅQðá÷ /ˆ„zï¯oãIc…ágmòâIÃ;°ÉCX;GÞ¥ª†EÕ-'~jÅÑ #¶—¹D"—¡[ÖÊ_œ3èVÄ_7aêP›D¤ð­­Â¸²äž•OW!öÄ>"—»÷9+Q Õï¯ð40X' êÓ¼;ŽOOÑ`ÌËjQ9Éc™çï.ú¬gѰB‡8óp¥g%¢m+Ê„H·˜zYÑÕkOjš—¯3DÊÍÐi\…6.•GT3³µ±RIˆö²ÂìM 1'4º Ï„b¬‘ÑbbD¼¬ ¦³6e¡Á„eñU:$Í—¥ÖÕ› iš€Ja")yDm) f„êa]a³œr[ZˆÐ€‡tUOebIÆ<*ñ,“7L·å¡O9’3Í;ŽJz[[•K`ðS‹©I\.gX˜.Žtô_ ~ò’°ü×uU›Âdµ@Õ“y×qµ&—Š51Ç© BÖ†½†~)Ûƒ+r_l­l iS…W””óIÓlôÉÙ—"ûØ o™çk¸nÆ%kžõS•EÙ™&ä‰Ú5&QL†Æž_JÓª…†Õ©œµ/Ìä–òð­NË8êàÊEzhÑY¼+áÛg³§À¬*<¼ «//øsá …¿^ÊêÎðzÈym–C†êàɬÒ; /¼ýX—dõãQdIž€’ðhÿ€s ª•yôŸª·7ü=9ÛÐ í¼K©•12ŽA-vsÏm˜½Ed·v¦çØ“µf]È—´w¥Éë ½*ÏÖkøwB{ÙjYÇÇÛìAÏ;ž+¨Q^½YÎõôñÖd¹Qa°À&ÜÒ ™4d^ ÎC$Û„)1Ü$*]åG>³/.Ì—¸š±ºÂßÿµ¼éO·¯S±DÞPù(d@“ÞôOÚ Ç¹œ¨d­òäÛ¨§™Ùj4že)–moÎK>ÁO%â$Ì[ò¿m})p¾YÑÂ=¦ðE`ÅÓ¡+…s ÿLŸö,Ë#ˆ-`²MW†CxáM€ÍJarÓRÏQ ¡»¤ßavù˜Ka„ÏÚ/ô2ñlÈ÷ :ÕSj¸™^1b;fÕ9¾PP!†þcqð¥ø}T Xˆõµ_,,ÜŠ{6,Ž&礩¢æãÓ¸X’Bº&¬”µÐ¡¾6{ŒfºjÌ¡Œæ"­õؼ-²-6ßu[R“³”« $&NÄ€ªr ØáºUË:’¶o…a^ûŠ'×Qð:SмXZ›P.^sSóo=ÞÛLÇ"F:ÂÌ2®›™åú»xÆ1îôeȪ²“¥KaÀï%$³»s§ñXBF£¹¾º ýxà–˜^öàx‡ 3Q&Úe™›,±ÿ® cúUvuŸ ÿ–²°n$³Z½Ôu€LÌKîÂØC­¬õž:—%»“iÉÓc±w:å*4—ee¾ØÕÇK‰0“î‘Å+@@…CVö8ë-¥šˆæjm"=²« Ó´^ùm9*‹–´-«3€¦Ë.Χ9Âl”ênCn-®õeÞöŸ¯wÜ›NäU/Q›<„,©N(Éê!$Dé‚ ƒyLñ}¸W†Õiàc<©6ê.˜4é3sLwˆŸõ@ëȦ㠹 ©Q‰‡¥ßgÎÏíƒûåU,Ç/ÝwÓò 2%}RfÈVúÊ©«öƒgfÞn a™g¹•°b‚®ãºÇÈèÖA—oJeTOøÛ+G‘*mwežÎbõÆ ­à¦ŽUšá›¸Ž®–ÒÞö‡5 =ÀìÕªDH¥XîÈy?kýТÌt2˺×É•ö P!Ë&¢%ÏtêéRq ½‰–FuH(y~è¯Uj27×A;°ÁJ‹T1¡?a  ÀŽÞ·•øI~±¬Á¼:@¥¾8Ïgšp #éQçò¹Dž= @W¾\“Úi±hÿ-àó€©ÑN\hYr]#ÐËTñp?Áû=Çÿ€Kæg5a}ï’×›ò)äÂc\OŒ‡xÊÚA6¤ #8h7ç\Ì §…•øó4i¬5ôªID–VÃ-Y—­§ë¼I¾,“"X‰ãZƤJB?Y  Ï~èý@ŒsCcó›ái™€õ¼pa-†ÒMœ6ÊZÖÒèý6W.~Oìû³­UËLœ3nS@Y¿àˆ²ZL@Í´¨áe&æZCVÇù L¡g&¾<–¯B¢R(žï¿1÷wó³käŒeÿŽÜ?<-lûŽÁDåOíªÃRÔ‰²§Ò;¥¨µÃf3™½3”ó ³„…0Y‰»ÊÅ¥‰èFdÃ}B™ŸßOlßÄ8N»½¶ÉÊN3r'3íûºžFµ)ô pÛ/íþ£ózhæî.]0$Ћ,‘éO¶•ˆ`AÔ֮Ē.¾—Í2ª¾éÄvŒ>¤%»Q&WdlÚ…&]¨.°º†v,[†ñÜŒþùúmß]ù5²?•…_™r@òm>éŽ"P@»±ÀËâ'hÈ/1 ‘¹ÕK‰Tù¥gF˜‘£Øëb¸di+.lfDsRWü4G99oq x»““Çr&‹@æÅä½ìa^ J¬¢>ÒCâšИsþ3Ù`$î Þ¶¾5…¾…ÁMØ)$”ç×¾üT>üš¶'Á¢™×£Ã½46ì9è!D¯ ³Þ~å—V9$[åÌæ=cPÎp 6‡A­&: ›v þ»üþk³?5o®aÜp àljà]2áè,¨5 êð ðA”÷¸Ƀ )>v€¾+ô9£Pìâ*Àÿ6Ôµ:Lˆó³ ÙŸl3îǷׯΟʤh5Ý¥Y¹_¡²šðBcŸÈzµ¨ªjãÔ{ú³Q7ÓMMoµ4õjàcX”…X‰BÒwŠQí QW”Ø™n²¢Œªƒš’Ÿ©Íýf¦ •<…õïçÌE†[¸Èl\^H%ð Õ„”“c:¢'©_ehý£gÁ_Õø*p|~ýéÕ§fÙ/Ú>^ÖÄ.P§ΘÎW!…ÍýWu ­Üu5ÆÞ(_——Ÿõ'TîÖʆ½zþbALçðß»p²e/!6|÷$·¥Š`T¬Êm¿ hþüÓûjåŸLÊC€1[d·#Á3ùM~æÎÌÏT±‰‰˜ÇS Ÿy`ˆûÉŽ«ŒQÛ K,u¶juä¼5p‘6:û…³…ßWÖÜ:´ω½áêó$jJpx2'Î׿Akþž™ ¦ÿ&>J5ÄËâñú¨)±´^‡þ¦²ó/Ø;æ9 pMR¬A¦ÁßïÍRÿ¹2Oä~˜rž*@`@´vê ìÑQ8/€Ÿü}ÖÙì1Dä·væë@!±4½ñD†BcÆûµ M ”sëX޳À<ÚRÇX®ß#_ç ¯g»2ÜdKÛþÛs–ˆ·Ê"·E•ž”@³þ²ÚÏ6 ²eÒnƒ%Ô¦´ª±‹Õ1qaÐ'.¸¦äË…dý×·]šˆ#ׇšAÝ4Üj˜šÁ±ÓY—·ì¹*?ì×vÏÜ`$¬°þÞ%n·˜÷'Sßíâ’¨à~l—ºˆ%³NÓk‘Þ%¦»^8S>a‹-âûáìü¹ò¡+øøìÞ­~è»6HÆaz¤Y¬ïŒ#ïS4Õ𨯪dsíòÂTêÀø>aS&¾ «óEîAËp£Ro±Â2¾Àd“Wßü¥ëYdX«ù´ú¡4H†ÀosØ4ïo%JÁ –á™ÌEmGÂßâÙ²¬Œ“Ï®¢>½Œ½X¼YlCÙuõþZ,z¸‡r Q@ÈG¾Y4˜eqõ}}i—ê<Šžö·¥­zÞ¤Q²‹j©J ¡s*¯Ò{6œ<&FÁoÖel²¯Þ~-Ÿ[FËgÓ§˜àŒÉ*QäQa”¢¸ë«•…gº¾H‘ï´ÔÔzûnËþ èuðYÑ—ùsÞ!€‰‘N!ÅÖ64aO…üV,³,>0)üßþû ¾‡ €0gp0œ„Ù¯ý".«-P1&ôÄufimÓÕ’²@â¶ÜÐ&ĶC!!tQgk à/ÀIdCÜ6¥p¸`hŒ‘š,¤a8[“@jYÇ¢ÏBí\;ßZ]TìlH³H…„GÍ,à:ç!ÚäWCÜØž ‡¯õ  ˆñ|©»Ä9â§90" øC\?z®ÙCö—]2®K£Ìü  £7½"óÛw+™kˆG½Ñl‰"¹™á—5!€Äö©Eò™Fýæ¢_ÇûÐ8Q<±¿.ªŸZmŸ WÛRúç„w9)9§Y¢P’pWtmuº†à[ÛÇ1”ºµÏ‰ýb¹þ x%›8sƒפzh.Ì,¬ˆüG¸„/>EB3QPæ$‡M <øÏÅVÚ‹¯¯?Eèmø` ”N?ÆáÏg_=…‹>~ŽÌ³DNnÿ'1#¥“NI1•Áä-\†hÝï+àko+!‹ƒVhÑïoî^ä†:O J “C¨žFÂî7q%¹"T‘ 5œQÞSÂN˜ŒÈ’K3w4ÝzE/É×/8kšf‘¤1]ÛX;i'ÉÍèðYžøþ£;Ñ‘)¸üáüX´ú_¼ÿça‚ÜK'+2³]œIQ† '¦ú8ÍO´®!2œ}L¼ ÷ L8m)²Î" (»™»ü=ÝÜæók™ïÖ6ï‹/à§y_âÓ E!æ]Rh5­íüÇ£;|3Óøs›Cm~|ÿ§¸¼¥gÑ:9ñ©r8U¬¥¥‰™ïŸ’äC$·s¯”Rê7¹ÎrcOÀÓé>7…ÜVcLÝÏÄ›”š¸ˆ, ªêÄ›"VÙQeÈß÷E•ãzq+çu;R©h'8>I«fb”L&ŸcBÔ¥ì‹^Æb¾°R¶ €,›«ñ@-Y/ßä´Q3OüJL¥%z¿ýM6ž,8Î'饶Ü`Iú‡ÇÜY¤çÕ-ÊÑ} ô$\»­­^Uñn§¾`Pˆ[(h¬ ƒ,Ó-µO6tVœ1E.O´T'eM»*ìf;LL'ïM¹>E>¯}8‹ ƒF>jÀàÓ'ž±ZX5¿¤Fœ¤*Žt’µÆ¤Þ¬ÎľZl *'í€Þ“É%øóÊÇvÅ`2‰j$Q¦“Ž}ÖöNù.¡eȃÈŒ$€²%Ì•¯Ät–/U˜›¹++5˜#’´¹«î'Ǹ®'õžõ) ÿ‘Útö0À,5ŠkËã*Ô—¢òÝV°Xœ‹äOôö”WYXýƒÆ"”ˆ-Ö8œÔPT>E¯æú%iÕTM‡/G@_é¤q1IÁÖs:8ßôbQ+2F*U'Ÿ…WxŠÈ¥ž”ö¥a(6©tùöŠR¨‹v©‚àkª'SEË&¬;òr\&ÊÃM\n)p"È~…\BŸ.æ”u3!¿ÚüÕ¿ðóCñ ¬ uO”:˜Pëâà{!o¯ ü’ÖIÈ”ÒA³!M©ðñÿW&&2D½ô‚@ÔplÊL{¤*›íÄ­¶ŠˆÚ ûžQéWνçx‹µdDŽŸÀÅø~ë×uäÚ=™%Ƹˆ$ë«ûh2N`Д†+ÆÞ?¨ƒŸBO÷ãV:¬ò dS4YÉ+rjš2)Û’eà¿'%Íyb¡€'ŒÇˆ£ÂËòEiU›Dà¼ìĦZWÉIgH®…ô–ž-òFqä«ùI™,MHh®,’¢!б/2gŠ”ó`ˆM)ÐÝ}®"žíJ¿6¡ÄíU(àA±“‰ïà„[q¦‡0wýZþæOù‘¼¹®à`sÚÞ„-ÛÖ'"7êzqV–ƒ¢žÊzjkwxçrˆ‹ÉW’–x”´ M°?1„ ©ï(»"»V÷¬%ý*!ΊÕtlÉfrñVa&4/"#­+p¸¢²nžã[¨¼§ 0ƒœŒû–«£/1­Þ¾¥®Y÷S (ãK‘ðI¾N‹ë"là˜¹V¡ ˜ðõ³Üoúz`ñ½Øö©ñèÇó\úýJTåQ‚¸AMi£0ÙÈu°È°õ‚ƒhÄvЭ͵Ì9 |b®{øg\ȵÖU:8ê1×ü<{ƒÕªœ°ÀO8'ê%|É0Æ9ý#±c´Ëk¸&1ÑëÉ‹6ŠÂ u¦ –Aj×ôHÜ…Dr]l’;€ ÞÀ[Èl›1®7¾ €êà ãÓ‡ÄN»¡°:ÏI×¶€‰OjúÜí Àôº 8Fü,^U»~ßñlÇ%”ë¡|û=*¡‡v¡u€ª©µZ~Ÿ‘ ç£M’îzÆ8ü·#RÅ´.*Kã'èWlY Ònñð7!`^Uæ£ tf –£*t6yÈjvÀŸÂvaÖ–a¯!ž="¬Ï–N–W틦Pê–%gb¥² òÍêHö$>{ûf(µOÉÐ÷äÕ?²Ü¦ã@ÙܾðÁ¥ç9±Eùôñ™Å8¦ §h˜éU–¸<Ç!»íÖ·¨IÒ3ÒUïdíâžïæELSiZ_L öh2=Â8« ·Gñl" ð™¼]àÄ›§Ñ>>q¶PáÑo*âòØU0ÈÎr»¿ ¡°ü<0å=³›°`«Qײr áŸ9Çxüg¦@Ñœ0£‰?¸ÕéJëh¸—â ÒÃ>‰-€Âa¯21Aob›à"jÝ$}©HÀ¶7!#Õ–Q¡0•ÒÅ ;Õiƒ ë­`þ6,¿Ÿ‹ëºa¿`Y0 ~BCby?Ê5 Á€bQ bwTSç-óš.ÒbN‘x\ÂFzk¯1'‚Äý:»½ntOÒèn)D•TÖH|5á¡Ý^b„tå ‹ƒÞ.„.zá-”àòA?„¡ÔûA)ŠˆŸ/UfrÐa”´¦Dh¼ƒs蚧鲋 9=Òþ?è’Þ@÷ˬdÓöcˆÌ¢¨óý¡Ý¸1­u\ÕR[b_‰19™×ᤃ >á U¡ö+mœöÎ^DZM»‹±ßÓBF½œ˜õÃ;Î×ø˜ùáû œDõ>u̸qÊ›¦“N®ÁÍ&Í}S%´¿I2¶ÕÃ¥[rŠK\Õ,ÎK’Æü>7F3ɸg-·t“^ÃÑ¡ÕÀÊB…+ä:Ô]S¦O'6¢>  ‹èð;6A\ ñ4/Ìoõî'Í|ÒÂ,¿³Èxˆ´}j¯žË13ÑR•;cçÁŒápU9$÷…Ø“ŠTŸÎ¤åø=+›l–”òmug™n–ÄÏòZ{zoP8âbqâ‰â –ÎTùûÃZrHY ¢x…]æ})Ü­^C§óÙ²+ìegÞä.0°[b Öõ©S# ®ùó¦#Þ Œ7ˆé”ÁMÿÉ+eǘ >DÉh³ŠFfn»Kú &'n¹²‰˲´»=A¹kŸ´ïîXÆõødc æîlâ??÷Œ=îÖ|6é¯ýÐ4r2ÙÚ 2W4P™Þ»Õç ›5„eig¥yh€ÓR-ÓQcëèI°ir’§¹'"‚-èn[?ÛÌØ”óV%Ì­]¦ù¤+/‹¾œÝ•‹·¥ÌžZç“U2’²NuR-ש@0óÕ«lÇ»E¿>‘sož0£WhÌ0õ#):˜X:çô¥ ¤ë.ÀòkR^X•Wב;˜JªÊláÈû™*e?½ÚKAs9ËNe‡pD5ry‚yÏêV¸©¨ÈÆ-,F–ÎbÊ`r)'ä|ÆÔƒpœê¶Õƒ)üÔ&—|B mÂÿÄO|‹¹¬Õ–þÁö#„¨úð¡ êßcûU.–ÊZà¡èt#éÑKh¿¨ÆÛg g׃¥7†öTç4ïb6ÀdÖrê‰Eçîé^‹íH¬Ô¹ Rç!XŽ ÄrÊJ‡È‘ªœKÅÙ/Ñ€Ñ|*t6ö- Å2†3jvÜ^DÅâPÅu}X„Œ B¨‰ "’ ZŸ"êçà*•Ub¿Ãᥓ˜A ß|UÄYgÓB¿<{XO#ƒ½D6.sš,*JS°¡LðœéDšéI*‚&÷èu!•Te¤‰Ž®j¬S.õ `&daNM¼8U­:(ŸpðÐa=˜võ×&ƒŸ×`ë¸W€Š…5ðŽpðÄÒTQîê [g² ’4Ó ˆ23YéÁ¯I;¦†ÏI¸D˜•¸âoÓ*«ááåK£¿ž›yÕ.¾;¯Êºõì;Ûäl¼:–¯¡iQ§)¿k¼ Gj²Þ/UQÑO$á[øH4\T›J¬M]‹ÐOTÅŸ' ºè5ºÆÀóîø± Ìò•95Škñ„˜Pé}h¹´t n9­n\’S ß<”50XRÖN%þȹ~ÚÉö(`ž‹²Imb`üX) ô£$òÛ|Å™íV:)ÕàŠ×l"Ž{¸Âä_‰€£³¸â#¸|Χ%GLŽ n…œW!@ihxg+e%ضȤXS9[‘ÖòÞïÐÅýªU·Çj„-¥×¦í£åÈ|Wö4õ¤ ñ¡œÁ¶®Jè:éC…ûØ D$Y°#ºs˜`ÕÓ™ä퉼^?‰Éе˜p² ”Q^+G_ŽÕðóc ·£UÞÔ,² ¨Œ—âùÊS÷s®8òê•ÊdA/DÝ,0ï•%«ûÌè[ݹ‚‚gÜz»Ø(¿ EÔ^À¯‹cHä1û½>‹Ä+¥JWÂ/ì"0G« Š—sNùÃòqÝ™›>+¬`ïšü½Ò–ªœVu¹»:€Ïù7VéF½F—ª¸|!Š !>àRW™ÿÄqÈʺ€"¡J‹ÝdЬž_4Ák{%Ó”f¤g»ŠŸˆ”R@¯WüµJÍ*RW[œ¼hè°¥#´ž"ð`&c™øèU¡­Â˜›}i§Yt´æªPb;cU'd;c•°AîˆèSøÐ/}éÖ-geùñR‘ƒç*f Ó9_DìhÍ©@é:dIÁX„ hÍ`'1?†—"Ûe4±dæ$¶O,2.êåw0±˜”+0^ß’½,‹ƒ ̸õÊîvj'Lc Ä…íÅ»:©MD-êñ/ì  E:oB¡[_£\Î…*‡æ/)¾T…1aÏnOtäMN8w°h‹0p,æ‰!æðÙ³›ô¾ð¢ç¡žx•biy Úº)î–—ô°¦ÐižÒwÛ¡pñ±Ô»úˆÇ)¤dA÷ü]5ðD³1ήL¬óª"¸Ä>ç𣌄Lôœ¦jô Ú HV.É|²5Ьv«šÊ<‹úò¥’ âDÂm"Ëåñ»NÀÂ_úe!½äcB•À‰Cï7Å‘Á“‡ü€ùºC¬ ¦‘€f†î±Õd3ѱGÔ€¿'ŠE•~”/‹DoÜO“•EB…ÊJsn܉õA_Q=ŒÖKÐê!­/<ØÉQϲý:@1=SE0ÛºðÌåßu‰^[T[§³Cô å¾€?¦4ÌrÄ\Ä ¤Ð>ãà 1•,ü6ëTÇçÁ‚oæ>—'Yœs(Â(3„ÓÏr ›>»KŸ`ñŒÃÙJ®Ô;ÊÄô Ø5ekƒe™¦¤)šœ;kß}s…73wÅx³"ÙŒþزùº ŸDØVO×[nÔ/ 9ǽÑJ~õƒ¤dâ½ÚGS6 ÔÔ: §`nq~VQe³y”  Iç*VxÐ`‰” c'!ñ>Xa%ï °=]djÄh6tžD]¿!}4­Ë*8)Ài)\–£Æ€eŒy“Ž‘™´®ódÀüÿáI„¶·Mª„ø°´U!_ĘÌbÜõó&KçÒ,‘h³!Uˆ±•iV7C[ÖÀ.”žq÷¼H©Îérœ 4Ëì&ÐYÚÌÖ-ÂÌIE…4>!¦½TâÆzÃ4–©C*eN—NÚµµe°©÷ˆÍËÙ>;ûÀÒ;oµ5Ù¥&©fäÃñ•#P ¼j¸—³ÀñÃ7`Š‰ÚŸ5PuÏuv¶OžŒ®¾BÄ 1¹¨Š€RMX°kU,œ2baþäªEí3Ÿ\ô¬,à|üþå Æ(•œ¦ Û=\ á%c~ÖÌ%g{>êùel€gW9%ÓEšyUPÿf Ao8åsÐzW Él¶ ¥+䔡Ó — ­A~ß½îç'4%á[9“ìd”±­œY¦aʧRÙ1/fábø:ÎE‘“3µЋ´²\òb1nzD.l¿¯¸bWR„‰ÎIÇl‹;,ùÕ™=@Z>ÖF?ù‚”Ásæh‚̸T 8@Û\ˆ «3_‘Õxp2¹¤ rÜY¸¢OJ€ÑÌ´˜:Lª„çoÃ!¿™ÀÁjߥ&DHùû‚{¦“Ä4Í""*“QÃv¢uÌÄC.ÖÛÓKÔäÂLCt‡€Xû‰‚}²ã´ ßÀ³`L¬âÆMCÎ Tj³¼©k$Ì WÈ`9¸Æiþ®pZÙLD²úûÅ«G¿t!ÂEÑ’Ò«'LÚ‚!ir—¦-;@ëž,4gFoE2qÖù¬{g¾it× /xÃ(FÙîj`@¤“evÐl6­c­ãGJß]ex°BŒÈNLƒUú¼3ÓáÌúXÁÖÄ­KNÜSP`¯—KŠ<‡¸Øã……ÂŒá>.#@gòþ'Œ í…™9©ÒôÂàøÊ¸ÛŒòdáPœ‰y‰ÉV/ð‰ý xÃ…·'“`üVxÝ`ýx#Þ•ˆ"`˜ 6›„mß@ Ç—Qg,QÞùö‘cÞmÈðˆ$Ëåëù£ù›NR`BÈè7÷x‰èß’hLY8‡Äq™GR‹¶*塊™ò›/ȳø»1è§ËìAúnŸžu“'‰C"}ÑʤX5ÆÀÁAâLÎ*N}lª}P(åÞ/¤ƒ[ ÐÑRË8Ì©Í8©sJÈÔ¦ Wœ–š{',±úɸb‘ªœ*ï}äõp:ÚfHŽ¡œT¯È£ûªB˜Žž§H­/pùu¨”†< ¯4ëS&×Oˇ-Ƥ²ZÝè{ƒø¸™¯›’ÈÅý^®`påÔ¤¤ªžU“@³ØôÞ0w!_Øiò£ \7 2óM¸Ú˜Ÿ6ŠXM\¸(\"d³[—½:‹\'~Rº}Q" u5;ÔÍÑJÒSéd40…¤¨*¿ÕF“>ü¶©&vF§m¤ë8++VΦT®ÙÚ@thŒF>}A!É…õ* ’bÉÖp’ P4.póZ§ZðÔ¥¢[½2 <‹°É>µòÆ¡›Ù¾IîàÄd!*ÝC´4ö©J˜`ÄÈ–5Or4¤ª¸c•h#ª¨Ò©¨¬«»²(8x[Ôò£«•#,kK0H#FIÉŽ¼±y„5¯$LT½m©!cïä;ZoÎŽ7ˆ©þ׫ÃvQÒIˆû&I=Y¶IsY’mÛ…R L¶ ( WÈuh+nho Bð›Ùƒƒ€Ç{ËáY™ñW$Zðü” s¶'•,á[‹ Ô-Å£Þ#dÊ]ÁÝj2zXÊIìö~Éá)žMÉg$Ä‹nîtœGœ£J§ ˆ*š ‹)Åö$ðào5ÇÄ<ârD,߀ur*ÑË{6£Ð‰ï`À“'_…À¤'ç¬ ¯L†œÊw`Âxvfn'€ì!ÞÊJÔ„„½©¬Žéšè~Lx|sà<òWép@63GqF—;"˜ sÆ[X >7Kˆkk[æDQšnO®AÍÜq©Ø€bŠPJb5gæ£ñÄ«hf>¿ß2eñèË÷OA)·7ñóTý¡ë+CÀ݈!&TôЕ&6À=Ö΄2nÐj !+˜ÛE™nâÍP¥»ß fÖce`ÁWg×ËŠ°·lÄgïϳºÄ¾i:&WšG¾*¡®¹â®°QÞMT« z£xŸØÎEóh÷2!OÀFn3²ºìÃ8¶[•#*å#Ý:CÝžÓÛÏ@v›}Ìô¸Ô ß_yR¹ÄW1ê_©ô™0)ØY 6~|=ö‰a¹24\#)ç bÞY5J‘(î™›·®ÃÆå\EZŒ 3‡@iÖþû·]µSGÒW|h3Ý̲DìÙ¥lÀðÜ]/¿#MÈ”PV ~w‚6¤ ßåC{Í?FÏ› ;cçËW±EªÀÍêïGÃè³ÜèÒ€?ñ˜ïºn z6&ªëiòî5EÇ `©cüçÎk‘<`m¯4±`ËY®[ ¶¨v±GíâÄLüë¡MJ,Äh RœU±³ätÀ}80΃׈Չ^ýÎàÔsÞ+¾ÖÏFJrÁ\.;{ö”Á)`B\aS>VÂ-ªÑøó“Zî±_ÿ¨µë) ÀfÚò?@ÿçIf&Å]Z–Bºqƒ.—L<^ÂÇíOòN’cÉŸzœ¹U @0!gú†…euÕpíGýÒ“‰E¾ºjS,Ÿ‰VÍW=®Ìœ{ëÖ6‹ß¨-5¥U•kX좋›vÊÆŒ´aû…¹ª*Bëñî›øh¬H+¾³K&<xõ¤šXÉ%+XFMFå4®†åÆ¥S¤H¯|»3à³ÊµÕÒoÂÃ,pëM,xeªÌ«D%(ïÓf<>¸Ó×I2“Õanž §Þ×ð/&€ÀÉæm.=7åã È­qt ?ì€Î\d›¿¶˜€¹+ò“Ï\5ž“¨¾2v'`„y6Né”O!½ÊÜ` ?BbtXéþæï›”<åÔ›˜yË=ð.xRûùn^* '¿„ñlŒ!Å«®(m¸“ŽÛ„* æ–³ßO¯* Óy6TULKÒ„ª%¿¶Éo¹ÓU3cb¦(w"‡XäŒè‡ó¡K{îÇî L± @yœ"S3(¨ê³ áÉãX‚ð§ócÀåhÿ((‘ÌüŠÙ” p‡&K¹×ß8gNDåVш*URP'žsµ¾Ér0vàĸ؟y«ã ì'B"ÿïo2݇÷"Òc²zà^V¶;ªË w]ú3¬1òFàçd¹s!µ`äjämÅ>øB\ ¯ÂUØ;¿Šë &x¬"õt@_´õ¶®ý=”±fHÓü9ÁËscýç‹ÝªÄ‰]K–„ÑRnwÓ©e'<,V$ÿð€¡­°â¨{ã?Ølæ©U…µW¥?J%ªÆM_é&¯‡è ÑI‹‚{˜‰ÄÅ&Dxß`òNˆ Ô,¯ê âIÌ&d‘¹^±Z”!±wɺV1‰x´¢€ÐÕs!+¡”5ôøT‰ðy>¥‚ÖìÑu†à>ÚC= _Œ`Å nÑöÅ«3¼jÚu´Õ§ØBb¡—oŠsù£B°-àVIÛŽÒ{]2ÐT6“ª|½f ’.Üœ’Ñcâ<üi¾„á9甞AÉ >?¡èÚ驟ӡY,Œ°ÙêUÛØåNÓj¿]Hœ‚1x¾Ã:²ŽÊl´;&ò?®× TÛÅ[ŸÂÏ a&ޤ€3®ãÍ)ËóÇÃÁùÊ«úµ8³×î¶8—޼g?l>ÚÕ'‚†N†ÐüÔ®Dô4ÃaF€1Ç¢˜A Â;[N"£'H€ïç`ß1/Í Ÿ{ T_¿»qüömëwÕ±Hœ©føì¼Ü|>u‹f¬†ÝtÔ‚5dSÿB ›æ3Æf¬ É1ô™žGw+¸Oó ’ù>‡y5 Æ=ãü{08ëXk‘ cìåb,ÃÝڑꯅ±FëAnRüÊúÀsb€÷52ržTÓ‘¿ÀÆ-ú)+ÅO…oÂëMÁå"3ÿù‘À”t긂°v ¹2LHZçäWRGü¬„]ïë G<€ü¢¯­®­£j2KÄ º8dæ)é¤áT.}x1ɯ¹2íôhµ±W_°'ߘðë¿×¼ˆBPN¸g´Æ¹oÉ^‹qU¸Tîçr ÛLZ?g¨¶bn;dy7¯V®,eMùÂíËÎØ¡ìEã26ÏŠõ슗/Cǰ¹Šè÷‹k CÞ¨Tv6¿ÅKèÑç?–~À)4'gîCwû¡²ë÷•B|ën ¡…;¤e~o¢~A¨mW}ðÉöÖ†§+_$WòfÆÍz=Å .NñÅ¢s£ÆÆ1½&ýo]ÜGŒH®r±Yëè1WÆQ oö ™C#×óùy‰Û‘0‚ìæï™$Ã>01¹K~½^±ŽU™jØ]Q¹ïÂPS;j$ÿÏžÒ÷ÌE:™s¢W¸ðIÓÛ©·ðGÁöÑŽ£«Ší±re’‡³•ãoŒðooÌu?³ˆy¬Æ˜‚1¢ù;ym R,ðÕˆµá3ØjÞû¾]]¬ˆªE4ážELñ[ƒ©‚Öâ­˜˜ ì×z;„}¸×5¦>¾øª|Ï =æ!-‹CjÉ@®&‘K„ú_ßÉÄmûØÍ>!,o_ZÕÿÉÊ^YßïÏ6®7¶£87jÔ¹²›¯¢YhŒÁßdÀú½º*Å=·¸ñ"•D’ñã{¸Á¶>UÖ–Ü‹;§®Üòª#äjƉÈüBï¡ùT¯Ð‰}Ãå×d‡ªP³`CŽÚ‰]¹ …À×ó «ähó"vì¤-^ÄÝ8Ø{wfÝÃ¥ì£DâÁRû^IÛc¹ütbÖn«OÿKœhæý#Åßf /3—Ç!RW‘˜\õ÷óaÈuÔÕ‡piºä3òÚƒÌ;‚ø62@’Gž(º5y˜Tk ñ|dÕ°ÕÕdîƒÌñ%ÿN:­•Ú$ÝL$5ò,qSŽ¥"ËÊC×sŠÙHÒÝ–$¡ÕŸÀCešhgõF8Ð}Å$¾ëÕ¤Š/äGPç`6š¹\úÒÌá¬ÕÒ_Uó¡G¶hŽÈá'cZ—ŸäC9épS”²êóa¾ 88ÿnr‘ä\YwV_#baÚù¦Û}!¥º5Ä2+:…½š¥\yÕgäPÛxœ0 •âx¼ sóv cz}ª&_” ›$›ƒÛ10ç\=PO6^p6鼎FyPÕ„ƒÚÕá¸11·j!¸YV¬Ëö+•ï§]g   F+…v–𑺼*åÙÊ%‹ÌºS­È‹´• Kkø!½êõŠ•×ë¬4‘ì×JZá÷-ؽ­·ÄW(2ÛÔbxÓ8õã(2ʇ©ÚÄF, gIŽÃÑÊÂÍ'bçFƯãÕ‹îÊ‘‰tZ*í,oíWŠeLPɆ‘à5ð×›j„;ÝÞ5"äì zèuDÕàû˜[òdxG9–a3 "Rgù¥•CÉW,¿/᳸‚^“Q/`YÞmf9òÄWòêuq3_€€øþØU$eø•Oä{¶ÓªàEfˆ ™3 \(T±ú©ÖW¥¶Øo‘$ëöŒ>¹»¾ FÒz|¹6ö¿N)éCäÛ³ÑtègY¼Ì¦*Rõ,È¢¯›ÉÁeبN§rkc¬Õ3Ü P f0Ù“¹ñÄð  ;0‚Ö´nî}ùÈöeh““=n”O¬â‚Ãr1_‰è×ÒèøCMg¨õï(år!¼£ñÜbùD±‚ˆDÓ°ºE|¶2Âj„C(EÇ#±?Ùqd´Þtp Þ¾ª(lsïPTÓÜcÞ€»V~Ô‰–õ…z\\M„v%“Öç:5XÂRTÔrPÉè¨çeôÓÙÕØÀÐ1eUŽ·t0ò”¯ãfAÕä:pË–q¹ª3 —jòNtðcáRE$´¤G€¢{•®ÉE/ËéÈXÒþÔ…|9Çͱ£‘ÝÖa¸Ž¶Ì¢ô’/w¯ Z3(½\4;¥\ð|úËtHhy–ß©ï `î\žî×}ƒð‡½î²ÚÆ!ÿ ¡ìôhÂÕ8Y ˜ùÌO4c½³ŠÌPÌpnöhÜÎXšHÚu¡îS@}J)æ¦'ñîAذ×e2K •±]Ú+ϳOÌ»¹}äÝä¬(‡³bGJ&`Q…°nк¦Œp‹©ŠÏ·]4Þ îb[ØÌ7ac`ÍKz”Ø?1-:”œØTm(ƒ‰ Φ §†e p½7…ø÷ÙM5&+jwØ"7áÎC¯…¬[4ؼÆ$‡ƒnê#0Ȩ ´œÒ¯n•uØ“‘ù·.²ƒ°ÊɈ˜AÖz17ȱ‘ˆÈbÅS’رNÈaÉ\,D½!8<0^Z\®ëêX]¤ÁduóÀ"wÑnsp?SׂæxœyOSä­&;ä­ßò;5!iÇVC„ZM¬ôûÚëY Â]Ó(±|¦±`Ü͇zŠRÀ=À€˜-O5‡ˆóâC)%7s[™hS›ëŸ® û=ÒÎw`àJ#f ؈ŒµI¨-¸S#µE8ŸoZæ>ÖA}…i.tåEÑF•×&CÄ}^t'l5ª(•1¨X~7ÉàaŸº!*·öþq¬ƒäÛMˆ1D ½9 eÆ÷a =r e2ŸÄ´}£õ‹½ ¹«|{‹Y5GÕgl>Ï: ^‡uLÕaüp˜3‡óÓÇØr¿s>eT;¼Kï2¬xˆ—,-Ó6v´0òy9ÃÏ×¾n')á³xç}ˆZRt* $—è=ÙµãpR˜‹WÞ¤zt Vf–q! íÒ‰+èÌzH{é²¹àbÁ.¾vžìö…t¡<Þ©;  Ã©[ª ‘qLY¾|"îy¯Œî.ÐÏ€™7!])ÊØð7=¯°±ž?+ÐpR>w":‡“¡öl³ŽÅy?µ@¶Šf6Q¯­¦;^-Ùƒubчø™é/§¨ÝÀXnº.õœ®IV·,Ö`¬}™/@"´¨9’|“à³^_È=êg} PV¶º» ‰i1ú©s]ù±Vù¨óŽé]–M…ÿN^Y8™'Ùã‹ ^,CÉ'‰™‘þhe:â•¢¡lÆSZ2å‰I§kF!^,"lË{XŒƒ ÒIš¸Ÿ¼ãó®:¥G“L€\䉪j4Û‡ËÚ±q‘³öÕÑ.Ùk¼YíXðĸ{‹•-֩œ[wiò÷,vÜÖÔÄUd½¬YC0tû”pj|+sÚ 'xW0¯j¨pk­Í¿vRur×_h %ž¾qÛˆhž¨ë@],a)úû'ß¾°ÄâÜA^\(öXÁй¸×t«ÄkÁ‚à¬N¡ŒMÕëXâ jÖ¡5ñ)3pÇ ‚UÌ´UPœÕ¥ÜÏn!=ÊŒªîA ­®HÀAîKç—"=ùëõU.)ËÓÌg¹¼3苪â%ðütÐ'ÌùVæZ¨XÊq>îÃÅjª X½|4EÒ)îÜ"X–¢›s¬ßnÖâ,U8œ¢Ö@”ûQB´¡œáY†l Táôtpµ • ¯_P0¹*1,_‘·TåÃÎC«ê0ÉÂz: {ù(„©^y‰Ðd{ÞéÛ+áÆÕŽ÷ì ¿‡‰cSµƒ¶„ (ZNbŸ9 &”T±‡®÷T~Ú©)89H‡áÑ­p^ÛW)™\·ö`]Y$åדlkéVùipˆsÇyÛÏ»Q=œ¾Š IÄ ;1 "NúŽͪ‰‡btòé:´sV.o9¼,‚Ú©y”eÿ¸8ñQF•3A”²/RêApç}âÜKE‘÷ãvO¢Á³1‚Iœ Éî¼_ßz¯Ç‚ Ôµ°Z`M%VLôм0¿~û8 êÝÖ‰"^(ôùÜÌ+sômAum,©Ãkr¼îÜÂcÁ„}kä “Ùlìw’˜Gë#À–ÔLGK¬€º&+‹3)º÷IMߎaÅb©~À†”™u€¶ÀYç•"€]ÙªkHwf᢫ÐO€¾g5¨"´Ós½K°xi_0HûPž{ ÙQ&zV«]Õ'›ÔÐ7ôÕ¾a²r§ßÇ}MB%Ýöþüˆ½ÅÊ|j·Šæ¼[T´›T ƒä*,÷aE¨£FÑÙÀ’/ë@žLVaµò>eé`§,ÂòØïr>OJQ 6¢ŸBùj81SB.D*`R%‡AA%šEžtñ‹ùÀtØ`±G‰:µIšçÂBéBù:[+j³ˆïTŽ‹ šŠ¥(BÕ^'¿ðTåî³>öI7wMzÄZ[ˆqf m ŸlÊ)WÎñùvA2k“ý?uÉ»]+]ØeÎ#{~·È aO_ u îØÄÌ6áÄ[ýAu¨ä^Y›U°ë[©ïûÀ—˜YÕ´CßÇŠÔ ) ¹.¸ÿ|z¤]­'H#r(0ýÑÛf‰ aá3×ú¨©Ëlsbi5Ž(©Æ©´3©ÊÂÓÒKhÆwΨugG“®b ýµ°†þR ¸J†R›LÅìlà¤6™R@!Š©Ôt!ßAåäÀ ª(: ªÀrÚ„?%fÛ+χøXøbÏIâ©Y"nÉ鲯Š@\$»Ê U¼%­}gÆ“Ò2'ï93D™ìÙÂd³c„¤:éNu`°ÀµO|ia›¸0ÕáâE@™ZÛd>ÌéhØ2³©-'蕘XÊëo)QÂH$*íëC+txSV¸†@1eßkX&ñ!Xbê»-ˆIç+ ÀâcüXGº>À¿ˆ¶ˆ0£Ó ®,»"ˆÎu´[Zª4Ó@vô¬TN¢B©ú½}ÿÅ)43^ï•+äÊ^Èd!9°EÐk Çs¬`îÏ.á™iwøó÷—ºÜÔWÁo”ˆ¹lÓ8qúÒ¯¿/’ÏU®â“l“«¨§÷A°@m’k­‰JMš’ yk#LÏŸY,@’ÎXÙ'ÄÈ«¦|WԢ߯ô8Ù„M'É!gnicÅuÝhÄø`ÃùèâFÍQ¼öûXäŸ:ÑùÚ=ÕxòQ?öØ+úr‹;,&>‰;!Þ³F6L37ÒgFþý¶õ/^€‹ôÃ{V.£‡œùŽÛtè4²øI}›m®=f–ç~7–.ô‹% Q»ƒ4ÇD¡»‹­&ÞÃ7ÞƒI-ßþü „aü š¿ß›ƒŽ³VãbAȉÃ=ƒ]X«f»rT–gòÉh±V•0D2Zã²R*‡ß¸lÀyìOõä÷[ÁEq_ 'nòª–­¥‚£/7Û•‚QòÅb¶ç;¥þffº IáÑqšØ°çrñGÅfÕ£‡å6ÞÖzÒQ?vËr8þêoí4ЇM•Íõ1aµæ…½Ôu.ÐH:~Eøœ\½£ñ5›Àø¦ t u"ÉðfÅÇׇá Hòëý"ˆÙ Œ}¨hxÀ¥oÈ@6Ÿ78p¯BqTø××½©Héà1ˆ~Ôßu6 3Ýa?ä © ämU½¨W…\W&D„5…åŠ×}C,zödëC9þºÐBàYT‚‘®8ù,Ìôs< ÌÙPN÷×?³ó4š¦ÍÙIJÞBqtà“)X½%>YWÞ^·©Xrà`•ùÈKv.OÄÃìˉ⟜¾T4ìÐþë ‚ò`?R@) /:·w9pÀ™æ{¿ßDCYm}*‘«†/À„Cì'å÷ð¾hÿ³àJ»ç÷¼Cš&qÆwTVxQu%Ï2ÒM£üzâOñBëIyVê ðÁÑí ‹¯ÉœÑ#Þ×^½©·Lî+‘ÔÅî"%çí"xROGa­4ÌWø„ø:ÔqY}UR²x7-_ûÅ…¶¢4(ñ;c-UÖÖSdã⥆Òû÷¥ FÂJÐßYOÝžV9•Ï…ô®,½½nƒ7åÏ–ØÔøwÒOMœAiY%FUcŠm€ô_` úc³\ñKg}ðHÁ«ÆõcÜÎCñÎdêµ®ÚTæ¦æ"1ðËf¹{¦¼$%ršß!&i œT:ÀáÕýøÅj­oÉGú±i~cUJ‰`Æ;}”DØ‚©GÒVŽÃ–g–’lŠW?¯ˆhY^¼C±\ë„ç{r$¡j(á;«µK¨LðºÄ,p@··@?¬ÕI㣶Ârùø—:†ªà#›Å&ÆøW÷½‚IîcÀ3y£Ì~èî7Ýr¾–Íg[ÁQ澸ÆOóò ±»læßᄠʪ¼ÈfuwXTÇ68åè%#×Èþ½É·T4Ê@˜ôª ûäbnº¾w u ½å—J·¿KŽù&ÏåÉÜ?Œé)]Yè$G7^[´,Åüôi`OVS“³Ç;ÞYau-+OØJüáªÎÇÂÊœ-1ðôžÑÿx8pÓ»@>´f]šD>9SŽÉNöµ²ˆÉØV…ùõ øe_~' Z%-ÝŸÀ„ŋʸ“²0|#t…OqÝÎdgƒ®ë»ãÞc6W øO H€u/Äñø EÃiäß^·ñ¦ù¤;8Ÿí…ñ™Š$<¬5+×¼Žâ^k7ß% Ø3ýAPHõ¼Ûþñòý¿4„^á8àt€Sð¶õ=g}slO–Ð&N-À:yjþìTæT"3ýf!¿ìÌñ­^Ê®Á4½2˜rÚ,±l§f0Áqó™Ñïæ—*Y¬”4®Ë!üÒvmDuOôÙ.anUž,+lÝ7‚tàÀX{ÝÈ›¦‡(:5pM8=Lò¼”Ãr „³ˆçµÓ oY‡Šp\» î dÍu*øáP©Ðí"dmW/?ìZ-±Ð¿Höñθ}j˜ã~;Ç›${̓ÅÏëpȾµóA13m?<ÌIÅ~½øå§ý n ¦ž¤¼Ó½4˜´î”ÚúÐ8ß;ŒQÅäWú–Áaã^<¶ùéý³ƒRÛ§©ÔHO{£4öa¢%œC:4ì ï Ì«šÅª'*2s¨:r“dËqžŸêí©O¢žäŒ*Ú9Ĥ"ƒñ‡7É`“âºyH>ÆšôÈfæò}ÛOõâ\¦ˆ}ÿã÷õLRµ«Ôë§“øk»|abµ¾û«VÒïÊoI¢Œ>:#ÜÜé(×ö¬=Ï^êBçzë¯#6/_Ï~Md9’¹÷Y³8’‰c,™c×ʉ€¿hãM•: lH÷Å—7éó1:¼Vdò–òŽêóË‘kóöºi¾SŒÓàøü BY6%þåÁœ!G @ÀBdyÄQ"°Gvݰ +K™e¿ ¢w ˜béíEwñµ±À±DÞ;¤%vväPŠj»˜” `BQÝ“eÁ¥»Š9<êµ1.óÉd@[p–1jZµªÎ£D û bò Füº0JT±˜x…N¸{5KºRsèO­*§®ä}1!Kkäð²æEЉZUý„äÂ2pÀ6Ðã,¸ÃkQ<ªØ„Œæ”ãQ3ñ“„©¡ÂÖ"’š¬0kµ¦x˜ô\¦~Ï8S¨ÓrÛÅØ„“KßýÌl Ká 7’ËŠ4?¨ µ<h7„dùBF«J÷´³vVµ;š¶°„%KÕ¸ |$+ÎT‹*ƒ’Ì–Zµ6Sd…²õd±îÖ¦þÕ›!¹pÝ T6a“¯›³EÁsp…½Q¼ÈNBð:DÂfê~D,M8hú%íNåÁ9V"D ÞÍ*ß­‡)3ÿFñí6Çeƒx·œßx£·Y7¡x²¢·¢Ùµ09ʶL<°êŠrý[–ÿ) ÉyR¹ ‘mW‘¼(Å®§ÚESº€S’hØU6ã±0Èéé®1„ »hÑn`ßZ …Xû¬XD¶ªa”ð‚ÄïmÐcŽ* à@l´¤£«žz³=°X/ÇgR"ñ"MH³m*´­û¢{;8>õdPÕ€ö`»y‘#¬B1¬ëb®›f«Õ“dR‘©U‚ûØ¢ÃˈHòˆºX¤@¾ikeÕå°€øÞ83C¾ 71Ç-Øu07ݹé*…çVq…’írÍŸY¨1òVØ`ýšt,;¦ÌO]×+rfûAU;w,z;¦À ÊîWZÔ¶¯×à;ÏJò[³fÃ.±ÁÀ+ÓÎjQT˜¸ˆ·­ÿGnzØbÞ~¹_ûÍ•ü',ÍqÒ½ÿÑIRź›#i-„܈Y(_Û娀lðfeÍ×m… ?{–ŒÑ9¸âB8€3’"´5@6Ûü;=þ. TV˜»fggR˜ºPdÏ[þ›¯Ý¥î—‰¿ÜR$ó;¨”g%ŽÕ¬å˜•´òÝÿíwðž]X@¨‡s0#­ñE·~ª¿8Â,6k”Zì/ÈP Ù+BUŽ›HÌ/9š0±*SÔÁP …•MD6¤©ŒLsŒU5oè÷Q S—lﺭL|P¼xùÙSÐÝ~”ªW{eìÆM>Œ±ï·×mà“-—³pŸu;ñÞ)V\¦GÒ˜ehö&Nø¨'j§„Ð ûXÔÒŽ_ªÊoçy£iäÿÚ³§K½@7œî•dâ­êÊ'NQÊG( ‹¼åLÈ‹ 76p7 n‹,éýKö¿{(ž£ÓÁ ô3(OБ e›ç!¹§)8J4 vhr‹T]‹Ë¿}ÀºœãŒš¦HTŠ3õá#|þ(í‹Zje‹“ò¼Cˆ [ÃÛàF3ñBm‰²:Šd—IË=t:¯O¥á>V@–µ}‡T ]˽Ù{ àâ öäyXm"îðÛ©…&žT¾h‹5Qw´ÊT^ÆL³Uº¨Ñ %éÚÃÜÎ΀õƧãÔ ïˈǧœÓ"ôÒ¿DÂkâ3Á}'6Ð7é­‘Ié{‚qNæÙ›”hUI‡MÞ’^³§Ð×¼©Ÿ\`,y©x¹÷N.F–UíõaïwRÆ{ÀÅ“ÌÓ´$L(&zTì}m–ïkRúëÆq\E®Ž[3Èâód•|zñºsˆ®_ëÄß'ë5ºÝY«©ÈqS|íŽTwæpUUFÜ‹ã¬òÜáe“ôI˜ý&fR“r¦’|RþëDqUº×‰ÌèrÅû±OÝ̃xÔ•ª Ó^멱ø¾þ(~m öÁØCç÷ññ K¡xraí ^6rZÿÔ [?»îLt`PŒ /°¾O![å³}óªÓѬ|Ð˼CÌê‡ãã²\2¹Ã: ðP4 kôX|mö|6kRÊ¥æF¶&ð¯Z 1ͧ4ŒâèÒ½]ó/_öS½ø8Êì ( h\¨+†6 ½ ×Q¹ Ñ¿ùНSú'XF,„÷Ë;Ì8Ò¬Ô[ã3æ¨$PÞ&󌸧5ß^7Íw.qêÕ[ãÚWžíQB4¦7\rÚ”Èn6²ØÔ(ùóWMgãøÿúzªD6ôA!2<-æRÂÑwÆ=«Õ…Ø©gö?h9úeâ Õpm‘ÉX:Ž„AØô‡èí ¹X0»Ó@ü¦ N3¨ôYñ$xWñë9cIÖMˆ,;¥éÄÚ$¦´×g$Ú˜¡¿vÌì­²Õ*Øýïç6S×ÉjcÒ(Ó]{@qq†Ò-Cxç¦L|7Ô&¥bû¹02KG¢l€_0¢rsÕ2gþeÐDØ ްG¸`GÀ5L ™¯YMÏ“€8ôÑZ&Ô«‚ÑÖ/}´*¾³ýõõ\°í?CÛha\ÊTa%ñÆujdÖ!À‘àÊ“˜«õhÒ(/%çÄ¢ªD‚ªÉ¨þlKÑÍ~앺Î2ˆ}zúÍ«N56ášb"Wˇ&õjìVÛÇè ó©33ˆ Îíµ!2÷Mÿ!†²±…§æBb)ñôÿÒþEñ“0SïË‹Šü¤â1ô!ÃŽ¯Ìè…“öþDtº®¢`Ó±‡¾ö€Ø¤YšT 7°IË¥X¹Mœ˜¢Ï²ÁQtVæ4¾h—/<<†è,0TÂHz ehCYÅÎk>yNeŠg¢¼|z6fÙ%®¼D>{ˆ-ÂbÛu!<} †Z!†3 z£Õ×—gó¾°UKsyñá‡tVÀ'2.Fwll+¦|†Ã%žÝ˜± =!¬°vñéζó­š[º¼ìÁ_-p¼šÐs{$œ< v€N¹x;ÚàzæV£Txl»´~ŸkÅ 9²F¹FM¦ k¤£-G¨7‡® K°’„Юjúrt»Ï$zån-zQ)öÛŒ^5Õ—Æ”ôº¢ƒûÆCä¤/q–çÀ°Z-~^Í9Y!6jb¿›ÐˆBXŒ°6F¥¬ø~+ŒÚ¼Ò³ƒBèæÎøU1¬îÐ%£vÝo_•4]múãå*úËVŸ•'NnLwBÇen©ˆ ÇbdY¹Ð¹‰W•<+êïüY³ÆÏÕ#â€NãÓ1 ð†╃ñ‘)øF£Ù†³!ÒrJ‘„cÕ2êÆ ¡ïŽŸèÀœqiòjÌ“#ó·ÌÎn¶êyþÑ–û³‘ÅãâeR0! ¤.÷NÅ“1Ì!¡8©‰W憰ò”q®–—ãýÏ“›AñTbÜmK¥º!ô‚µ.½÷›Ž{"Dˆkìñv.ÊyOÎ8ò ±pŸZ®·Ä”®na“_ú!Ê‚J?ìæl IüÚÊj,‰/Cð—ܰ)MXž¾7}è†ñq:|¼ Q<ˆyŒñ¦‰n®Ï”G.~Œt¬º„ƒÌ`• G®Ç¢3¶9¾pœßó(N–Âý4ð‡?Þ;ãßA‚²™p.†þfÄD+”ºa(ÏΉóÛy>› [x ;žíñì¼ ‡ýIì«”Õ@é]âP&\8…U²}õ;Ò0ð•­d4NøýÔâ„÷"ú::VLÕïý:tYPÄ`½»Ÿ•¯OµaŠ:¿}nîþy¾çõ»[ê<– g „½4àtÅ!œeñ3G:£¿ððG8Óµ‰RfŠô`¬Zü~:õ–­gœ¡QÍô%ü¦}pöÜcÊÏÚóãúû~ö¥ za+§¤æOëo_ ؃¥l`j¥x-x|ÖYÕÎfcBã{_<Âwã„þœì!¬Ïd¹AèUHçú…¶ygãr ÓR¦©Ç˜„ ‡¶E›¼Æ¬ˆ}°á¼t¡[8P?'d~Þ„¬ªßïɳǛ…°sf[˜J‰˜G#Õï1€PsgÅ„ó¤°óVj­` OÃbà°ºÃÙ„ÆXÄÙö2˜öÄ79aZ4`ÞiŽ5{*{Úfµ„¶9ÍÎïtxàø}ìµø€VÙ€Ó0Å»,Zý·xv×Ì›}QºŽ#0”Åi‰c»}y×£A­”¯«(]x6Ù8zeÌ¥.Ò8 !b'¨kTyldãLØC>Z­úrýõ۷ϾlõÛ¼èíËïúv 8´9?ÎàV8φð¨,þÏÑÀ ¼0 «7Zrj¬¼þ¸/fìÕÔ~Y¸b>­®¿ûíÛ•øjÉ~³º-í—ç&­Žç¬äŠ/—p”0ýS _¦•øZc 8ü.ëFÍûïÌHÇ‘ ³å•øï 04W#= oQvé0ÖŠ(¡9xü«ò cÆȆËVC6³Û/ÜÁøí ¤0n$8´Ý5çàsÞ@Y1öËSC+Ì–ÿ=×ÓºÚ„ÝÒwúåÛûé¾½//÷õ©íXÙÃŽ­R÷„%gMzýœxjŒ—·‘h¶yhì馯UŽ= i8ì#Ï.~žº4J0o™ÐÝøþ*P-Åç§€xÄ‹7T6@¦˪ · “”róÛ¬ø½×qÅï5œìÜÍB~–M .F¾/Á½ÂùçðLAÙi ó¶uÕ¢42( GÆ*rN™³+éŠì‘—nkxÉíOÆï~ —9xl:¸w A›»hÃ*è±Ø~á’)0 #ïŠuå„oØE¶£3æÛ•cÞq)ÜŒ¥GP´šag¡Æ{öcFæ_¼9JEo=k ×\-3^æ©«èën.…:¯[zÁø¦Y9KÄ“¢·),òiõŸ0ÆêhA Ÿ»ÚÄ¢ tæÄ%»õS•бÊ5gBWºcý×™ãUåØ Cýz<Ú8z.œ9h¸<æ: •_0F¤ë¬ ·ŠW ¹Qk “†5ÅKÎy}ñós¡ì=„N\Âçó@ÄON¾ÿ™ÚE¿’Ûc!Äù꣦ñ€-§LÒÅã™{:¦â’±2‡•æ\“JþÞs½]YT<?òÇVä*ë;ª1F§Z‰l5¥íéÀÄ2ûâbù»¿Ì5çøBsvnU:#6—²¦TY£›&*t®™­+å²åRÞÁMnéu®Ò ¦ë$ÇüÃÊÎÒWFåÁûé~ýËŸþ¯ˆÒ®¿8Jk©O£^úÊ3¶–ö!£â·bã,ë¦Ò¼}häñÕÈŸÑ'ÓZ|ð„kMŸ¶"¦g¢Ü;U>ýeqÚ¹WŽœ°åáe¡Ã ha.Ž4FlÃtÂ?èB‡uá£g¸Úãâp»ؓ=a ¨·Z¼Óeq‹»¬€‹Ÿû0‡x™joB³¢MËtº¾„ZuÈïÅf.1¶†dm²&lð89¾·G\Xm»ÐõˆhÀy”m9;pöŒ!°ÓoACõñøãC&Ü‘²úˆ„4„ž•eiî‘Râ²e6]Glù”#Þ¿ÌÒrÞן헢ärBµ›9&,áQpaEÄ8Äà ®CÍN•½2B¹ð79 |̸‰È½L]{òg#>öa™¸ÐJ£ÎƒÙÀ&,Ù„#â$.ô´ŠG6ˆhàF@T˜†e˜.vCÑeyúqòȵ&„µº~jp" q1ölñÅb¤mâÑpNºNCÇíI¸¯“¹tø~¯Äˆgh9VŒU\Ä“®½-spÅ› x’‹}\L‡„ sØ6oaëÒ #ÉYKHÝ" a,kGÝÞ¡È&‹s üÞ5 6àE,+‘ ŸÉ5C9‚d¯*nNºÉ¤‡Ó ÓCã0Š"è‡Æt3ÝÊ0Ž#ÜEöUÛÕKCIK0 «Â¥Q—îÂZ+– _Í!tÒHzdLᎽëÝÎ)¼+,TdM$¤X­à“YS_à¾>çP°ícÃéfŸ‚© ÉcÍ·ræÀÓt]\`g%Ó8x28jaeÙ·Xfо`x:‡Ã€U|lÄ;ì  VëÆ)„@vˆÝ[ê⨶wa8Ž;Ác\!tWCà“³ ü¨v±£hÅŽs!†—Û…ŽþGîÐ92#Ã|Ká³;ö\yñ½½×žxUKC x#Ní¼ØÀ\w‰óUG¹»ÿÙ€˜.örä‡F w ¦b×=¸´‚,;yD,ÎǸ ì®è‡ž·ÏYLØŠ-€ ø²Œ…ÜqØuW< ¯v>!lUç«ãÕ7cÏÄp¡ç²â„N\G–±pÈ;1„káˆoY²ˆÔ'qò0öd“YVë®/¯ˆÓ|£%Pâ£0/±2®ƒ¹°݃BϧóÑv€ÞGHȲƒÕKn]÷VJ@r!´ÝtÂqù¹©ä ±—! š7Ê—±úÆÍ'§ kªº=3Öœ'ùåí$+—pQðõÄB“wrúµh×í×<ö«>®£°}QSÊK¿ÛËiV¨=ôÀ U ;aõ¨Šaªü‚¡ 2`,ùg…akÂ{vq:ML;JÅ£PjçËþŒß{¾† ýDoJÔª bŇ9À¦ ŸCp„PÃBK&Ž ªeN}*½Ð]—&œ ¸ÂWÁ°’·ÐLsígͯm;&q[ñó³ì–ã_Æt÷ϪwFOèAD|LèÚ\ŽC®‡5È1;ÇÄῌñJ­F‚_LBÙP®;ëÐ7[<»Cµ3âÎÜÙ[w¥ø2+”Øçÿz8…}y…ÿ×ݳ!,§lÊ:›g6Ëc 3M’ݪ–µö\Mé‡çû¶OÁTù²)ßûvß[ý¶õµí¿9"^'/žï©o´Gß7ÇäË#õåáûÍAýòPyüsU|s«¼º~¾¹ª^\k//Ào.Ë—ëË+ø›ëúåÕþðRax©\|£†|£²¼To^(Bß(M5qð…0Ùš áJ¼Ä}8\èÉÛ¿p_ïÁvÃÛç®ØÔW\äA¸p褮‘‹ã‡r­™öcÎü.‡öüƒ“úå©þêüÿæ®øî^yq}s[}s³½¸__—/oÖ—wð7÷õ7wû -àá•rñR y¡±ð -î *G³ŒßÔü¸Ýæ fv~ü+Û¯súþÛ·óÿr¥|³ª^®À—kõ›uýr|³[¾1G^˜.ß9ßD/Œ§—fÖ·&ÙKóí¥¡÷Õ(ü΀|ei¾2J¿3`_šºßšÅ/MèW¶öK³ü« ÿ±ÿÊ1ð½á…»áµgâ¥㥻ã[×ÈK7ÊK‡ËKçLe¨9rÐ3~ç2á݉ûGØœ·À5v’‹yŸM°¨ºÃe\Š 2Îá¼’¿ ExÇ|ψó™pL¦{§rô“ª «4xŒCìÐ)áŸÚ%¾`2e ñÐwaõSÌ=q‹s€õ ¿bþ1ƒ_à4[Q¯ ; T9­He±<€È@öá›1YUÄÿÏÜ»­Ú¶-ÙB_0ÿa¾ú²©÷Ëã9 ”)Š "r™Þ`ì‡ãߥDmcô¨sCÎLMîµ2v­·ÞZ½D(TñÔ¬4Þ«áïÄY«,Œ ö³DéÒv") A4 +lO?;—½®¬Þˆ‰Ê¶y$H‘TÔV³]`›<« ÃbhÅû0h.6¯`&FH‡À…u½±eø8›“´2£Ï\Œ1LøÙNÖ¿I‚ÃoßÁåÓV ×áÈ»Tœ–'ŒŠ–Öã—òï»´21v3‰:¶õ³Šr´ Ëb5<äO`Ú&JXXã~n\xH…\å¡ðÇ×ûìQgâ >KJ£*/ ±å¯÷e• ž IFç½á“¥Ö£W 1hC¨±­Z&¡†o|crFͳÖƒÒ“• jXT×ß«/js5B“_‚¹ÎC3Å/bZ‚o^<Ý)žë™V0±’ªŸ!Øt5#ñTº÷XO«=C2ÚÉËvK×V! &U#ùõ¨¦‰¨ÜLÖY(D7ìD»ÏÄÕ¯j±xööãW÷;hP=Ð pÎò ×Ó…‚©…í“ÅH½©m|±5¬gŽ;å g©‡f *ðˆð ®Ò0ø”´÷ <†¸|Rf˜^ÃTÀªä+0#^ɘö¦—jÂò%â®–¿­ó÷k)èR’n$ÂRR1–šqÐ’ÞɬXí¢r¦0ðs"ÕJ²@¬6;ùð‡ «îªÛ"ÿ.0‘s³S¾ÏLkN¯yTBQP·?WE†ôÞªãÅ3ö±%˵ó470†v÷ó&˜嬒p¯å (Þlžéa cHȨ́eáö÷‚ó!ZW4+<ÙNc@„‹¡tç±ËwÔ×½sÎg\|zó3 ÒŽò9ád€ìÓ¼$5\ìxó"qJ,O›=‚ìÄ'ñ‚eV’IõÖÏš›¤¡º—Ø(×héý>\É\Ζ½Í5Ô‚VmÑ»µå%+Å’?Áa—žÅHôä6dPúÍîØØ×$ìU¢ ©ÊýÛJ˜•Úm¯@Šm­"¨Ó\ß‹É&®}Y¡BÞÀ6²@~ðõc¾À⹎¼FÃ„â… ë“é¨}~¿øþt¼0F²œoPøßçpå|c×k‹mPEÞ„Ü« õu›±—MÜ©þ‘´oŠ5d9‰ËI‚r&1¾_ö©w3Á pSö l%Ð`í8‘ëå8à$Ù±a\á>aë[JA<¶‰X3‘½ï‚"ÐR,—‘z~î±SYfK$zâ#œ¨$ê§ÚK¬Óëm’Kj¾-AP $ßÎPïNZá?ÙïÕ ‘)3•‘`J™­²ùf±#}&_‚ì5Ô]³a”ãc»@£"C"ÎX^ìòþ¿,…•¤öNä˜~òS ؽãûS{Œ,^T«Û> QËv0´ ñpù "a(. éÔ°Ç.L˜ÕzhÚ™Ó`« p¼Æ?$áÀiÄólbö#Óh℘}d ÏÃX©‚Ç# C¦'sÌü7ã]I¬ìŒÔ»S&÷2¾~¤Üþ~ØÀCâ:¸€ä%©³±4¸yÂÜÓW¢aŠô–äEÖÏ\ÔgYs €wÍjÆ¥Q:³§es^jE(7/Ïn•E¡TÎR íÙæMûD‚|°h¹ƒ2‘>Ùª•¿ôõ7D -kB‡pÿ ùeõíù•ö$ô^QaAÂv;¦©ì¼{£ ¢ßþ|úDÍ&TÎR“„¢³‘ËF±|²¡]`˜ž¢õaL*0W­m^ØŒA%«Ô,½‡´°-(À‚§Ã%é>VJð<ìÍœƒžU ŽÄeÙYͳ‹lÕ~»@% _ÂVûËVi_™¬¦•{`'µK FÉ¥ ä´Ïœa‰we•0»Œˆ6ãÇd¥Ä*{ûóª®o!øðá5—„ØHxˆÓŠø7Þ¡Ü6háÚYõaî”\Aà`̈£âžÞ/HgYÔ0ú´°à`v0p–àbõR»+vÁlNž¡•j¤‹µ2¾­ä~™M€íüÒràƒºÐY}`8ºF|Š´ °º¥ô2í°¬l{Q·k?K“6C·Šêƒ²Q“{$\[fÀDU$œ !½|1S_îäA[aD±N•YÑÆ ÔD”Þ´C¡ üMÛÌ"NW‰AUä·«Ûi‘TÃ@fˆœ,xÚØPË™ÎÓ P°ÖQÖ¦Ž8pwÍ]ÆLÏ®WÊã00é8BÚ¨¤7Ò>½«Î2NÖ„…ªöÄ_‡¸FüéX}Ö7Ñ*‘;÷G 6»€2øn¸ú·fKÕ¡ªß¨™d3áÑÖ׆ `}†#ihü}ý ¢à1¿RæbÒ¾àùÂ2Nh†·ª%”}|~¸‚rž ë6í낌äÛuúëÚÞ†¿>±Çy`=Íàca¾Ze¼M¼ƒÓ‚¬8E«Š#†ÚS\«Ï ²@ùõw(—U«2+ŠÍD11\„ÛòlQ¶°­"ßù”Ç ©5<ÅÉ §öÀë]B¬mÏçùébø¥¯¯l„Å+=è¨Ëå¾nvDço1Ú¹2$p&«²ðYˆkí+4ðÒµ}ì€mŒˆ<Šnkxõ!ªÍÐgOQd¶ÁŸ®N¯Ìé—AƒO¬·AÍ1°9¬cw LdÔ ?–:Ì¢Ö~ª+8Ôî«es8ˆ˜«Š/…}p—‚Iȸ$Wí7Ñ^•§2 ¢Á`ø'jô°nX©ò`¹3(uäTð^Øm+B`£³ $_>šÑs-h}öC}Ñ`kZ,ü 0%; £y%p157³Ÿ€½I4²í!͹ C³Þ¸=oC éò¶ÌšÀ wøœü ö Ö¤ŸÄΤ* hëb{«ê%L|²ƒ&E<ªf&¤T+±‰5ל˰2eôt®HÄm¼\`(0Š A–³Ñ¦ìV¡–¨Ÿ5ºÂ.¹üt­“>–ênÏÚqŸxÚÝ8à<-d$é”ÄUë’6a©{˜ÈÌ×'‹}%5ÇêwjJÕ§¬¼ –Œ|6ñk‰îKGˆ {ÉGŽ}i ¨¥§†þ­\~¹æŠ;°ÂÎ'7¦Ù`³Ldn–NmEñO¶‚&BÀõÉA5³cÈ™Ë äôƧ™• ýÞɼ¡°„ü(vnì©iÐ(ï$£Õ Ü›‡äãÌ0óyРf{¶…((Zƒðб¾®1’`aM’5hUo >ˆXŸÆC!BÙ{ ŸµŸ2 ô Am jP­çmß—y2djâüØPˆEÔ¶®¿ö7DÂtÒ‚ ÉÿÕX äm‚´Ÿ›¸½&3ø®í‚âÒ ïl Ÿ Fªû€ n/ùäLa¹j™\0ˆÙضŒéê–‹iŽ4ë{>šÛÁ@¹xëkÛë!&{šœ ¬= KÖ5G6[ÞÈ{Í…<ød ›àŒ6c&*$Áu}̤|yN`¨:QÒ]èV Ì2Ùš?riy=î–†y;öh¹q…À¿Qa[V¾çÏÀ²Ö‹ûj„ûã@’7o»wŠ••DÙi Ûß‹ Q!Ä8‚¤è†Rˆ‹çÉAö(Ó`<¨"‘ŽÆî‘£(ð(5tBf=Pä8B//h–#2Q( LÃÖ}(šrÄW`3Ý4ԾϡRµÈ‚ä@êmíLÔOËú e¸/Þº:2#7&jDÅ­¯©gÌ^,@¶i°;êIþل±€; Å"}5”¸únm¥œl'& ˆ·XI` 3án©R*½î½1Ûf¡T\M,PæS®©É@dös!“%Aƒ÷æd?Ûî`³nšóõË®mZšÙÓÄWõ\\ýÇ.` 7­Œ¥y€ÄËŠâõ`…Ø[€P¡yÉ—ö`ÇØ©Ìs3à2ñ÷j€fÏ â¶*Jº¼yKRÝÌÏf¢â»Mà f¼…"iúIÕ_”G¸ Óú™ù\‰•š5…ry|&6" T_+ÁdGr9íú.—G–¤lwÀþ|6÷3 š­/±N=XìÓÀÝÚÁÿµ^Òzý¯<ú±JŒõÙî ›±ž]P`ýè ²»•?'òhßl*㬾A(V¬Ì;gFê"V’Öì˜øÅ²¡„±êŠï/ÌVŽlvO0ÍùÑÛë™+¡lLTê߆»Óþš¼*§ÒóÐ(_¶MX¶AÇʼ¬iš[¼ Õßuͧ˜˜IÈèu¾H†i;¹j‡ø’)Èú©SL. mÛ­0Ç£dc¦ƒÏmÞH&µ¦ÁŒ3›”­± {kGåý‰±(¶Á©3ÈöÞ+¼ I ÈC:g Ž£<ˆ™P«Ÿºë7þ<Œ&ñA;!ãoÈ>¢Ô+ I†¹ÑÿʰIv’žäº†#’ ²¹›åž'Ùz'i#IÍZrÕ#‹ ü¶&,CF!ÏBž‘LJ-ÀÒÔ¼<<ëî¯ácÄZ½ƒ‘-K«ÃN´„n&iÐÆkòYî®âO‚¡^žîa»…­ƒ|›­Å|Ìì Àù1[Ò`ÄÜy’ÏÈ7AD ¤/ 6,»áÇaãåƒaF'pƒbfpénB²»2yYâÉ4çtD¾‹Xu’ÜlŠüƒžp®Š,ªhw,–ªÑ[W¬X'-kã%K ¢Ä+=Ƈ“,àThŸd:‘hln‹µ¡Ù>ì8PšŒ‰I´4߆%¸Û ®õp$‚­Î¢²îùÉIaà † 5wCðZçG r%W•™ŽÏ2«âGmTË&Ëdq/)Ïuh-ã–˜06ŽË¢ZaЕ¢¥]?Lñ|Xþ¸k«Šo#ª"a“(™Nÿ–µyx£v(+V&–ð òÈA $ï"SøR‚|UÜ­È.@ÜA\±ÜºóòX&;4‚ruA;œ E6ƒêj/>B0¿ ÂN“éT'!ìo %h4³ž…F¢Nv»0r°EÏcñ³\ŸW'5\]÷v5’ÓKqžÙr¸\IO®Ó±Th¾Œ,ö[Õ‘b«yæ¹}‹•ƒ· ÀµÖñ¾#> 6 éS;:Ù­í¼‡e%/šK.¥e•œ¼L‚ÙPUÃôüea«SšNÏûµRt[鬴?°%â¨TÚ` ü¿á×àÊGèR›`LÞ”èL›pþsw¦œôƒq€j71¢4I%÷Ú„Q já£Ó°áDE˜Ç‚í#Y•1˜w«Šy>pŸÈvÍŠŒäæÒÙùSd¤aþ3/ÀÛxRRdd§õ ±ZŸëøM¬Y(´Ò7¹r±?·Ó2d5¸íL§GåVòR3Ú€Œâªˆ&¢´S‚ùd¸3Ó^¡°ÜŠ  ‚¥µŽª Éw îІ+΋Wu÷ °lÓ^É­ù/3l¹Ö$˜Àƒs¥'…$Ê,Y)^[d=¬¨ 1}¶ÁÛ'Î3 ¤"4œIŠh"”EVÔƒ§˜J¢ä©òƒ-šµò´‘M ’u»ä0¤ÿ‡èÇ©:w3™ü×É®@Ê-U€¿Á¤æ`VBèÆqÈåIÖê„Òê¢t~g7Ðà\û\`?#áL>Ì”dl[B˜ ÜåzH˽x<0ËD Â(z~EAÐr Ï%1'0‹zzÛø(KAÂ8JAâ5Ìè™,•´'V2$ÐÔ©nA²Š3ëPÔ!Oæ5Sx¬M¹à³Ö£¶õ 6*Å«6Ýܾy—e)²ôGÙ7–fɤ3L•u’e/Zp C VœõÌØ¶“‚X…(pL‘bÖ`V­ÕP†!¤ýÁ?Ê(fíI¢ÑB¢ŽF¿˜ÀS"¡³š ìž¶Odé|ÏçYŸE¸³¬Ôéìba³.¯(×¼ˆ7â•ÓäÎ ]tóHëð––Þ€õ°àDYiºÇ›FçDÕ òœfY¯Å\Ç—µºœø5Û!U<Àµg‰Ü"^JÖ»/}1¡Hú¤³Yxi—ÒõEÂä+5ó>± åË«ó,î¤7òëš-îxg(ì7ž¼•ÈfŽ@r›çå § § IИ‹¢ùÊŵ0üB.à•7r C6bÈ\ YŽ!ò y–!#3fo†LϘzá†\Ó•XC®kÈŠ½hß©¶%÷ÊÞ ™¾'øÂ¾pßYÉsÌvyÑuÈ·™Ù1‹;d|ÇÜð <äœGäôÇQÞ¯ÜøGrîCvþ…ɲþ/ú¡–@¨;è\• BÕƒP!ÒRub…†«šC(ü)D„j¡òÄE£â¢gj_*EP}#Pé¸êyÚ¡JÈEQ$T¹è”\4Mý“P)墪)°J-œK¨úêÃÄR2æL¨Msѱ 5oBuœ‹’N¨ºêóÄR>ÕŸP(Ò u‡b…¢«šQ |j$]õ”Bí¥w‘¦‹žS¨ýhD]Ô¤Bå©P£ê¢gj_…*Y¡žV¨¼•þhtÅÚ^¡X¬vQ •ÈBͲ‹¾Y¨…‰¦]ôÕ"-¶Pµí¦ðªÁ…ºqW¹@.T®»¨Ü…Šx¡vÞUg/Ôä Ôû.JUÀ@?ð¢5êF †µÃX1ÔP Õ#YÆP¿ñ¢õxÑ… $CµÉ‹2e¨aê]†Ú˜¡ŠæWÅÍ/ž{XW#¡ÎXÑó¢þyQ 4E/ú£¡Vi¨jzQ@ÅRCUÕP5Tk u]/°‘^l¨,{S¡ kCmÛ‹n¨™ªëÆB¼‘fo¨î{^ÙÈ‘©]ZônÖŠP-t÷-á—Ö8§”ñf-O”Ö›}Þ$o•ªµ*s‹Àz‘Ò›ØÁ ž×þýü·¡xßi"Ÿ?~C) É'¢J@i ¨/šÌ…RCRâîMDØ ©=! ($ …䢆3–.䦀u¡L…ôªˆR¶BrWD»PÆbzYHD»ÖB‚[H…»Ðæ.»Œ÷B’_H¼PCšaHH¼qšã‘'/DË’Ò7Y»5ª§5@8hŠ@Ý5d«F¼Ö 6æË†ÌÚ+ 7dìÜÞ 8ä ‡ì☈|á,ìæ :dM‡üê‰r¶Cv÷… ~a‡üò‹òÖ#†û… çC†ý…2÷/ÿPࢪ „Š¡zA¨spÑD¸è'J U†PÁ!Ôzˆu!B ‰Xmâ¢LqQ±ô..Ú7Hp#”æUGÑ¡œt¤;}•¨~e=Ü›§£'—Ÿ ¹š–iU§¬z7òV4Ö°mî Õ\,€|/¿`–TX –^žá‚$Â6¦*ÀF‹½©Tcµ4ýêóqón+öO=†§N´Òž¬xùQÂ%ÑÝXr”öXŽ“Á•¦»?D®íyk)€\è}¥°xÖ9:)†3\}Y(]{ ³&ÏÎÚ×(8Z¸ƒ„bºMEÚƒ¢v–•è¿;½Tƒi´Æ¹À.…ÅÖÎÅÀ ÜDmе¬²dm3¨¬J½*=õn®×/q¤RØÞ¯ ¡3ô“§ptT†ªÛ´ ì,óªl¡¯…½-Yê>  L½±ê"óô çZ=lç…×uPsþ͘Ê-YBVÖ g‚'Ûs£¯#+lÁçÚç²Ï³>Y¨Tº°~#9ó{g’í¦ù£hÆO‘ ríY:éyVá|”FæcŒcdlŸ“ÍÊm„™=®þÙ†0¸P¨r_«,žÐƒ³¼@»ÖÏ1)Ø0àU£»£À(ñ$P0ÈœeÇÂŽä[‹dêV •ö ^m}x/÷#ÃÚœ#Þ'ðÈ:¥€‚ýƒZØ gž«ÍžÉ'Ù³`È‚÷ýб9Ø|%[¼Yv2ûðý¦{i­“$c‚fãa•™&ò¦–ag¯… uh³¨ÒÇò¯¯N>où-x\x#½¶¢`âïAÿké V ãù/ÂÞ$ô°T4–sôawïnœÙŸx„×’ƒ¸Ö¼‚zƒÕ/ †ä6º:iÒ;çØM‚ÜôŸˆFÑÒퟨ¨K36eìÙ$ßK/ׇ¼ K°Åk‚Fz]€JÛ@™]7èî»-Êgý± B,.ÍÒºgê&»Áù5ú:pºß{O·Vѕм¡@8¸€&-AÅ*0ÑÊ,Vœ· aÕË¢-Y% ‹;äJj®gÄUlà¾4ˆÎT¤iJäËk­¹º$SQä5_#/ý”cÐnßþaÀí¹WÉ¿^Í'=t瀨ÆëŒÄž;»’Q/hZ×ÐÜ×÷y¡çôƒN<•´îjZï7p~LQÄN‘º¨Î‡¦?i ´gÈñþë?äÍ- &¶í¼Ÿ¦A–&ìe¨Âà+8kx4 …mˆr – •Å%„¬†äÞ€lv™ÐҞϩñˆ$®Ó˜WœÄO»ÙTIäÖ@ðœ(ä¥aë¦IØŽ¯`‚£½9w¬A”p«vôÀÍHݾlt"´Þ=C¾ª`ÖL0×k‘ûD‚ZRÚÔ5×t8.£§Z n0¶>? äYF!“Z¦ÚH~á°žX 6r7Å´M@©:U´ìLÎ|}$h‚—Ê#r­>m¨VG”TFSJ.¢~,A+,˜ˆ]u-S6¥¶CJ|ïweBœdY|ʬ^ ’NiK¿k9cdf½+ Ñyà/èBŒ(>ªšjuŽ%2)k¡B6O_P-ñ“ð_‚ü°r<‘#$°ª yãJ¢Û›KÓ‰ÂaÝ0+ᔣëtS}ÖM¡ "Úå«L/F•ǘ ÊouÝ€„–Ÿ¼WÃ[+½¼Rš2FõÑ×Ö÷jŸm¶6Zù| §9¹c? ž«Rj­+L”îz\ïñù„ »M·òµZó ƒÒ“½Ï,BRˆ‘1a¥,…,WŽ¿S…ÈÞ~¡ÏeØË܈hyÌ¥òSTë­ФUh£ÝÔ¹WˆŒ¾!±•Åfß” @ÊÓàwàßÛj˜—‹cœæm^Ä鍿.%EÊœï‹Ú±†pÔ§…L)IW^TeF?1ÇÒð…¯Ÿ\Þ¶œ‘•]€ü]aÕ.ö¦ÃiµÆº®¡l {Q• hC­Ú‹®íE7TË •uCÞ@®÷¢ì{Sõ‚/ÚÂq¨X|Q7•CÍ䋾òE‹9TmžC5èP7ú¢1}Ñ£•«¿©\óHD´ún›²®¸¤ÍNßï+Òs¹ò£4³d”~2lcOfAÅr3É^Y´åªÔš# 3åüºIœ‚Ì, 3N ¦Q5ó¹¦)jåGKÞp›ÐjSdV&k|K§·“"‚ÄMz^g„ ²™¤Å6ìPªÂH¼ ‹ J|S«2£•·µYôàAІ Â,¤}Ë%ìí>žnk˜«yMC ðiçY˜ÒÉ9p¨ÀKm˜B³”I *y,¨H¸Ø‚ÓD¯x°’…7Úð «Ú¤îcWÿlB6˜‰ÞÖ ªX¾L5å—¹ª­Tà…±ÀJEP),Ì…@8)\¨ïh¹¼ÜɘŠ;Ôà€ãQã©N€z)?x€Ëîvº˜´î`ŒÕ†oáñФàÔèÙ «ü'‹SyÃ6cEb=£ËD°kÏ^‡Æs÷(v:-îùÑþd½üR «ha½íR› ëxaÅïR +‰—šcXŸì†G³²ç.„È”»áû¬‰e¼Î|®ŸŽ}u ™€ña.Q)$¢¿Uµc¾¶zÔÉ|bð°N—Î…{QµB9½Íã ž…™Ïàe¡wY}çìÀãYmQj?@§O! Ú“×ફ%\Š“a!3,yÞË£©T—k+yc–ùÕ8å}<&ˆû3f¢G>Öv¿NÕa-Q^ÅZ!ÄMþP_*Üq@ý\+Dc9~ߺËrê¹Vödqÿ“A~¤†É è¤Sébckàû/xü<•HXÈt}¢Íƒ ¨¬ÅÆ(¨¶¯«›Jl,8m©>™åi¸£!ÕØÌÕ KµnóâÑ`.®–0vÅ—‘ê>)|'A’¯µeÆçðJ>‘ï Ý Ã²jNH#,¨êã.Rš{ؤÔ‡£Í-KË*]jy®”ÒŽeŸÝ”š0î´½52¸æ&*`5Ñ(ìûhõ£"áKˆˆK&&ò °I5Š®I-yivò'4T]í8DfXB }ªYIƒ“;€^€¼nÊ©ü çÀZªrÄy͹grŸ|²hÿMw£âœCÇÚv?Õ‚d_‡V_GÉâË0<Õà!"s‚ЮÕœÃêÜYƯÿ°ò¶ªëäĹô¢9¬Ñ8—ðÀ;i` h°ùXWކ wÝÙÙŠ•¶6ITq“ w]iªbƒ ñºÒ¶5ˆÄž1  N¨ƒÏ.AU!Âtä4 ¢î\„èÝN—5QzŒ^Õ§æFš¯¿E…•ˆ](üÚ¸.g=S÷ÅÔ]o Û"µ*¨8„È›µ¾£WÝãaó;ü˦>DsXAÛÔ!6!a56L$Œ:{²ƒZ¬5:×&¾L©©ã¦ûBê28ùÙTŠËó¹,œ‰ø4ÏUҠ†‘~G9àÂbH6Ø_ÁJ2 GÃfM ³ fMϳ¾R¬,(®Ý*¬2¾|µ‹{Á¨BĘü+ÀkÖÛIßÅAý(’}ÅÆØE—wäw¡ÍÜ‚ ðsÓp«®•DÅO!$>¦µe$EÂÂ.CjÑ蜿Í0ü“¯ÿ •ú°ñå%,•êÅ)¬ƒ ì<ƒmôùØ·›Þ>”w$×ñ të² !O%èÀѤm˜s‚ÎE²x¦y°† é[Y:Î#Af¶áȧXXØi]!Á¼± é8tzKädÃJÐn¾ã‰ê_#ÁÃ$Â4Ø eÁYßNvþ‘^çn…_Ö¨DŒK¿ªnÕhܪ8ØEGi —Í‚/žž~òpuž×p:·uÛñ’“¦x0´ ÁÊôïtÇ+®Ø ¤íGƹ’2,Áý˜B¯l¹‚¬ŠQiyþçe×3„(—¸äqŽf3—Ì'Ì’Â|ê’{]ò´0£»doyb˜O›>ù+ð蜂i©X»&ŸÀÛ.ÿ'=ähT}þ¸ŽÀp¬¾k*Ç­Ü0ØX_•`jø²öªjÌW$b£Ò)B¾ÌðvB!D=Go‹ŸÝ)]'†'ûïóöóÇuއ«ÁÛÊAŒ 0¥"G@c!”Eeç ¤$w0.àü ÛF=Îâ”ø5\’çý'œß'0Ðdæ‡z(ëV̰9èü­³2ÊŒU¦_¢´¶#›|-DZ†tYwÑ4´;'f¤2n ©(Á5³‹G2ŸÜɲZ/q¨ìlêö¤qX'š8Ü“‡[wTo "«™þž€òñô“­- Ä2Öº?nÛr\Í?Ã'øG6‰ >¨“\8è|Ô@IÔd[ ’-“0¥bL¿"®¨Úà.Ó ÒNÒzÖ“ rZîA«áì †R²_ë w³ŽÁcJ¾c>ѧ xv›aiþ[X¡å6OgP’tíq žh\…©Âeò°(k_0 øC”¸€*.ŒªÀ:þa~Qî_ZOtÛÝ(©¿Å` ¢›*¸Û]¯ …¥9í\Œ¬«Ì˜Î ¸…Ò¤šé4@‹*í™å–J1b×oa+!l:ÜëëïÛÍç[Ê&gÑjú»•7\£¿®ç¸…Ê™÷;@ITê³§“‚UL‹ƒô$ÑÜÚÂ@Õ-ªÈëæH øuÇ w×xþ¾gŸó-YÿDx7–ÔfrÖ.\À—³ŽŒßÛ°OŒ¹ŽÝÀ„'IËŽ¸±’Þ"Û £â0ŒA@¿ CüXÖÙ:öÞ:ˆ°ÒÆÞžé:i6ŽÂc²˜‹‡}ö¤¿·óÆålžbÞNÏàw°Êa5C\§ÀiÑL“6½†›¥¦’liÑÔÿL2ÝÜù²µ!©T<Ù¶Zª >ïñp=æÒ\ ·ÅGHLúözÄ{â´D÷ üœ©.§¯·“Úìñ¨€d 1e!öØÈÙŠ¢E')Uý Êú­¬j(ÁеFº®r(´³€Š£?6u4“hP?ò°”&MÜ´ŠÒ ¦ÚÇA*?/×—¯•ý • 5pL­Î‹^«ðJSoU‰„A-.ï7} ªÂ™ÝøÊ„ÿ CèqÈ©;9ëÛÐS_G²ÁŽ!ÂüÈs§Ó9 ©Â²Ï„Ÿì?ëQÝß'õcÆ‹až !ü>ù¨‘ÆÂÞ”ïzãH¢¼kë€È©§›[«`ûXtˆ»\¤‹c=“Oî’¿³ë+#ŒWÊ|?2,ô#>,>;(ð‘x8‡†+y¨éÞky˜R‹+c'ט¥ëÚarlA[³ÜÔÑhÍܲªƒ‡äØ´°f ÒŒÒäŒK{‚íÐ/Ý‹áL+àöq‘Qü±à^¬XG€ð€0w¡<’a¼kÐüÃwð,ÿ¾•·?F­KJáô“Ô i¢À®;ŠÍëÝ@TR“+ö\çšôƒFYL‚åÛjTM ºÀÊÁÒ†ˆ` Û_ë†Òol¯ÿ†¥Þ°(«Ùâ¢ûëBg öV~W⿵ÂÆÁ÷&«ÎM´ˆäh«mßš«ô{³pÖåË_þ[a˜Óçß ?…Q‘œT(=iT]ä¬"é«›HV(¨‰oÝdº"E¯‹øW v—{— …Ê.¢f¡Z ”v‘T»È¯…BmQ·@.”Š»ÊÊÅt¡X]¬kJà…by±°^(ÂÈõ]¤ý.2€¡`àE\0" % uÃP1–L¼È+^¤CÑÆPà1ƒ e#¯“±e(\‰\†‚˜¡tæEf3”伈w^„>CQÐ@>ô"5ºÜn;»²ÕœQ®_ã2yˆ?’½bÀ^Ý—bà“Z0¶µ 5Ú"ÏÆsµŸKÕ¨½P¶Ù™3ªøv°í4[&eW8Êþýl.˜÷ÁtŸuw|s·ðê±™+n³NGΜÚEç:é7Üz} 梦vw1³PøUV Ɔý¼´Îð~®Tl7°IL=Ù}1Û4ýîfndëv>îÜÊ¢B½ªÐ‡ûŒWc‰JÐøÙøLbl¶ƒ:ÙŒVLÔáïÄIíobžÌäÆ]¹·uãŠê¦g{CUnÔŽ`ú¤³osQD/'å(T;R[@ òœ=͑Ă&ölC*U¬•|Ñ‚gËRY¬hüÎç²’až¬cÒ*ºá©BsЖª=ØaöG˜]p³“‡,A•ÿFps­KYEúºÁ»f\3 PUËZo$Ÿô1+$XL/q X‚Ö‰• û»ífÊ&À’i#^]‚ÌsÛñ›_Fä¶™FµÙ†€ê’pMÜw¥´%j $ ³šE¨g£â¥ïÏà¢]YAÉÅÁù*­ÉGæ‹k¨LHðH¸ALU‚­±E­Ë/PQ(¶%ñª~¾åŸsö–£R)iõ +~¤U[&âIs|¿–—Û[Ž”é&Ià2áUšåA´4Ûïc¢:‡_ #O_k ôZ3äè7¬ ³Ò> g¯jvP«CBéLÐíN·4}(®&ÿ Ó¾­¸ò|î§57cf ¬ÇºDGÕ¼á2>Œêù#ÍHõp)[˜Ðp~ö,DÑËæéÂ+hrP:ªÙÔ•3ÙömŠs¤Ô_¥g—žÞ*kˆîT¬ŸM”¬VȰӗí î ¤g:ÈÛ&øð¤ÆCQ2Ú/.Ђ¬?H (d[ ;2¨‡µ~vÛá=Ó¨F¿,­‰ ÏTÉÒqžvÉÀµOÔ)¾š)»‘U[„Ð •âäi¬‡ Ø/ü/àkX §‹7ÿK9ƒ\ëáW2ãÙnå.8Iü4'¡Å¥lU]hbhjEZI Mm (AÓmÒ~Iä:ƒ™ý8éǦrÔ5]»¤vï9`œ-^Ë  ÒU¾nJòõuRþ©ªOúÿµ\¾ýÃH1oÀÏWŒGˆ¹*‚…êa‘ÌØE‘Ì6kf[O&˜%"+qG°€ß@B°Á˜@gÁåôêÔÝûgr÷W|×JP:”d)x ’ºôä¯fs ÏGǽmGëXèîjŽBpwEM‰š{í¥…©'܃(î»—æã¶æ ÿ>80ý[YA°Ø'%‹Î\Û8 ¸9ØÙ4ï_‰h9‚©µ4¸Øuu7]ô-A'ÀtÞlTo¾îßÁ€CÈð \üˆü©ÇׇëEø"ÂWvy½áP¸ šÛ‹c0l/C|ù2%«3ßþÌ<^*-ë7Câ2|Âöí>A‘o«Øç늮—u4ZpÃu9Z‡¬âÔ­|怗ôT¯óïUÞóã‹üžÁ:°X-(aêOŪ$]“Êš ›ŒŠé@ßÅ“@a×|«Ÿ bPèÙ A~ Éâ\aãÖd' é $|‘:B÷Þzæªû[ȃ+˜‡è½â¤¼2Ÿø·K.ÓÑ]ÅéN¸0ƒöPq¹IŸ+ËÏ¿r²² C:ØE¤¢OAo¥Åò½×%Œ•(;†F‚p/Š FlòÀAe®/p šQìSí¿ˆXÊ&BÂa‘Òµè<þî’ˆ`ɃÃU›,›o¶Ìq0[Z…3ÀpЗ/¥Î;RÉ\>4ž Èߨ]Ž#ÌØj,_°h1Š'Dü¼Cƒ.(¢ â(À&]pLÌSˆŽº ©úfÑž¢ŽÕuYdhÀÒ½#!òªNXƒ|„µ£Ç8­5×!i I{ˆ|ÞÅg”WD.ª[©^‚•Âd+™Á⢞IíçÀ\S ¾Xƒ_7‹é+Wùð]/øãÇU[8T!~S,þÀªò PÄ⫲‚e*Û5ÚAfZG Ð[¨®p-„É#ð2D9ý3²Ë‘JÇ‘×z;*%KhÝЗ¹X…ÑÿnÔ1qP¸JˆÏŒ°þFlN›ñD•-Ï–kµ:å/ƒ|ˆn VñW‚wÛbožsoóÎseóΑÌÓР“[ö zõ#|²^47h–¹’?pÉ (ªZ›®ì 2×Z6ä\˜pÓù˜â窅d¹ýF;k„dA‹2ùíh“â°ü.ÿ´ó;‚§’ýUj½*HÁ‚­öç¼§v>Žöß&ž•\bH\jb¸JÅSï­Kø±ÌADùÌÙ_MgL‰ÃmÂ}!W>jµì¨´B`ðÒÔ‚ÓàãÅ߸ê‹#X ïPœ~ÏÖŽWsQ yBùI ÊS–Bqnãñ †Ex{‘$[®CL¦Ùgªè †—­”eÁ>¼ø’ó‘Ñ$A&Û<°àv¨9 Ã™XuGÆ35&0cÀÜ÷¤¦Ù”¢ êÙ^'uÂäAyFáÒ,B¢8íêc’£tj,Öþ R’§¯ ò‡U»+™B¿J»Ó²ô.†7N] ÁJ -/ÚxyŠ~Æy设V̹¡Ù¤B¸¬iÕAñnol1˜ ÛRRÙõkÔ‰Ž¼ÚŠÿËå`Y¾"ñ–Edýƒ"`˱FޏP âÄ,’5c5Ô“Í{0´eþV@“.löGc˜ ’æ3/“înˆ]Ý©wŸì´Ð,Iù¦£³|åæÛý±¹»ê‰AÛ©F<øf»*¨{‹Îœ|}âi`Q¾jã9×Ü+Mx«ñÎB¥:<œsP™4•/汕Mcb3.Ü.kÒyÌòš•ʽi¡nPÂØýb–Úª¿Y°“E@6 cLåí§_;£I QºiõCäJ.Ö ˜wÈpëp(g ¢P)IÝÂò^ z-äy.— Á’xŠÞ¢ÔÚ)öA [Ÿaa÷õ¡¿6ëb9ÈM·U ‰g?.§òj÷ÙÈ+ÇÆiÞjÓÞÇ‘·o„dA2u“'ðÂajª‡¶tÌt©p/úÚ~*к¹á`®j}>Œ`vgiuYœÊ»oæÚ ¤¾K„Sc<”„Ç/"å¡ y(}~‘IÕCéõ‹Lû›¼ûU>æoRô¡l}(qŠá_„óC‘ýPŽÿ*Ýÿ®òÚ\­›Ðàb^„–_ݾõ©Ôt@¾¢L·I‹™áÂI&i6S\˜d.® .Â6`¨sIç?r¨Ü3¬8ÖÉÍ5 QÕåÊ“nˆÆR6ìñM.:”–$¨/bÕÝ Ó!5äqröRƒ`’™'½Ñ”tÅý² j›0}oMÕmKÖ¿í†[yc h\`xY–ïõ’34«R!Ím| ‡$*aÿ ‡ñàU~C|@Ó!¼ú ÅþZ¾Œ­{nŽò1¹ëŒà”™ý(´ uFd®(.oz“Áü gzð8-<“¿Ó,ÌË5Òïä!ÐþóÇ”Â÷ïPÿˆ.dƒ 1! 0„T‡€q'.4‹˜‘R7.4×0àã UŒuÁꑃ—ÑwXhÕJn6þëËòš”Ûリói È›"©> ‹L‰éýÖm¥ t0“¥®ª…wÐ'‰Š%vŠÎå`–šíÆFdâàwë\éáÔ·æ#·Œ‡ä 4&/°¦B~Õ…‹ò¶"†×… vcŽ…³r×n,·˜²çBžÝ…“GÅØ(UlÌ/2Yʾ²sºÎê¼µ“JÆØ$‡ þ}A²Ó¬(ÁWx”£Mþ[ƒ\mšY¼Ø ’­Y¢Jf5¥Í¹{õEv+c¾ƒ~˜ÕOñk 4ˆéð`KÔì? ûJnœ*9q}" ëk9qU×ÈÍF“WMù÷ʽÊo¨|¥?ET©/|ý€`u%cUЦ¦{óꩇ^ó¬øË‡FÆ<3ÌÜ]*.P÷ ¸¹¥éO·{‘«€§º(õŽ#x^iOKùûFÿv=¾‡/ä)D<Ñ”V=Z~’aŠ—ù(¶&¢ýTü–T± À¤hR+S“ùÌå%wB…ß.Я*³¿Q¤µkc[C*+‡ÍtŠô¶Ì3FÔsí¨¨¨èï£)&aˤÔà¾ßoùŽ!*_µ˜ÝæPáùNYŒè!2$M²W¤á½ï‰"¨i‹OòZ¾ ƒ'mà;lþ“ž8“FÎS~”GA½£ªU]‚DD§wQ `@·Q|¼½…ó"dà´™*/—šÕÔä7«dJb°y‚NÏo@ïçøÉÞ»5HZñí!>ÍKBØàßq¯f¤GêV/°¢dŠ@H&¸.$…€Îp¡>,‰N0/Ž2i""C¦;59Ê¡¹‹bMÞÙhÞ¾iR^ô+¥Ë‹*f¨ jm^ý!ú?ä „œ‚L0¹¶ ;¹uÙjƒ¿á4ü‡ˆ)qgU¼nmÒ&¨©PmSôý>_ð›pë'­O×ýÔ~¹¼õ±|¯²_¯§3†Ý݆¯C…)Œ†(&é‚ÚÑá¨&xe  6¼*Gÿ+8Á+îDuƒ0ßàÎ.ú+(Ãþ>™E”…›e4u{†–í IIå2‰4&ýTrßÍÚ²f©V!Âà·|‹€›qaq„ŒPg7Tä Ô{Æ|z;B¢Ÿ$å´-wè‘*`ÍWQLÁž°f•|›VË€5ÜÊ ùž¬Þê q=9öüžƦÔF5àEöô7©¡˜ê¢ýŽæaß1D<„“ÇÀó H=´‡Ð÷ Lþ©Á÷ >¼ì­aëp›'-–u‡ãè)ü&Îû‰psÒ(3ù~åfË@ïΨ4LqàÙ%&°¢½ûC«Naï¯Sqî^e&^¸v«´8WñÑ×Xh,Va„L/ÂÕ#-(áXy;pûåŠFͬ}9—«Zê@zqq€×Š ÌꬫÝ@ÎSu5µ9ȉâ­î˜;N¼P@E‚Ü»ž¥àÊ )j–aÁó2U|Þ‚›J+ñx¾™-åW’:Õ³ßñ¬7(D‡tµ¢D2i›òtÂ{d˜‚KGÖó\`£`׬ox[r̪AÆ¡3W›Æì²XÝ$axÏYå¨71ËÙ}¢llBkU£z7GSäzo»½mÓŽ–€©‹"˜ ”Û×:’û.Àûƒ:LÜxw5 ²&Œ¾Y 5…Š9pâ3=îǯ°Òœ ÝÏééü®ÊF¢YagßÐñæ¡>K:æw6fúø¢ÃÏËÓCä)Ø-½þîÅùÒÝÁÛ0)ÄŸ€šŠH2?€H<‚Îc«¹]lu±u×L\äHK@!ëOÍêCÞè•WÍÇHo© ±‡Ìbœ4Ù3µAÐ*JÆfá<¡ä©ÚDOæ~´q´ ºB'}–Ç1Ø–Õj9ÑtÉAvV‚K,qÙÏÂD•å¦æŠŽ± Nm€|+UôªSÕëεEúZކ£¦p=>ÕûAº ªÜ Íö| r¿AÓÈ»£wÅóØ¿%xØÃ¥xE4èÇ&yAT†è˧yÁt†øÏ)zA•^¨!Võ‚k}ÇÀ†hÙ²6Dá†xÝ+¶7Äˆá ºø‚DŽ Ë!º9DB‡˜é ¾:Äb‡¨íß"Á/˜ñ ¾<Ä¢¿£Ö/÷ âæèÕo`Z ëþš¢N’_¶a([ŒQÁ(ü «+"€…L±+«,` …\µ ¯-äÀd¹ ¯î¼¹waù…ŒÀ;xá^8‰oÜÅ Ë1dD†ÜÉ Ï2äd^Ø›¦gÀ 裦iÈJø«®kÌ‹ ´¶mÈÌ 9¼¾oD 9ľqÈMYÌWÆsèû8Än2~šUÒ5ñõ2Ÿ³£¼Õ »*?΢£¸(ÒüŠ ëô!V&ÿœ.aÃ`Ù¤æðµS-‡Õö‰ >¦+?Ëo"ò|²© ?;Ê+Çi´×“0^ºq †ÂÈrM€÷Ç÷|¶rª¡A„Ö>^•ÖLç†À òá`AÎßau%siÝ1þg6ù®Ê'É↞‡{?sèÈéBˆÃ´C|Qà“Ø~ѯ?àñëfóôÆÍ'Öw¦æþê… ŒÇô©-LàEù7ŸÃa&Ò8¾Ñ,ºA Zuw[=¿ñ¦Ir“ \†¯XszãdØ¿ñ •éáŠr·“° Òåw¥†«*6ðƒ[œ»Ì©°¶C t [‚gø×š5þ2½I³›¦¶"/ÕP‚šXìíö ‰Ô9â?0cKn寿O‚Ðï?æ¬+9¦@½É=‰™¢øÇfúƒ|z•ò  ×í(íô±®u&1„ ¦oàñ|Té½Ð‹OÖûOVæ\ô$I<Úó -%È=sXÍ’§ !ÝWø‹6ŸÕnì^\+ÞªzršY4~9ô3­§ÿª=¼P¶¼2þþkž?u;¿fZ.õɃ%ð¼Gõ^íÎûu ²*<,µ&I‰ýX£ËÑÔ­Õàr¢çÝÁŸ7ºS|¶ù³ ŽÅe‡¿ùí<í¼™'ò?&¸ìf“ÕÅÏËÕ BI–7áÀ¡]Ä«ßÁ ¦NV¼Œ?8ô¨{ãH/©Þ&FßË‹‡Æåð0ÝħÑ%âý6®Ù™·<¦àtuWå€gþéŸò^uâð±PiVø$¸¸ùËOH•ƒÁ8©òs9l–ã8æ™R·®Ók½tÃEÁ`0p!dеYÈ_‘îæ8¯`fjJÁŸRÔ®•ÅfÔLTÍ•à"2q&r9$Œ¦‹ŒŒN-#n½7®P­+’õ À|Œ¿óÒ?\9ì!Ûýß‚ާoâ ŸÿO?]T¾ÿyÖ»—ð¾Ã_HI<«¿‰}й: $D.ìçÂ=~m§iÈLÚ]†Õor#pr øÃ¤/oX榿ѡy9Â6ë㸛ìW:›äô?±:A S ü¿3²º™^öX+­‹íVhÐu1ó Ù¨!o5ä¸Çò$ku[p¹,³þ8Æ“Z²!Ë–VÞ6F»Po‡'$ˆ£Am {w21Q¸.8Å™™ûÑ9|MSRÐr§ø»|L# Þ6Qõ˜¼ƒ×¡‚?a،ϔ²dÙÌ'úùz’¿¼`ÅÅ ,°<Ì×åË6åÿéßR¹Æç*íÔEý¸p_HÖ3VNv+@¬ŒÁ›g†ñwˆÖ¨z¤¾Ãf°¾5œˆ+~9V–•àî>ò>R‰nMg¹}“xW¢ú`P… œ(mÃXv0ÚÿåG楋ˆQîRɿ贴Ǒ"+?„rpÐ)g 2y,cOºb8- ƒN FaÉDi &2ô½¹À¡B¯[èÖŽ¤ KÚƒ½icÜt4"ÁH›#Ôñ¸(~„ê ¡’ÈEs$Ô'¹h™ª'W5†P¹!ÔxxÓƒø#Ñ—÷qE †p £õ2²/³ œ/ÑÔʾ6 ß7 òov8 ‚éL­§DÅ·Õÿ?äd7ÓU†Í­ìäÛ›ÆB¨Ç*7\UãÏÐ"ôb'Z¥of¦´¬?Å œ³Šç3e†9—àëTSY˜à/çE9Ù'’9UËM™±™œ?¸…ß7÷&Ü’.Û×e« 7ÅËl¶á¶|ÙÂ/Û}˜„ID˜p„©IÆüIfùþVÙ8 G@8V¢qêÆÖ»›ÞÐÒ74ÿ½6 8"º4Í‘Ug¾ªpïµ6¦"à°=ÎB±JöÜ2M‚5ñ\éÕù2x\Ɇb pY; ÃÉJi$…IÐpJ%CÆ ™ÃI[ýV÷Ö‚‡8¼±ý%ø)ž‡74ª6+P”7s y“ÅíŠÜGÂÆÑÒö“uaeÈ@â1ZþhG{ûEŸ?®?>|L×GÚL›Dæ’ðñ]ô÷wò5q"ÕPä"%ÊŽ„%W1ˆäé1 Cv>Š›àŒH0 .š*Á;hî=ó<ëƒU-?6”2W Äw@—ÉNËp ‡Óý²0\‘À—<ô/¿K³gBL¯‡6™|ˆ'P¦¢T„¸án©>üN!"Ô’ˆt'Š#ôºÏ¦JaUïbÌM½'Tú¹h]ôƒ¨#Ê‹„ViåÛ¯z{„¶í½ÿO„÷ä$ Rúµ8˜¡lçë£W}Pj2sƒu±ë¢ó Ï5¢z*-õ<ÑC"¬’¨ÙñJ˜éç•€šS©£)ïõôÈ¡õEPé&¾Ê4Å’Ná †ÚU%”N EV.‚,86nê¶…à8³6li“«T:þírA6ΪªÁ¸¥Ž‘Ã$6Îè|H×uîþ ·B¦tJI¾w9›Wé›X#'”ÓhUþêÇøtC/ÖÔµàp,­Ò²éÇNE-™É³ÀzÙä ¹…O'¶ºú$iŒ^eøÉý´0 D;¨ûéšØTy2Š:²ðpEžî/‡Äôæ‹"?ð¡"§J²›ë*X°š#L®T¯íųÜ>}²±ŸºlhŸNœ »ñòLg_öF¦ËTo,h]»ë.zÙqƒ½ùm!ûø³¼ë}J}þ¸ê!…ÊI•¥X)Tnº¨<S(œl׉ù>‡ÃÉ~]ÂEäûJó¶ ý dioÒå”…ä]Ÿí$ÚD—[m:d¢U¨.{Ñ=›a{ã*ˆÆ†ò²W)ÚP¶6¸ Åp#ÝÜP`÷"Æë´Ô›¶½úW0ãq£Å[P‰æåC‚†‚+««3MWóµ^‚¬x6ëqY°= Ç¶‡Usy†ƒ¥­føÓÍ«}ó¼Ñ—`í £{"/l³f«åU{µñÓâ,d“$ÜÒÄ£ÑwocsjMóE¶`GK{ر‰¬Kð•À”(Á±¦ólÞò™U0¿zœÓµÈf†é9KÎC·ìàzV’¨„¥¯ZxDmK? b~òW*RlqÉáj+r»1rÍJG2±2Z´”5ïWší{$äÞDäf`qËf äµÄ·«ƒ ¼œƒ©N”i‘r´†³m7õY“ó™“©Óa Ü4¥A„wm&޼r³ êO²ÈAÊ/SÇ^UŠ(Ù£›‰)‘KÝì”kÊ2XkäZjŒ‡ýº@6@‘*ÓPÀUŸöE…æ7Š5‘´M¤‚só!‹¿ E}ü¸ŠJ…òSoRU4T ½œC×çÐ!ºû©NîÀ­OÇæžDîÁ»Z•žx@>žð%=TNÑ»™l‡~Ü¡s÷Ãåû«6ßqüÝÁCñï–ãpFEeTÉÒ…†ç”©gJU'µØ(ù€:éâÕˆ¥6OQƒÊ?ª6ÍG¬J™œÓ%»¾`°Ò-qÍò²eQpm­^Û²© X>4¡¼õZUE3qFRy½A¦2$Q,LUdáVD–°åÒÖ@–©ê_¥ 0ÍeU½®|•NÚ‹›A. ÕD(nG†bu)?Ù!=Tÿ~“n‰ü¦ÃÅL‚>¤Ü€ò=Í7•íÏ¿Qäµ»ÿõu¾ÿWýŽÉü-u4Zö,é.;ÚQ’¬Ðíò ’Zq7’‹,{7ΉvßlJpuKHêdñŽe%FæŒÖŽoå°T;^`Ûa|-'£+w3³YŸêˆ ÿúW1|”Ÿ›‰"@³]ŸW".µ€‡Ð7I[ÒY(|]ªl÷^– 8Œ„çvŸÌö$ø ﲉ7˜•fÄФ|à&»ëRã¤A-)¥¥á«Q’‘z@ºC{ñ Wúùã7®Ù뛄ÀÇßÈ „›Àíæâ‹sñÐ ývBgž‡¡ÏÃħù³,?²âv_)R §ãJå©§£¢P ?['¾k˜ôÎù î=ÀË7Û«ÏW‹¬ÐLëb¼št…v^±óWhÚ‰]¬ÇB›²ÐÐ,4? Ò.–j×2Ä÷ŠEXÚOül+_¡Ç{:ÂÀzæ|ÙN? H‚pC{|ä‚§ºngZ²­Í^®Ö4jO÷o¥S›®¿¶´€ü+ŽÊGd{ûà(pX¸:pYœr v# %¸™`Ë™ PÛMŒ–Nÿ,…#ÿ¶/}Ü.ŽoÿúîpÒ{À†f;‘'OhÞsײ·Òv5Ѫi¿¿FHÙR{߆PÝÓ{…‹…`´Ï?£ý±9Ñ5çÞz±ŸÚ‹ýÍgƒk¾u‚åרþ³÷_­ÿõ¿üû?ýûÿøÿüßÿÇ÷þÓúçÿøw þûþßÿÏ¿ ÿçÿÃßÿþ>ÿùŸ~jô'ÂÿÅôóß½žü'ýü¯¦Ÿÿ×ÏüóÿýÙ~þ7?ÿçÿ%ýü§Wôúïµâ,šìb>³FvÞþˆýzƪñ_ç/ß#þw×/ÿo_ÿ'ÿÉ?íŸ8hà‚ÃpnübÛ¢%üE›O ô¼#žÉG¤Õ÷+¸Ø¯×£4Ê«¥ E:ôGDVò‡¦wÚ­õø á¤$ýrµ%:ùì+ÙïPäRÑO·ø°²?íβè+iJzQÐò%ˆOv«z9CWzÎÆ"&WmrÖ •(*ã^úÑv«RÕ¼,Uv7d¦4ˆ_¥\`Ù~%XÚãï5YÖÇE¥eÍëG{ãŸ[çªh)ïÜþ·§× Ïp<=Úñ5ÔºðT²‰ï¦òv¡ Õ@¤Ð`si K¿7ñ}J>¨¼¹÷;øËoM{?xºä´¶„•ÜÞšm—òYîÊ•URÁ=ë÷WÙ²ºNÉŸëÒð+þ2> ‘#*ø’«ËHøÜ…-B0LÙNuMﺽ(ûìÀgácWí¼ù owÀTÀ’óOÒ¿5®šÉ˜þv¼5ÙÚRí}‚‹­ëö„d<þ"Ç[Á‘:ì¹V [~ù|ämÀ\ߦ … w|7|uã•PÞ0™T:Ö‚Æ{Õ¯¢4«ü×2€ë*´ wPøe B¯àÙ'›"áRù6I¸ž{mQXó›áUì¢Î2nr+òÀ‹ü‹ôùÚÛÛkðÉ’°ºñàÊ‹¿—ÒT­™ªœ~R½føu »_câ¬ÀÓ¬•Ê1²ñUÇÌB.PÞäí¼")yÝš|^kغ,¹žßÀ€[CQ# ³YÕiý߆ÒcŒµ…Kx5WÂ\²›ÕñÓ¨G~²æ ½—“‰º¨¾;áÓC@÷•òú!\V/ÜUíl«£¬Z "Ó}hiI´ŽúØg,ø:¦á£TG¡úÌaþbùýÈ?Ã;à­m[\í¡¹ð£„sñyìo{ÞÔ\œðþ2Š€ñm@CN‚cá³<¤¼ßÁ¹µT9ó=Ê[k™{¯Î•_?¾^'›ß ®\|µ.~ß¾÷!ò‰uáU²ù“áTý-·4hk„Žj‚AgwùÔÄ]«´Á ôÅÜT!”—ö3g™:¶4.ÿìÌß¶2¹×ɜ움ëªL-2Å^Sã — ‘âœ÷zú¾"Ü™<+„Œ|v7?-Ö†ü\ÁyÞå™öËØËy]¯ñX–) Û&7Çí{ˆÂvAñ=ÏúÏãÎë}øÝ!‘é¯É¿˜»»‡¨ºa¬Ì£ßp%Wk 뀹’¨˜t(}P/–ÚÛL–½˜6F•Õº ’yð£”`õ [ß–«£(Ñ®«í~ ŠDÄ7ùþ?ƹ-3W°T×äo:E ì Œ§• z¤¯¸¹>LiÖ–¿B˙ܘÙÐ.P.°—UO'åg²aŠAÒ‚æ~ ==V9-rp)1Á/ï6Ù–øõ¨$µÞ–ÖÏx×/À¤\@Üô Ûð:]oŠg úcéÛc¼MÝÛp&UØâ³z0†ü½âFOfçÑ\¡2\¬Ýj? ÚyS”gt£€‰üúª"Oëš¿fö Ãí™Þõ¤»¼Ð=¸ SAºw³A²Ëâ¸ÑDZ-§§Õ Ï„¸º÷'+O±ô“àb*£gn›]¦ gg r¼fνêùᯱÁ¥ï2cQM‚²í¨TÕ¹rAUû®…ÉK=/àVll¶Ó¸}Me¿€ûöÏ6q£dû\m½ìɺݤ„ “P•É´`ɯ¹`jî~ŠÊଽ¢ŸmPeÚòTiÞ{~<¬•4¶iäûHBózW&ÁÃWIâŸéØH¾¹ûi‰c"t;ZpáÇ7Z†0Àß‚+~aÅÞZc[žsé±ë?üÈ ¹õÇž3ŽÍ ÝúùlnÐ’{Ç6H…ýÕ7ž½ç·óíPÓ¬R…‚™&€Ý˜ÀÒ§Xrh/ZÑnë¬çlö壕ÇfЇ4shý[ªüžz0'y»³O†'߀[ˆµª+V«1ç©Áû~<ø+è%WÍäTÍ•àæš¢UEþ¶Œ©Ó¬ÈÏròÒÂ-z¸ÿ(ßò·ÙVs[(eZ £ùSë‰ÁºO¶Ã“d³ò >»x¥ òý±'r¶ZUbÉEÂ…y‚ á 2Šù¤ËkÇ©ŒBMòüš}Œä5¾Sr“ 2_4Øé†ð~c8ÇÊ:à›²Â¶?6Ì¢>|°^A<šŸbï+œŠ`Kt™~î¿Í7å÷;ÀÃ$Ko|ÊRø#vé•~–GU ŸM,CPŒX>Y¹DiÅmiˆÂ¿ÝÅrØÌ,ìOÐ-áýÎô;=G1‡ lͺ¡¿˜FO®öŠÓý_ïdJ×6¡â©Ïî"cpVC{³çå1íµjcE„±íÕkp¸\þ†Ìš^¶»e×jžÂÂofl kOäáùeŠ×ú]ø"ŽÀR)‹cÚiÁ¾ÛÛ ’¦\¥òÌ8£Ú¶9†çºÃÖ\ yM˜J¼€’ -\øÑ2 O——uÿón×䟟ààÖÒm  Üf¥ªqJ{Ö‚ ÍÆ@ cX­ÿÂ, CA‘ÿ hnÐþæg9S»ÿQ/„—«üùלc4O<»©ú_{>æç¶æ…Ù€xCŠO±çt¼Oèàø¦äØ!‰SŽÓA‘çç%=šÂLÏS7­ë¶àŸR%/Ð6+Áª.§:+× êì‰'‚AQ䨞ÝÒ_Ö`•švºâŸ‚¦¾ Ãb2Ûn‚<†§ÔíQEôŒ~W†Ô¹Ÿð`3†9Ö¯»˜2õy]S¥²³võà"³6«Vœô󱂑å1-Úå9Œ}äë©ï¢Ð"ŸEת¶Ò‚Z98‡P·!”b­n&Á̧Qq³Áá^9xb‘hãL`gHîjùZD÷Bd]Ýð[î^XøY¸TÑÎñ<ëóPÊÙ''{ï!»ñºèzzNäΑBôʨœÑÚ~& ¥,G´à-+õ‚z²ø²®Îdž_r¸ù,i ¥ÉÆãv%ûuuî}IÅÖh{¡U¹îªÞR.Ùµ.“=Ôy÷7Á\xã{ a¬ݼT  ‰ªÒéô½‚ì"Œ§bjöCÂpûLQÛܼú+Ëm¥üÖr“;@R7(¶¦ÁÄf°Ë¨¾í¤ÜÀ¤YôM"rŸÝ¹ŸÈ Ä+«â—ÖÏèªø6ñ­òb„–$?!œj`t;šYr:ë£d‹ªYaoôµ@(«;*ËD³Â1Ô0›5¶÷Py£Z fí57`Ê9d³Ç8òô¿¯Ó‹bȘgóÖMwƒØÙþÑ­ðË œ>7YI³Aùõùº±ƒ,6HL™ª¹ÏC;œ\g÷úb§H¦^À?©P[ŠßæÆ7!4“ÈF l¹|¡ƒ%\¹Õ®âF6*‰6ít€®WH}áŸÝ¨+v³½ñ^ETÀöØå`j ø5ö£ð ˆñâß»‘Îô’ÁxÔ%ÕÇ÷4ç+àŽQ|ì3‹ j&‚b•™NqÌJ}阷ÂqbPA£Hê|¡^|ûGKŠâŸ5<}6òN®¸®FáÉÎA„ËÚ‰ãÐtß4HQßâ‡ñÀÙˆ±\›ø¬!\ÔÀDL$Œsfº·6ņ$t0'.w¼X Ö ×M>EZsä“TªK/ftãJR™E|×§PÅdo €¬ÀoOK¤bRã_z2*£¼}ÓË.O=²ŸŠç¹ÀDż“¢ç–voO #;ÃùÖò¶NòDT GçÝÇOzüe®•­óA–G^U8~Å×8o(u snæÅ™Ó ŠºÙ7ŽÆ#"…Óâ¬+ÄgçD‚™ð†,ñýÛ¹iŒ:Péq¤U¬<Ú#·ÿ…ðY^”ôéáÆv‘oãÑ2Èè ½ïC™Ûˆäm6a<¬ûÖ¼O‡'agU9Ÿó^ì…WæÉ5Óäò Ð|¸ÎÇr¨§17¹tLGâ÷³“6x%7•¹žî‘¯íèI7äLý&'*OUyZ;u—ÎÄëN.\ÏàÚ0Ù|{„x¶"—k~?‹Û¢ÛµŠ’¿ŸŸéç,øÞý†“pe§™,$¹€ƒ’Î[O››égý@Cø£\5³õLó¸U¼²ôl–¯â«ä™ö«x!äÔþå“ýàE¹ª¯úH_ùzVV¥>¤ŽKêv¬™)O•X^Hfgm ª*õGAÏXŽGújOhŠÙK ;ež%Çbàø­üûÕˆ%¢‹À’CÐþ¶5K°¶ï•…Õ~å=‰9ä‘ÜŸ5] -¡ÐÔÛh‡¶‡VÚð&îÄ™Ša¯?)4ÿ-ü8¯AßZùZ8¾ª<ÀÀùP¶ÖWØ UUy_ß§8§U¾àm)¼Õk»Añ)Cê©ùŒÏ¡˜s_iS|ܬ,« Èzk‰¨Ë|ƒn QÔ{,!+‘_ÆGYTL…N1D=$ ‡Ž+jÿì W¤ÎêgýD+ñÔ”¯½; ·isг£!ô7‰‡­©”oÝšb ~Yåi›¿K\J#Ç$Eé¶o•Ÿeݤ[ Ø‚²—°ÂS§°‡ýتF©¿HÙqØ O³JÃ!.ŠiˆPß÷ø PyžõíbË—Ö[TÌw[åkYGÍn^¼x;|iP?ZÝÊy{Ï~`ÑÆ¥P#¾sÕ^ã”>Lk9š}˜l ­»§cWõí!ˆúä8†àËKÇž4X8+Æz¤×Uce‘r›ûr§³Á¥[?"iª‚àä]9N}ÆÏ}aZÈg ‡ºLíéÇ©Å#­lÑM@ÒÎ%#yéw½½Ð­Â‰lq;bïmØ¥¸±{6,;üÅvT¢^¯31Fg¥çΟd]âÔœï.¥Åï¯ ñÙôó¿ ¸Î|ÉV\¼uœâ·Ÿ5‡« Ìí•ÎÁ.øYK¿hÊéueìDBÃñ€hÎCάo°²m?½OÛY-—›-Ä~ñFg—î€ó5ÈnvÙx2Ùñ¹¨QžÌ¤xA²ÓÇŒN¬ ¹bÖ•`7m Iñv6Ìœ·VcÃnòý¥ÕBâÁDÓL‚Å*í+‡w€[{_æÈa<5"ëdi+»¾­w‡½sðÇ"'ø, ®¯x€¶@¿ Z?|Í‚?ßÃ`&½žÿÑ?ÛgðYï*ñ°…»¯)wøÙóeÏà·œýÃV±¯sJæÏ8‰´*p¾¨Ë-N¤“5€·‹à,)´×ÍÓ®’»?I‘õr²¢-~ñÓ‹ü§šMÙi÷ç1¾V2g¿]×~ŽJ]UB\t;¦QÌJå ùŰ×ý7­òõæEp]|¡h¸'ÔµÒø w®»Î/S õγê“4 áuéç’›yAþÖX,X>/5Sjf!›º|’ x÷º¸ûêí1Õ~á~_ëÌä®fâmrÙ¶¯ydó§I£i°ÑÙ]ÂìqB. §•ö¥ë'A6ïÑuË’RË—]ƒÖ ÕÒ÷—úóºî>ò¯iÏóéвUç»oÚFâxä_®]˜›ãu4ªBð¾ÿî\²‹Æs§£ì}yT÷±{ª5Ã"½è¨¤æâ‰í4Ø—ÉÃó=>^n† V)«¿„üDpŽI¶i¦BèA®u}¸*}ºúq߸xúYOÍ]Âo;QkØßð&Ñý¼@xU .ß3j>îS±UÉÞh{‘|=+‡•C?%œ€T¹R¿‘ât  3ãA\¤ÝìÓ 0`$8;/ZpÍ mpClâiØGp6˜©H z—®˜ìÛ¥8¶¨2y™ù ¦¿*y§øóå‡Îázœªj˜kÓhü|8©è܉¦a›¬­&êò¤Efƒ„¯æÏ2‹v ”8ü¦?ÀQ5;¯mþÖêÕdÊË/-S}¦Ç/ps‘*_v ¹Í’4`Þ¨pqïÔæ:Ø UëjçJöâÐCÞ”`$h¡-ÁVY¡Vy0îúÌÜxBʆõ›~A—q8VÝi²Úu5LtÁNX\ZDWc2¬`ØŸ•s>Æà̆u<¤\¿@ç8¤ƒVJD|Ë=Ç£q‘óµ·³«¥Òc¥Ó½dj–‰ ‰#³u@P™ãìÙ¬½îõ ù©{YjyØ]® Òxä;I°ìoG–½Jüˆ{æªë®òËOÃRqŠˆdNÄÙ—ÿ‚^88”Vò Š!¬DrÙ—¦GÛÑÀ{:˩уŽ7 =œvÎG%žçYß^)EI*Pþ_QAªèæÅ/`ÕD~«;–Õ ö²n¯2É7;ÉîýM¯ì®É—ÂvÏùæfÃpÒXp8Þh¸–ÞfçAQ¢=ü> NÀgçKauÍ´ÞèÑ"íâÍI¯s È(zž‹`YžDösE¨8‚ü—_Ög«AxO_ºO[ˆ‚XnóºçŸ…â…HÖÞNõf9F²Y ’ƒ5ŸÆy"OXÃ>åyÈYf}ó.×uæÇ×ïeu ?K1‰æ$ª½¡Óꌟ†…øgM÷öñè)lÑ ÚÏ"(/°ý «©±-eç˜@-”žtÅéRÇO¨5ÀÞª‡[‰¯}XAv'‡ÕñXL—£Ye’Šã »ù0˜½ßxl'©¥d ¦þž;pY‡‰éÑ‹» s…fúñ62ÎS˜bY@;ʹ1ïg£3› ¤ƒ´´ã=¼Ï¡áÿ¯¼«‹±ëºÊç8±¥Ü´%)¤ª(§.vÀ™ó¿Ïñ_±Çq”æ:žÚ.qSÅæz|;žæÎŒ¹;I¡´FT‰'„(­‚hŠPí/¥T~$ B¢â¡â©ü $*AÔ²YßÚk­sîñ¸”Ä/±½=³×Ùgÿ½×Þ{íµÖWYáÎN‰MFÑ#öLæ2ÛÄåâÅ‚#&ïÛó¢ŠNªÎG¯àyU÷®?Ä1sÖ37H³›˜™góÂ!V‚ Úàê|@Ó ÔA °ó «' Ócæ=ŒñDuϾ5U›«Rg­ìpÚ4ÅEÿ.¤UÊR—opmµ=a«Í@/ê{]X‰ð°Ôg¶7kÍ‚X/*@.í8/¢L4=ã¶N•œûæŠËbÙÖìWòZw’Ý´µIãÄû[˜ËM‡»§î)d. Õ1R®\"ÏjÌTëFÑ#‚Ë;£/Ýœµ=õ̦ªìˆd37ð_F´³Bï¬. ñ"†à£š–:ügbÑ7±Ós3ž‚ 2mk5¯ýÒ“§Ë8ëèûYSWs‡Tâ]N×%±‡Hz™€K0=x¦N·Øú½€K&:§UÀëLÀBßï "á~·igðÑÙé´—y”•aS;«ßËIU[Ø­Š«ôÔ¬PgZ4YÕÁµæ™îäE=‰â©žäþŒS¶Í¼”ž!à22GÔ¨ëEG¬i«ûÂRoF™\èòÉ †"O(3Ó®MUø‘gª4-¾‡·‘!©p)×}a©YYÚ0ój>T²™6•ª$ }•Íàc§'_uòž-Åuõ˜ËYëár=[Šü’‡¨m½ØŽp‡q›ŠÓuµÁTxÈvöæ“+PÚd4V¹]‹?¤b²ÖÄoX0Ö ÙP×m¹7±.:«ÕT¥gݶ´®žu|MŒÍC¦®š¹yܦ‹V³€Nm@k¦ ¬ëSq_m*믭™H»óÖ6ƒ*ˆ¬½ ÊU¢•µáÒTNȵ¦V¹6@Ô—1£ºJu"Ŭ1mý:¸s t¶,Š:”•.8fûˆ´Ýõ‘n&3ÁRé "Ð=ƒÕañÓèŸõymí’ %I%©.Ü¿KωfO­ÊIá;WvÏVTVF[¦åÌ­>÷³œójÕÆæ¢j͵zá;7v~,tLuk¥òJŒÔZ7œN•û™l†Ÿ,дy‘›N[+Ã'Ù 1Ôâ¨1ö4dwðUt™„Ý­à£(1‚«ƒìßà6Íå—}©<CËdgb¥W˜¦4ň‘¢eYÛ¦CníÌò¼rw–ŠÌrR]t½Ëé–ÃÏùšñ›ªí"ߢ‘É2ËDÛ³ÊípEÌ"5‹ É´4ø2ÍwÊ@-ÝDª«4&dLµ5ûšÒì0Þ4Ì,‹™¿M#Ù¡ó™K¯2ç ¶6™ªº`ÌòNòTmzuC¯÷`…t,¶´ú ]f\·6ÿOÆ=xRk{I]y\oU6·x/-u_ƒ|(änQ,ZY›ƒ*÷s™æ¦Òmæ@L¶âX+p(ä²Ö­§Š÷®"ãÞ©ôŒ1Ð*]fL™Wkq_æLj‡˜Y9»³Øº ‘Ý@‹\˜7óÓ5E8ÌTéÞTÍ8µ1Z“ÄDÓ«¯J)¢rÙ‡B–¡è™9Õíã͉èº9ƒ£xëqSxiuYUk&B,SƒMœk–¶·?Fº |QÛ„Si k†`m(®O\8u+tZ“éÊl=#®ÅBƒe¹FZ¦Ó)Õ¬Í3õ ›ö¢ú²pÁ¾`§U¶´VÖ9… EÚVh¨¦•îõ®…ºGµ»* ýÝÈçÉ «è¦ëäò°±–Q*HqÃtÁ]3P“ü™½.5#Õ»lq\+Ͱŀն•̒ؾ¾#Ã9ÍY%;…8 U³«°¢4ÉÊ̈.ƒ»xY%œbæe¹mž:̼ª²-¬´A®uó¬{¶¢-=`/?®ðz­^Ô+²vQ™ÏW§ªEˆÏ¶ñ­•U ¢ 6A>E…H6¶ DgWt|ó¢èaßu¡ÎvÜÎP1Ó\[å:ÜKe.(Ò„ÊŽ9µŠ$Ùô¾ß²îe­­U- à^ ‹vj"À0«r~ 8LûŒ|&¹Êq^ô}]b\O¥õjre!r¥Œ´y¦SRVïoÎún&>pƒVGï‰+C§ÖþÛp™Žý´Y#9³®º²½?nl_ N#g“Æ”nÅ~ꀲ ìö•2¨PÍJïZ‰ùj ·*0ú›ÜF0M­4XÝ*¥Ä.íLP}Ü¿[àq¬ë¢ŒÆœ/ÅïQµn Þ¢—&¯½2,‚,äÉF+= ²`y­qZr¾G·Ù(ñ®ŒB<m¥tós¾½`/ Ç[^¾¾vfc“7?É>¨^ÑBåö'çÏ…}su®.'‚ï>àz~¥è‚¡mzqÀ…9Ì/¥À#8ÀR4eáZ†Æé&\NXŠ&ØÂYï•¡­…ä`µœk†BÖk_…õ¦,CûØ“ƒRœX±;râZï•­´üçÀp4'zes|¥¶Ò‡!|ü5M—ƒÆûícŠÕBr°Zεí“ïÇFr¥@®ÂùJ2†“JaP ¯z# s-D_ÞÎú‹»í† —›ÂúµÀxHYȉؙ&¨[‡»0ıu@¥ ¯`Wе¿ NéDÅ¥J~$gAKIÁ”ªîºq¬èOøbÕørøÄYÙOAb H¥ÔmºK)ØèÁOÁŸ¨¬³0Dpÿƒ}¿-÷Œ+X÷8E%OsŒi6‹èÍP‹7•Œq£€MržUÝ—3c¹7‡Ù—»6gÍ(ðêïBƒ+˜qaöÄ uÐj< céDMÁº"½xX¦ûo°ÃÅ~Š"ìó-ެÙ7@)tzhy(EkÁñ´Nz“‹ãœ·¤—BÛNSØõãü!·ôÎ$,‚ø›%Ç®2—`³,è˧Ôy8¯éŒÄ”SÙãmH)ãx»“1iq&ß»4ZŸ›ŽV't^¹6º1NFëëXoÆWéI²2_ÛÜ˜Ž“kW6ž…^Ñä,e¸øØdrOçÓ‹”{²°9ž®­®SÉÊx3?7^¾7¤¼vetyu}…R5;¤Z„dâ±5*ŠÖÛ'|ôÔÅG§”Ùx}s‡œ–QçžOÆ7Æ“ü–•Þ»÷‘Ó'Ñ›£ÀMßÝ î½zõ"w’tËàÞh?w´+Š£üû›¢¥èÔÙ¥÷dél²xzxú̉GN&GèYLá0bÐüg[X1b*E;þ¹‡Â+òÚ=?ñ¹ènúy ¾û5,ñ ¾µ+”Iy»£ÝôsOŒÜ~…B³{WôCÑÞè+ÑüïF_ô¿Náé÷¢ßñ“è·ü…è7üÙèWýãÑ'ý£Ñ‹þdô“þ½ÑÈ¿/:㟊NR8êOEûÅè)$ú°?½@?‰âŸò§£ßö£ßó×¢?ð¿}Å¿ý©ÿ³èý×£?òÿ}ÉßÑ?ŽÂ/ûâOùW¢ÏÒ³Ï{ÔåñQ.~Ø¿7~—??è4~³0~£¿+¾Çÿktÿ›è^ÿåè>ÿÙè­þ“Ñ;üóÑCè÷wûߤø—¢ý_GøoDßë¿Má-ñþ]ñÛ|ÿ ?ïó'ãÒ?§ð>úý¢?OüBü,…›þPü¢4~Î/íÉø‚*>Íõ¹Óccÿü÷;>Fî–rûcåíáߟ£wŸö÷Å«Ö=ÊüÏèI*ç<•÷ÿÏÑ)ýªÇˆž]¦wFþˆö-zö ¥ù/J‹w^Ï<â‡e&¼%ú5êOS¯|†v/Q½D=õ}/p¸@»™óþó´Ky™zÿÓ4+^äp“vç=Þ=ó”ÏpOÞM=9ˆÞI¡ŠÌñ{|F;4>L;¡ƒô³¡xMôÒW -Åý=?DéZJßÐ{x¿Š+J[Ó;ŽÞ=H?Sü(ÑßCiŽúƒ?Hôƒô¼¡tHßÄG¼ë…*>4Ê™pÄB1—‹Pr¾5åUSÞ(§¡ÐRü ”7jJƒPQz„r&´D;È¡¦ßCh|èÙÈÆhˆï²/Ü*¢è.þ2ÿ çÎåéËDÐÉêyùºÎŒ‚ªK© http://www.intel.comàÉêyùºÎŒ‚ªK© ,http://www.intel.com/}DÐÉêyùºÎŒ‚ªK© _Toc176025230}DÐÉêyùºÎŒ‚ªK© _Toc176025230}DÐÉêyùºÎŒ‚ªK© _Toc176025231}DÐÉêyùºÎŒ‚ªK© _Toc176025231}DÐÉêyùºÎŒ‚ªK© _Toc176025232}DÐÉêyùºÎŒ‚ªK© _Toc176025232}DÐÉêyùºÎŒ‚ªK© _Toc176025233}DÐÉêyùºÎŒ‚ªK© _Toc176025233}DÐÉêyùºÎŒ‚ªK© _Toc176025234}DÐÉêyùºÎŒ‚ªK© _Toc176025234}DÐÉêyùºÎŒ‚ªK© _Toc176025235}DÐÉêyùºÎŒ‚ªK© _Toc176025235}DÐÉêyùºÎŒ‚ªK© _Toc176025236}DÐÉêyùºÎŒ‚ªK© _Toc176025236}DÐÉêyùºÎŒ‚ªK© _Toc176025237}DÐÉêyùºÎŒ‚ªK© _Toc176025237}DÐÉêyùºÎŒ‚ªK© _Toc176025238}DÐÉêyùºÎŒ‚ªK© _Toc176025238}DÐÉêyùºÎŒ‚ªK© _Toc176025239}DÐÉêyùºÎŒ‚ªK© _Toc176025239}DÐÉêyùºÎŒ‚ªK© _Toc176025240}DÐÉêyùºÎŒ‚ªK© _Toc176025240}DÐÉêyùºÎŒ‚ªK© _Toc176025241}DÐÉêyùºÎŒ‚ªK© _Toc176025241†œL`ñÿL ² >Normal¤È CJOJPJQJ_HmH sH tH t`At ² > Heading 14$$$ & Fd¼ý¤à¤<&d@&PÆÿ56B* CJ,ph`¨\`A\ ² > Heading 2 $$ & Fd¬þ¤¤<@&5B* CJph`¨\`A\ ² > Heading 3 $$ & FdÔþ¤h¤<@&5B* CJph`¨X`AX ² > Heading 4$$ & Fdüþ¤,@&5B* CJph`¨d`Ad ² > Heading 5($$ & F Ædÿ¤,¤d@&5B* CJph`¨H`AH ² > Heading 6$$ Ƥ,@&5f`Af ² >Heading 7,(Do Not Use)$$ Ƥ,¤<@&5h`Ah ² >Heading 8,(Do Not Use-)$$ Ƥ,¤<@&5` `A` ² >Heading 9,(Do Not Use ) $$¤,¤<@&5DA`òÿ¡D ² >Default Paragraph FontRi@óÿ³R  Table Normalö4Ö l4Öaö (k ôÿÁ(² >No List @"`A@ %² >ûCaption,fig and tbl,fighead2,Table Caption,fighead21,fighead22,fighead23,Table Caption1,fighead211,fighead24,Table Caption2,fighead25,fighead212,fighead26,Table Caption3,fighead27,fighead213,Table Caption4,fighead28,fighead214,fighead29,Table Caption5#$ Æ@„üd$ÿ¤ð¤x`„ü 5B* ph`¨>`A> ² >TOC 1 Æð „ìú¤Œ¤<`„ìúJ`AJ ² >TOC 2% Ƽ𠄼„Dý¤¤^„¼`„DýZ`Z² >TOC 3! Æð „„¸ü¤^„`„¸ü^JaJmHnHuFU`¢1F ² > Hyperlink>*B* CJOJQJaJph`¨TþOBT ™-Ï 2LevelBullet  & F¤x@ˆûÿCJKHaJtH PþOARP ™-Ï2Level sub-bullet & F Æ hhþOh ™-Ï BodyFirst„Ðd¤x1$^„Ð#CJKHOJPJQJ^JaJhtH TþO¢qT ™-ÏBodyFirst CharCJOJQJ_HhmH sH tH H™ ‚H ² > Balloon TextCJOJQJ^JaJNY A’N ² > Document Map-D MÆ ÿ€OJQJB' ¢¡B ² >Comment ReferenceCJaJD ²D ² > Comment Text¤ CJOJQJB`AÂB ² >Header ÆàÀ!¤ 56CJ4 `AÒ4 ² >Footer  ÆðÂCJF`AF ² >TOC 4! ÆØ ð „Ø „@ü¤^„Ø `„@üZ AZ² >TOC 5! ÆH ð „H „Pû¤^„H `„PûOJQJmHnHu: A: ² >TOC 6 „ þ¤^„ þOJQJ: A: ² >TOC 7!„è¤^„èOJQJ: A: ² >TOC 8"„°¤^„°OJQJ: A: ² >TOC 9#„x¤^„xOJQJ.þo. ² >Body$ B*phVþo¢QV ² > Char Char1(5B* CJOJQJ_HmH ph`¨sH tH J( ¢aJ ² >Line Number,(Do Not Use>)@þor@ ² >CellHeadingLeft'$a$xþoA‚x ² >CellHeadingCenter,($$$„(„(d`ÿ¤x¤x]„(^„(a$5B* CJph`¨XþoA’X ² >DocTitle)$„D„Œû.„Û/„Û]„D^„Œû5B* CJ,ph`¨hþoÁ¢h ² >CellBodyBullet$* & F Æ´ÐÀ„¤<¤<]„ B*CJphÿvþoA²v ² > CellBodyLeft@+$ ÆðàÐÀ° €@@@@@@@@„„d8ÿ¤<¤<]„^„CJDþoAÂD ² >Bullet, & F„h„˜þ¤x^„h`„˜þRþo¡ÒR ² >CellBodyBulletSub- & F ƴФtþoñÿât ² >Classification .„Œû^„Œû45B*CJOJPJQJ^J_HaJ(mH phòsH tH :þoAò: ² >Spacer/ & F¤@&CJ @. @ ² > TOA Heading 0¤ð¤x5;DþoÁD ² > Bullet Sub1 & F Æl¤Hþo"H ² >Register Summary2 Ƽ ¤DþoA2D ² >Code3 Æ`Ph X€@@@@@¤OJQJTþoAT ² >Caution+4 & F Æ„„üdÿ¤^„`„ü>þoAR> ² >Legal5„ìú¤¤P^„ìúCJh`þoAb` ² >DocType'6„D„Œû¤&dPÆÿ]„D^„Œû5B* CJph`¨^þoAr^ ² > DateTitlePage7„D„Œû¤]„D^„Œû56B* CJph`¨ŠþoAŠ ² >Heading (TOC,RevHistory),8$„ìúd¼ý¤à¤<&dPÆÿ^„ìú56B* CJ,ph`¨fþo’f ² >NotesTable (Numbered List)9 & F ¤@&G$CJNþoAN ² >Note+: & F Æ„„xýd$ÿ¤^„`„xýþoA² ² > FigureSpace`;$„2„(¤$d%d&d'dNÆÿOÆÿPÆÿQÆÿ]„2^„(a$TþoAT ² >Warning+< & F Æ„„;üd$ÿ¤^„`„;ü\# A\ ² >Table of Figures!= Ƅ𠄄pþ¤^„`„pþJþo±âJ ² > CellBitClear> & FdLÿ¤¤>þoáò> ² > CellBitSet? & F ÆÐRþoR ² >zHeading_1_Appendix@ & F Æzþoz ² >zHeading_2_Appendix/A$ & F ÆHd¬þ¤&dPÆÿ 6CJ ]rþor ² >zHeading_3_Appendix'B$ & FdÔþ¤h&dPÆÿ 6CJ]Xþo2X ² >List (Numbered_List)C & F* Æh@¤<vþov ² >zHeading_4_Appendix+D$ & Fdüþ¤,¤&dPÆÿ 6CJ]vþov ² >zHeading_5_Appendix+E$ & Fdÿ¤,¤d&dPÆÿ 6CJ]8þoqb8 ² > NotesTable F & F @þor@ ² > NoteTableG & F ¤x@&CJ|þo±‚| ² >CellBodyCenter5H$ ưú ûü€ýpþ`ÿP@„„]„^„a$^JhmH sH pþo’p² >Heading (LOT,LOF)I„ìúd¬þ¤ð¤ð^„ìú5B* CJmHnHph`¨u.) ¢¡. ² > Page NumberNþo¢±N ² >Cross-Reference>*B* CJOJQJph`¨FV`¢ÁF ² >FollowedHyperlink >*B* ph€€:þo¢Ñ: ² > Code Font@ˆöÿCJOJ QJ @j ±²@ ² >Comment SubjectN5\@+ ò@ ² > Endnote TextO CJOJQJ\`A\ ² > Footnote TextP Æ@@„@dLÿ¤^„@ CJOJQJ`þoA` ² >Formula,Q Æp@ à°„Èdèþ¤Ü¤Ü^„È CJOJQJ@þoA"@ ² >HiddenR<B*CJOJQJphÿF``2F ² > HTML AddressS6CJOJQJ]Ne`BN ² >HTML PreformattedTCJOJ QJ ^J F `F ² >Index 1U„È„8ÿ^„È`„8ÿ CJOJQJF F ² >Index 2V„„8ÿ^„`„8ÿ CJOJQJF F ² >Index 3W„X„8ÿ^„X`„8ÿ CJOJQJF F ² >Index 4X„ „8ÿ^„ `„8ÿ CJOJQJF F ² >Index 5Y„è„8ÿ^„è`„8ÿ CJOJQJF F ² >Index 6Z„°„8ÿ^„°`„8ÿ CJOJQJF F ² >Index 7[„x„8ÿ^„x`„8ÿ CJOJQJF F ² >Index 8\„@„8ÿ^„@`„8ÿ CJOJQJF F ² >Index 9]„„8ÿ^„`„8ÿ CJOJQJL! RL ² > Index Heading^5CJOJQJ\^Jt- ñÿòt ² > Macro Text&_ Æ àÀ €` @ à¤È OJ PJQJ ^J _HmH sH tH D^`D ² > Normal (Web)`CJOJQJaJ>`> ² > Normal Indent a„Ð^„Ðzš ³#z ² > Table Grid?:VbÖ0ÿÿÿÿÿÿjÖ4b¤ÈPJ`, ` ² >Table of Authoritiesc„È„8ÿ^„È`„8ÿ CJOJQJ*þoòÿA* ² >Italic6]\þoòÿQ\ ² > Superscript-6>*@ˆB*CJH*OJQJ]^JaJphTþoòÿaT ² > Helvetica8'>*@ˆB*CJH*OJQJ^JaJph:þor: ² > Bullet+auto g & F$L`$ ² >Datehzþoz j² > Pseudocode<i Æ 7SnŠ¥ÁÜø  @@@@@@@@@@¤x¤x*$7$8$H$m$CJOJ QJ ^JRþo¢¡R i² >Pseudocode CharOJ QJ ^J_HmH sH tH <þo¢±< ² >codefont@ˆöÿOJ QJ ^J o(@þo¢Á@ ² > registerfontOJQJ^Jo(FþoÒF ² > tablecell m¤(¤CJOJQJaJ@& ¢á@ ² >Footnote ReferenceH*JþoAòJ ² >Reg_Fig (bit#)o¤ B*CJphÿHþoñH ² >Reg_Fig (field)p$¤d¤da$>?`> ² >Closing q„à^„à CJOJQJ<[`"< ² >E-mail Signaturerp$`2p ² >Envelope Address!s„@ „üÿ„ôÿ„ð&€+D¼/„´^„@ CJOJQJ^JaJJ%`BJ ² >Envelope ReturntCJOJQJ^J4/`R4 ² >Listu„h„˜þ^„h`„˜þD2`bD ² >List 2v„Є˜þ^„Ð`„˜þ CJOJQJD3`rD ² >List 3w„8„˜þ^„8`„˜þ CJOJQJD4`‚D ² >List 4x„ „˜þ^„ `„˜þ CJOJQJD5`’D ² >List 5y„„˜þ^„`„˜þ CJOJQJV0`¢V ² > List Bulletz Æh„h„˜þ^„h`„˜þ CJOJQJbþo²b ² >List Bullet 1,lb1,Lb1{„h„˜þ^„h`„˜þ CJOJQJv6`Âv ² >List Bullet 2,lb2,lb21,lb22| ÆÐ„Є˜þ^„Ð`„˜þ CJOJQJZ7`ÒZ ² > List Bullet 3} Æ8„8„˜þ^„8`„˜þ CJOJQJZ8`âZ ² > List Bullet 4~ Æ „ „˜þ^„ `„˜þ CJOJQJZ9`òZ ² > List Bullet 5 Æ„„˜þ^„`„˜þ CJOJQJND`N ² > List Continue€„h¤x^„h CJOJQJRE`R ² >List Continue 2„Фx^„Ð CJOJQJRF`"R ² >List Continue 3‚„8¤x^„8 CJOJQJRG`2R ² >List Continue 4ƒ„ ¤x^„  CJOJQJRH`BR ² >List Continue 5„„¤x^„ CJOJQJV1`RV ² > List Number… Æh„h„˜þ^„h`„˜þ CJOJQJZ:`bZ ² > List Number 2† ÆÐ„Є˜þ^„Ð`„˜þ CJOJQJZ;`rZ ² > List Number 3‡ Æ8„8„˜þ^„8`„˜þ CJOJQJZ<`‚Z ² > List Number 4ˆ Æ „ „˜þ^„ `„˜þ CJOJQJZ=`’Z ² > List Number 5‰ Æ„„˜þ^„`„˜þ CJOJQJ4O`4 ² > Note HeadingŠVþo²V ² >numbered$‹$ ÆT„®„˜þ¤^„®`„˜þa$OJQJ@Z`Â@ ² > Plain TextŒCJOJ QJ ^J NJ`ÒN ² >Subtitle$¤<@&a$CJOJQJ^JaJV>`âV ² >TitleŽ$¤ð¤<@&a$5CJ KHOJQJ\^JaJ Ã0ÿÿÿÿÄ0š0€€€€Ä0š0€€€€AYZ[\ FP$©¡ª a ¶ ` ±  Y « ÿ R ¦ ¨ µ Ü {„“óᯱÀË^e­ßù9¦ÎôRy–³Ð?[u¬ì,£Ï]yƒÅÝí÷_gŽ˜ÕBj´àü/COYBJ_hq“›¸ÂÑßéT\–·$Kp“åù8A]g‚§8?‡ºÔé#@Jq}‡øÿR • ¶ ¿ ß [!|!£!Á!ò!"V"h"¤"¿" ###\$y$Ÿ$À$è$%3%=%Z%d%¡%ç%ø%&G&&&š&-'4'w'€'®'(B(g(Š(Ÿ(ñ()B)¹)Á)Þ)è)*-*a*n*y*++_+h+–+,*,O,r,‡,ð,-e-‘-™-¶-À-æ-.9.F.Q.¾/Å/ä/í/þ/[0^0l0t0‘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€€˜80€€˜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€±€˜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€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C 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€€˜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€ &˜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€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€˜@0€€€è00˜@0€€€è00˜@0€€è00˜@0€€è00˜@0€€€˜@0€€˜@0€€˜@0€€è004 AYZ FP$©¡ª¨ µ Ü {„“ÀË^e­ßù9¦ÎôRy–³Ð?[u¬ì,£Ï]yƒÅí÷_gŽ˜ÕBj´àü/OYBJ_hq“›¸ÂßéT\–·$Kp“åA]g‚§8?‡ºÔé#@J}‡øÿR • ¶ ¿ ß [!|!£!Á!ò!"V"h"¤"¿" ###\$y$Ÿ$À$è$%3%=%Z%d%¡%ç%ø%&G&&š&-'4'w'€'®'(B(g(Š(Ÿ(ñ()B)¹)Á)Þ)è)*-*n*y*++_+h+–+,*,O,r,‡,ð,-e-‘-™-¶-À-æ-.F.Q.¾/Å/ä/í/þ/[0l0t0‘0›0Ä0š@0€€š@0€€€š@0€€€š@0€€€š@0€€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€€ @ 0€€š@0€¥š@0€¥ @ 0€€€A 0kk€A 066€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€Fš@0€F€š@0€F€š@0€F€š@0€F€A 066€š@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€A 066š@0€)!š@0€)!š@0€)!š@0€)!€š@0€)!š@0€)!€š@0€)!€š@0€)!€š@0€)!€š@0€)!€A 066€š@0€º"š@0€º"€š@0€º"š@0€º"€š@0€º"š@0€º"€š@0€º"€š@0€º"€š@0€º"€š@0€º"€š@0€º"š@0€º"š@0€º"š@0€º"€š@0€º"€A 066€š@0€&š@0€&€š@0€&š@0€&š@0€&š@0€&š@0€&š@0€&š@0€&š@0€&€š@0€&€š@0€&€A 066š@0€6(š@0€6(š@0€6(š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(A 066€š@0€41€š@0€41€š@0€41š@0€41š@0€41š@0€41€š@0€41€š@0€41€š@0€41€š@0€41€š@0€41š@0€41š@0€41€š@0€41š@0€41š@0€41€š@0€41š@0€41€š@0€41š@0€41A 066€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5Hš@0€}5Hš@0€}5€š@0€}5š@0€}5A 066€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5Hš@0€}5Hš@0€}5€š0€€€€ ½ Å[ÕZÐRÊK§ƒùÃ…Ó!Þ"B%Ô&Q(Ñ)d-4/Ë0y2'4Ö5Ÿ8Ã8 !"#%&'()*+-.0135689;=>@ACDF¶^uÕ¸"A%R(è,B0h3¾7»8Ã8$,/247:<?BEGÂ8e‰žªÂÃãó    4 @ \ ^ _ a • ± ³ ´ ¶ Ö ê   + ? [ ] ^ ` € ¬ ® ¯ ± Ñ ã ÿ    % 7 S V W Y y ‰ ¥ ¨ © « Ë Ý ù ü ý ÿ  0 L O P R r „   £ ¤ ¦ Ã0Xÿ„ ÿX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•ÌX”ÿ%ÿ•À•Ì•Œðtð  ð,2ð$ƽb ŒÔÔ«/d×ÄÝaµ•ÿTe<@ñÿÿÿ€€€÷ð’ ðð0ð( ð ððB ðS ð¿Ëÿ ?ððÈðð°ð( ð ððx² ð S ð:AÁÿ¿ intel_rgb_100"ñ¿`ððlÒüÿÿÜ#5t@ÿÿ _Toc156967727 _Toc176025230 _Toc166414669 _Toc176025231 _Toc166414670 _Toc176025232 _Toc176025233 _Toc166414671 _Toc176025234 _Toc166414672 _Toc176025235 _Toc166414673 _Toc176025236 _Toc166414674 _Toc176025237 _Toc166414675 _Toc176025238 _Toc166414676 _Toc176025239 _Toc166414677 _Toc176025240 _Toc176025241¨ {{„„±ÞÞ´DOÒrr‚&‚&b*b*:.Ä0 ´ {‚ƒ’¿¿ììNNÞÞœœ||Ž&Ž&m*m*E.Ä0ÿÿ 7I¨BÜ,— 8I¨BDvR9I¨B¬S˜ :I¨B$@R;I¨Bì¬VI¨BÔV?I¨Bl$V@I¨B´ëVAI¨Bü^"BI¨BL€"NNRïïóÞ&Þ&â&Ä0   QTTòõõá&ä&ä&Ä0  9 *€urn:schemas-microsoft-com:office:smarttags€place€9 *€urn:schemas-microsoft-com:office:smarttags€State€8 *€urn:schemas-microsoft-com:office:smarttags€City€ œ»Ú õøû…Ä_fguvˆŠ‘”—¡£°.qtw‚S ” h(k(n(x(y(†(P,S,V,`,a,n,°0°0²0²0³0³0µ0¶0¸0¹0»0¼0Á0Ä0\¹ô…Ä_fg³.p’8AR ” g(‰(O,q,°0°0²0²0³0³0µ0¶0¸0¹0»0¼0Á0Ä03¡ª¨ µ {“±ËÇÜÝ÷1BCY¸éåø§q‡&š&a*y*æ-8.9.Q.‘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&þÿÿÿüþïÿ3˜\?ÿÿÿÿÿÿÿÿÿèK‡t1ÿÿÿÿ]\“ (ÑCÿÿÿÿÿÿÿÿVC ìöäÿÿÿÿÿÿÿÿÿä B(Ñÿÿÿÿÿÿÿÿÿg†øbPÙÿÿÿÿÿÿÿÿÿ)k“êE\ngÿÿÿÿÿÿÿÿfvl°†Òÿÿÿÿÿÿÿÿÿ©;¦ D:¸"-WŠ!˜8(mÿÿÿÿÿÿÿÿÿ‹N#ì媒ÿÿÿÿÿÿÿÿÿCF$~”ÿGÿÿÿÿÿÿÿÿÝL%ÄÌ„þ?ÿÿÿÿÿÿÿÿ¶"Í'|† ÿœÝ*VÀ¨ÿÿÿÿÿÿÿÿÿeâD(ÑÿÿÿÿÿÿÿÿÿzH£LzT~P*'GR效ñÿÿÿÿÿÿÿÿÿdU’S˜˜8ÿ,Ó2¾Te¬24ÏRûUnq~1 ({\ì媒F9ÿÿÿÿÿÿÿ%n]ªwÿÿÿÿÿÿÿÿÿ1cí^tŠï@ABDEÿÿÿÿŒb_¸Yšÿÿÿÿÿÿÿÿÿ¤!Ò`,jP—ÿÿÿÿÿÿÿÿÿŒY5fb½øa/ÿÿÿÿÿÿÿÿ÷hZiþ/~áÿÿÿÿÿÿÿBqŠn(Ñÿÿÿÿÿÿÿÿÿ"*Fo„Iâò<a>ipÈt£ÿÿÿÿÿÿÿÿÿeG‰u¶â"@>ÿÿÿÿÿÿÿÿt#¢|(Ñÿÿÿÿÿÿÿÿÿ*h „Є˜þÆÐ^„Ð`„˜þ‡hˆH.h„ „˜þÆ ^„ `„˜þ.’h„p„LÿÆp^„p`„Lÿ.h„@ „˜þÆ@ ^„@ `„˜þ.h„„˜þÆ^„`„˜þ.’h„à„LÿÆà^„à`„Lÿ.h„°„˜þư^„°`„˜þ.h„€„˜þÆ€^„€`„˜þ.’h„P„LÿÆP^„P`„Lÿ.„„ìúÆ^„`„ìúo(„„ìúÆ^„`„ìúo(.„„ìúÆ^„`„ìúo(..„„ìúÆô^„`„ìúo(... „„ìúÆ\^„`„ìúo( ....ÿ„œ„XüÆœ^„œ`„Xüo( „”„ÈûÆ”^„”`„Èûo(....... „Œ „8ûÆŒ ^„Œ `„8ûo(........ „Ì „`úÆÌ ^„Ì `„`úo(.........„h„˜þÆÐ^„h`„˜þo(.„„PþÆ^„`„Pþo(.„È„þÆÈ^„È`„þo(.„À„xýÆÀ^„À`„xýo(. „¸„èüÆØ ^„¸`„èüo( ..... „° „XüÆ@ ^„° `„Xüo( ...... „¨ „ÈûÆ^„¨ `„Èûo(....... „ „8ûÆx^„ `„8ûo(........ „à„`úÆH^„à`„`úo(.........„Є˜þÆÐ^„Ð`„˜þo(.€ „ „˜þÆ ^„ `„˜þ‡hˆH.‚ „p„LÿÆp^„p`„Lÿ‡hˆH.€ „@ „˜þÆ@ ^„@ `„˜þ‡hˆH.€ „„˜þÆ^„`„˜þ‡hˆH.‚ „à„LÿÆà^„à`„Lÿ‡hˆH.€ „°„˜þư^„°`„˜þ‡hˆH.€ „€„˜þÆ€^„€`„˜þ‡hˆH.‚ „P„LÿÆP^„P`„Lÿ‡hˆH.„h„˜þÆÐ^„h`„˜þo(.„„PþÆ^„`„Pþo(.„È„þÆÈ^„È`„þo(.„À„xýÆÀ^„À`„xýo(. „¸„èüÆØ ^„¸`„èüo( ..... „° „XüÆ@ ^„° `„Xüo( ...... „¨ „ÈûÆ^„¨ `„Èûo(....... „ „8ûÆx^„ `„8ûo(........ „à„`úÆH^„à`„`úo(.........h„Є˜þÆÐ^„Ð`„˜þ.h „ „˜þÆ ^„ `„˜þ‡hˆH.’h „p„LÿÆp^„p`„Lÿ‡hˆH.h „@ „˜þÆ@ ^„@ `„˜þ‡hˆH.h „„˜þÆ^„`„˜þ‡hˆH.’h „à„LÿÆà^„à`„Lÿ‡hˆH.h „°„˜þư^„°`„˜þ‡hˆH.h „€„˜þÆ€^„€`„˜þ‡hˆH.’h „P„LÿÆP^„P`„Lÿ‡hˆH.h„Є˜þÆÐ^„Ð`„˜þOJQJo(‡hˆH·ðh„ „˜þÆ ^„ `„˜þOJ QJ ^J o(‡hˆHoh„p„˜þÆp^„p`„˜þOJ QJ o(‡hˆH§ðh„@ „˜þÆ@ ^„@ `„˜þOJQJo(‡hˆH·ðh„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHoh„à„˜þÆà^„à`„˜þOJ QJ o(‡hˆH§ðh„°„˜þư^„°`„˜þOJQJo(‡hˆH·ðh„€„˜þÆ€^„€`„˜þOJ QJ ^J o(‡hˆHoh„P„˜þÆP^„P`„˜þOJ QJ o(‡hˆH§ð„h„˜þÆh^„h`„˜þ.„ „˜þÆ ^„ `„˜þOJQJo(‡hˆH·ð’ „p„LÿÆp^„p`„Lÿ‡hˆH. „@ „˜þÆ@ ^„@ `„˜þ‡hˆH. „„˜þÆ^„`„˜þ‡hˆH.’ „à„LÿÆà^„à`„Lÿ‡hˆH. „°„˜þư^„°`„˜þ‡hˆH. „€„˜þÆ€^„€`„˜þ‡hˆH.’ „P„LÿÆP^„P`„Lÿ‡hˆH. „„ØÆ¨^„`„ØOJQJo(¾ðh„Є˜þÆÐ^„Ð`„˜þ.h„ „˜þÆ ^„ `„˜þ.’h„p„LÿÆp^„p`„Lÿ.h„@ „˜þÆ@ ^„@ `„˜þ.h„„˜þÆ^„`„˜þ.’h„à„LÿÆà^„à`„Lÿ.h„°„˜þư^„°`„˜þ.h„€„˜þÆ€^„€`„˜þ.’h„P„LÿÆP^„P`„Lÿ.ÿ"„h„˜þÆÐ^„h`„˜þ56;CJOJQJo(‡hˆHNOTES:„„PþÆ^„`„PþCJOJQJo(‡hˆH. „È„þÆÈ^„È`„þo(‡hˆH... „À„xýÆÀ^„À`„xýo(‡hˆH.... „¸„èüƸ^„¸`„èüo(‡hˆH ..... „° „Xüư ^„° `„Xüo(‡hˆH ...... „¨ „Èûƨ ^„¨ `„Èûo(‡hˆH.......  „ „8ûÆ ^„ `„8ûo(‡hˆH........  „à„`úÆà^„à`„`úo(‡hˆH.........ÿ"„h„˜þÆÐ^„h`„˜þ56;CJOJQJo(‡hˆHNOTE:„„PþÆ^„`„PþCJOJ QJ o(‡hˆH. „È„þÆÈ^„È`„þo(‡hˆH... „À„xýÆÀ^„À`„xýo(‡hˆH.... „¸„èüƸ^„¸`„èüo(‡hˆH ..... „° „Xüư ^„° `„Xüo(‡hˆH ...... „¨ „Èûƨ ^„¨ `„Èûo(‡hˆH.......  „ „8ûÆ ^„ `„8ûo(‡hˆH........  „à„`úÆà^„à`„`úo(‡hˆH.........ÿ„h„˜þÆh^„h`„˜þ1 = „Є˜þÆÐ^„Ð`„˜þ)„8„˜þÆ8^„8`„˜þ)„ „˜þÆ ^„ `„˜þ()„„˜þÆ^„`„˜þ()„p„˜þÆp^„p`„˜þ()„Ø „˜þÆØ ^„Ø `„˜þ.„@ „˜þÆ@ ^„@ `„˜þ.„¨ „˜þƨ ^„¨ `„˜þ.@h„h„˜þ^„h`„˜þ.h„Є˜þÆÐ^„Ð`„˜þ.h„ „˜þÆ ^„ `„˜þ.h„p„LÿÆp^„p`„Lÿ.h„@ „˜þÆ@ ^„@ `„˜þ.h„„˜þÆ^„`„˜þ.h„à„LÿÆà^„à`„Lÿ.h„°„˜þư^„°`„˜þ.h„€„˜þÆ€^„€`„˜þ.h„P„LÿÆP^„P`„Lÿ.ÿ„„ìúÆ^„`„ìúo(„þ„PþÆ$ÿ^„þ`„Pþo(.„´ÿ„þÆô^„´ÿ`„þo(..„¬„xýÆ,^„¬`„xýo(... „¤„èüÆü^„¤`„èüo( ....ÿ„œ„XüÆœ^„œ`„Xüo( „”„ÈûÆ”^„”`„Èûo(....... „Œ „8ûÆŒ ^„Œ `„8ûo(........ „Ì „`úÆÌ ^„Ì `„`úo(.........h„Є˜þÆÐ^„Ð`„˜þOJQJo(‡hˆH·ðh„ „˜þÆ ^„ `„˜þOJ QJ ^J o(‡hˆHoh„p„˜þÆp^„p`„˜þOJ QJ o(‡hˆH§ðh„@ „˜þÆ@ ^„@ `„˜þOJQJo(‡hˆH·ðh„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHoh„à„˜þÆà^„à`„˜þOJ QJ o(‡hˆH§ðh„°„˜þư^„°`„˜þOJQJo(‡hˆH·ðh„€„˜þÆ€^„€`„˜þOJ QJ ^J o(‡hˆHoh„P„˜þÆP^„P`„˜þOJ QJ o(‡hˆH§ðh„h„˜þÆh^„h`„˜þ.h„8„˜þÆ8^„8`„˜þ.’h„„LÿÆ^„`„Lÿ.h„Ø „˜þÆØ ^„Ø `„˜þ.h„¨ „˜þƨ ^„¨ `„˜þ.’h„x„LÿÆx^„x`„Lÿ.h„H„˜þÆH^„H`„˜þ.h„„˜þÆ^„`„˜þ.’h„è„LÿÆè^„è`„Lÿ.ÿ„|ý„ÆL^„|ý`„56CJOJQJo(‡hˆHNote: „|ý„Æ´^„|ý`„o(‡hˆH Section . „L„PþÆL^„L`„Pþo(‡hˆH() „Ü„pÿÆÜ^„Ü`„pÿo(‡hˆH() „l„PþÆl^„l`„Pþo(‡hˆH) „ü„PþÆü^„ü`„Pþo(‡hˆH) „Œ„àþÆŒ^„Œ`„àþo(‡hˆH) „„PþÆ^„`„Pþo(‡hˆH. „¬„pÿƬ^„¬`„pÿo(‡hˆH. „h„˜þÆÐ^„h`„˜þo(‡hˆH. „„PþÆ^„`„Pþo(‡hˆH. „È„þÆÈ^„È`„þo(‡hˆH. „À„xýÆÀ^„À`„xýo(‡hˆH. „¸„èüÆØ ^„¸`„èüo(‡hˆH ..... „° „XüÆ@ ^„° `„Xüo(‡hˆH ...... „¨ „ÈûÆ^„¨ `„Èûo(‡hˆH.......  „ „8ûÆx^„ `„8ûo(‡hˆH........  „à„`úÆH^„à`„`úo(‡hˆH.........„x„ˆÿÆh^„x`„ˆÿB*OJQJo(·ð„h„˜þÆh^„h`„˜þOJQJo(‡hˆH·ð„ „˜þÆ ^„ `„˜þOJ QJ ^J o(‡hˆHo„p„˜þÆp^„p`„˜þOJ QJ o(‡hˆH§ð„@ „˜þÆ@ ^„@ `„˜þOJQJo(‡hˆH·ð„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHo„à„˜þÆà^„à`„˜þOJ QJ o(‡hˆH§ð„°„˜þư^„°`„˜þOJQJo(‡hˆH·ð„€„˜þÆ€^„€`„˜þOJ QJ ^J o(‡hˆHo„P„˜þÆP^„P`„˜þOJ QJ o(‡hˆH§ð„Ø„(ÿÆh^„Ø`„(ÿB*OJQJo(·ðÿ>„ þ„˜þÆð^„ þ`„˜þ56789;<CJH*CJOJQJS*TXo(‡hˆHCaution: „h„˜þÆÐ^„h`„˜þOJQJo(¾ðÿ"„h„˜þÆÐ^„h`„˜þ56;CJOJQJo(‡hˆHNOTES:„„PþÆ^„`„PþCJOJQJo(‡hˆH. „È„þÆÈ^„È`„þo(‡hˆH... „À„xýÆÀ^„À`„xýo(‡hˆH.... „¸„èüƸ^„¸`„èüo(‡hˆH ..... „° „Xüư ^„° `„Xüo(‡hˆH ...... „¨ „Èûƨ ^„¨ `„Èûo(‡hˆH.......  „ „8ûÆ ^„ `„8ûo(‡hˆH........  „à„`úÆà^„à`„`úo(‡hˆH.........h„8„˜þÆ8^„8`„˜þOJQJo(‡hˆH·ðh„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHoh„Ø „˜þÆØ ^„Ø `„˜þOJ QJ o(‡hˆH§ðh„¨ „˜þƨ ^„¨ `„˜þOJQJo(‡hˆH·ðh„x„˜þÆx^„x`„˜þOJ QJ ^J o(‡hˆHoh„H„˜þÆH^„H`„˜þOJ QJ o(‡hˆH§ðh„„˜þÆ^„`„˜þOJQJo(‡hˆH·ðh„脘þÆè^„è`„˜þOJ QJ ^J o(‡hˆHoh„¸„˜þƸ^„¸`„˜þOJ QJ o(‡hˆH§ð „Tü„˜þÆ,^„Tü`„˜þo( Appendix „„ìúÆ^„`„ìúo(.„„ìúÆ^„`„ìúo(..„„ìúÆô^„`„ìúo(... „„ìúÆ\^„`„ìúo( ....ÿ„œ„XüÆœ^„œ`„Xüo( „”„ÈûÆ”^„”`„Èûo(....... „Œ „8ûÆŒ ^„Œ `„8ûo(........ „Ì „`úÆÌ ^„Ì `„`úo(.........h„Є˜þÆÐ^„Ð`„˜þOJQJo(‡hˆH·ðh„ „˜þÆ ^„ `„˜þOJ QJ ^J o(‡hˆHoh„p„˜þÆp^„p`„˜þOJ QJ o(‡hˆH§ðh„@ „˜þÆ@ ^„@ `„˜þOJQJo(‡hˆH·ðh„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHoh„à„˜þÆà^„à`„˜þOJ QJ o(‡hˆH§ðh„°„˜þư^„°`„˜þOJQJo(‡hˆH·ðh„€„˜þÆ€^„€`„˜þOJ QJ ^J o(‡hˆHoh„P„˜þÆP^„P`„˜þOJ QJ o(‡hˆH§ðh„h„˜þÆh^„h`„˜þOJQJo(‡hˆH·ðh„8„˜þÆ8^„8`„˜þOJ QJ ^J o(‡hˆHoh„„˜þÆ^„`„˜þOJ QJ o(‡hˆH§ðh„Ø „˜þÆØ ^„Ø `„˜þOJQJo(‡hˆH·ðh„¨ „˜þƨ ^„¨ `„˜þOJ QJ ^J o(‡hˆHoh„x„˜þÆx^„x`„˜þOJ QJ o(‡hˆH§ðh„H„˜þÆH^„H`„˜þOJQJo(‡hˆH·ðh„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHoh„脘þÆè^„è`„˜þOJ QJ o(‡hˆH§ðÿ„h„˜þ^„h`„˜þ„„PþÆ8^„`„Pþ..„È„þÆÈ^„È`„þ...„À„xýÆÀ^„À`„xý.... „¸„èüƸ^„¸`„èü .....ÿ„° „Xüư ^„° `„Xü „¨ „Èûƨ ^„¨ `„Èû....... „ „8ûÆ ^„ `„8û........ „à„`úÆà^„à`„`ú.........Ð „ „˜þÆ ^„ `„˜þOJQJo(·ðÐ „ „˜þÆ ^„ `„˜þOJ QJ o(oÐ „p„˜þÆp^„p`„˜þOJ QJ o(§ðÐ „@ „˜þÆ@ ^„@ `„˜þOJQJo(·ðÐ „„˜þÆ^„`„˜þOJ QJ o(oÐ „à„˜þÆà^„à`„˜þOJ QJ o(§ðÐ „°„˜þư^„°`„˜þOJQJo(·ðÐ „€„˜þÆ€^„€`„˜þOJ QJ o(oÐ „P„˜þÆP^„P`„˜þOJ QJ o(§ð„h„˜þÆÐ^„h`„˜þo(.„„PþÆ^„`„Pþo(.„È„þÆÈ^„È`„þo(.„À„xýÆÀ^„À`„xýo(. „¸„èüÆØ ^„¸`„èüo( ..... „° „XüÆ@ ^„° `„Xüo( ...... „¨ „ÈûÆ^„¨ `„Èûo(....... „ „8ûÆx^„ `„8ûo(........ „à„`úÆH^„à`„`úo(.........ÿ>„¨ý„˜þÆx^„¨ý`„˜þ56789;<CJH*CJOJQJS*TXo(‡hˆHWarning:h„h„˜þÆh^„h`„˜þOJ QJ o(‡hˆH§ðh„8„˜þÆ8^„8`„˜þOJ QJ ^J o(‡hˆHoh„„˜þÆ^„`„˜þOJ QJ o(‡hˆH§ðh„Ø „˜þÆØ ^„Ø `„˜þOJQJo(‡hˆH·ðh„¨ „˜þƨ ^„¨ `„˜þOJ QJ ^J o(‡hˆHoh„x„˜þÆx^„x`„˜þOJ QJ o(‡hˆH§ðh„H„˜þÆH^„H`„˜þOJQJo(‡hˆH·ðh„„˜þÆ^„`„˜þOJ QJ ^J o(‡hˆHoh„脘þÆè^„è`„˜þOJ QJ o(‡hˆH§ðÿ„„Æ8^„`„0 = „ЄÆ8^„Ð`„.„ „Æ^„ `„.„p„ÆØ ^„p`„)„@ „ƨ ^„@ `„()„„Æx^„`„()„à„ÆH^„à`„()„°„Æ^„°`„()„€„Æè^„€`„() „h„˜þÆÐ^„h`„˜þo(‡hˆH. „„PþÆ^„`„Pþo(‡hˆH. „È„þÆÈ^„È`„þo(‡hˆH. „À„xýÆÀ^„À`„xýo(‡hˆH. „¸„èüÆØ ^„¸`„èüo(‡hˆH ..... „° „XüÆ@ ^„° `„Xüo(‡hˆH ...... „¨ „ÈûÆ^„¨ `„Èûo(‡hˆH.......  „ „8ûÆx^„ `„8ûo(‡hˆH........  „à„`úÆH^„à`„`úo(‡hˆH..........÷hZidU’SÏRûUeG‰uÝL%zH£L©;¦ èK]\“ ²9: ({\Ó2¾TCF$ŒY5f"*Fo)k“1cí^]\“ @’Û ]\“ Œ’Û ¶"Í'þÿÿÿØ’Û]\“ \“Û ]\“ ¨“Û P‘83WŠ!fvl%n]‹;•2Œb_eâD]\“ @”Û t#¢|]\“ Œ”Û œÝ*g†VC ä B]\“ Ø”Û a>ip‹N#'GR¤!Ò`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿä’Û`¡?@%„„^„`„567>*CJOJQJ^Jo(ph" ÿÿÿÿSøð˜øðÿÿÿÿ“Tÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‘ÿÿÿR¨„iUnV WdXÿÿÿÿÿÿÿÿ’iRi(TbUdVshÿÿÿÿÿÿÿÿ“lr Tlr ˜lr ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ”Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ&ÿÿ&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ         ÿÿÿÿ        ’}f§        ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ         ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿrJâç        ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ         ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÆQ¶Ý*Ý„Õ       ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ         ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¢å¡H+¸ n;b J d õZ k ¸;€5 ˜rüÒT™K+øYß@Ó. µc Âe!zi!Ä"%"øO(ø/+oT+]|+Q,‡.5[.F1´F1ù 363À4?`5þ>6¼7:f8C :ã8:;4;.%=² >{#?Z@\ B'D¾uG68Kb N‡oOòERÒHSVQNWåjW7&YŠ[®%\Üda¾{ÚÎÜ© ݘ[Ýß-\ßÔnßO7ã}ã ä$åjhå‡:æÈVê-ìå íú:ðhbò6ó¯XóŽ+öà`ø­GúûÇ'ü@ùÄ0KKKKÿ@€@@ˆ…x @@Ã0`@ÿÿUnknownÿÿÿÿÿÿÿÿÿÿÿÿ G‡: ÿTimes New Roman5€Symbol3& ‡: ÿArialG5€  ¿ ûüÇhŸMS Mincho-ÿ3ÿ fg;†SimSun‹[SO7& ‡ ŸVerdanacGaramond BookTimes New Roman5& ‡za€ÿTahoma71 Courier?5 ‡z €ÿCourier New;€Wingdings;" Helvetica 1Hˆ¤¨h¸DµF¬ä»fL~Dl)XDl)X!-!),.:;?]}¨·ÇÉ    & 6"0000 0 0 00000ÿÿÿ ÿ ÿÿÿÿÿ=ÿ@ÿ\ÿ]ÿ^ÿàÿ([{·  0 0 00000ÿÿ;ÿ[ÿáÿåÿ ´œ‚€d˜0˜02ƒqHP ðÿ?¨ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB¡2ÿÿSC:\Documents and Settings\jcihula\Application Data\Microsoft\Templates\TXT Spec.dotSIntel® Trusted Execution Technology  Launch Control Policy Linux Tools User Manual Joseph Cihula¤&                           ! " # $ % þÿà…ŸòùOh«‘+'³Ù0Ęô $< T` € Œ ˜¤¬´¼äTIntel® Trusted Execution Technology – Launch Control Policy Linux Tools User ManualTXT Spec.dotJoseph Cihula76Microsoft Office Word@t¨ Y@ Ð’å‘Ç@Øí±12ÈDl)þÿÕÍÕœ.“—+,ù®DÕÍÕœ.“—+,ù®L hpŒ”œ¤ ¬´¼Ä Ì ,äIntel CorporationX˜0' TIntel® Trusted Execution Technology – Launch Control Policy Linux Tools User Manual Titlel 8@ _PID_HLINKSäA$N7G) _Toc1760252417A) _Toc1760252407;) _Toc17602523975) _Toc1760252387/) _Toc1760252377)) _Toc1760252367#) _Toc1760252357) _Toc1760252347) _Toc1760252337) _Toc1760252327 ) _Toc1760252317) _Toc176025230Thttp://www.intel.com/)   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúþÿÿÿüýþÿþÿÿÿ      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstþÿÿÿvwxyz{|þÿÿÿ~€‚ƒ„þÿÿÿýÿÿÿýÿÿÿýÿÿÿýÿÿÿŠþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRoot Entryÿÿÿÿÿÿÿÿ ÀF e»12ÈŒ€Data ÿÿÿÿÿÿÿÿÿÿÿÿû1TableÿÿÿÿßâWordDocumentÿÿÿÿõSummaryInformation(ÿÿÿÿÿÿÿÿÿÿÿÿuDocumentSummaryInformation8ÿÿÿÿÿÿÿÿ}CompObjÿÿÿÿÿÿÿÿÿÿÿÿqÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ ÿÿÿÿ ÀFMicrosoft Office Word Document MSWordDocWord.Document.8ô9²qtboot-1.8.2/lcptools/Makefile0000644000175000017500000000470612365404264014371 0ustar rqwrqw# 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 LCP1_TARGETS := \ lcp_writepol \ lcp_readpol \ lcp_crtpconf \ lcp_crtpol LCP2_TARGETS := \ lcp_mlehash \ lcp_crtpol2 \ lcp_crtpollist \ lcp_crtpolelt \ tpmnv : $(TPMNV_TARGETS) lcp1 : $(LCP1_TARGETS) lcp_mlehash lcp2 : $(LCP2_TARGETS) # # universal rules # build : $(TPMNV_TARGETS) $(LCP1_TARGETS) $(LCP2_TARGETS) dist : install install : @set -e; for i in $(TPMNV_TARGETS) $(LCP1_TARGETS) $(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) $(TPMNV_TARGETS) $(LCP1_TARGETS) $(LCP2_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 v2 POLELT_PLUGINS := mle_elt.o pconf_elt.o custom_elt.o sbios_elt.o LCP2_LIB := liblcp.a $(LCP2_LIB) : pol.o poldata.o pollist.o polelt.o lcputils2.o hash.o $(AR) rc $@ $^ lcp_crtpolelt : crtpolelt.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp_crtpollist : crtpollist.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp_crtpol2 : crtpol2.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp_mlehash : mlehash.o $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -lz -o $@ # LCP v1 and tpmnv_* UTIL_OBJS := lcptools.o lcputils.o LIBS += -lcrypto -ltspi -lz $(TPMNV_TARGETS) : tpmnv_% : %.o $(UTIL_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ $(LCP1_TARGETS) : lcp_% : %.o $(UTIL_OBJS) $(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) trousers_dep $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.8.2/lcptools/pollist.h0000644000175000017500000000621312365404265014564 0ustar rqwrqw/* * pollist.h: * * Copyright (c) 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 __POLLIST_H__ #define __POLLIST_H__ extern bool verify_policy_list(const lcp_policy_list_t *pollist, size_t size, bool *no_sigblock, bool size_is_exact); extern void display_policy_list(const char *prefix, const lcp_policy_list_t *pollist, bool brief); extern lcp_policy_list_t *create_empty_policy_list(void); extern lcp_policy_list_t *add_policy_element(lcp_policy_list_t *pollist, const lcp_policy_element_t *elt); extern bool del_policy_element(lcp_policy_list_t *pollist, uint32_t type); extern bool verify_pollist_sig(const lcp_policy_list_t *pollist); extern void display_signature(const char *prefix, const lcp_signature_t *sig, bool brief); extern lcp_policy_list_t *add_signature(lcp_policy_list_t *pollist, const lcp_signature_t *sig); extern unsigned char *get_sig_block(const lcp_policy_list_t *pollist); extern void calc_policy_list_hash(const lcp_policy_list_t *pollist, lcp_hash_t *hash, uint8_t hash_alg); extern lcp_policy_list_t *read_policy_list_file(const char *file, bool fail_ok, bool *no_sigblock_ok); extern bool write_policy_list_file(const char *file, const lcp_policy_list_t *pollist); #endif /* __POLLIST_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/lcputils2.h0000644000175000017500000000574412365404265015027 0ustar rqwrqw/* * lcputils2.h: LCP utility fns * * Copyright (c) 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 __LCPUTILS2_H__ #define __LCPUTILS2_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 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); extern bool parse_file(const char *filename, bool (*parse_line)(const char *line)); extern const char *hash_alg_to_str(uint8_t alg); extern size_t get_lcp_hash_size(uint8_t hash_alg); extern bool verify_signature(const uint8_t *data, size_t data_size, const uint8_t *pubkey, size_t pubkey_size, const uint8_t *sig, bool is_sig_little_endian); #endif /* __LCPUTILS2_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/pol.c0000644000175000017500000001105312365404265013661 0ustar rqwrqw/* * pol.c: * * Copyright (c) 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. * */ #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 "polelt_plugin.h" #include "pol.h" #include "lcputils2.h" size_t get_policy_size(const lcp_policy_t *pol) { return offsetof(lcp_policy_t, policy_hash) + get_lcp_hash_size(pol->hash_alg); } bool verify_policy(const lcp_policy_t *pol, size_t size, bool silent) { 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 ( pol->hash_alg != LCP_POLHALG_SHA1 ) { 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->reserved1 != 0 || pol->reserved2[0] != 0 || pol->reserved2[1] != 0 ) { if ( !silent ) ERROR("Error: reserved fields not 0: %u, %u, %u\n", pol->reserved1, pol->reserved2[0], pol->reserved2[1]); return false; } return true; } void display_policy(const char *prefix, const lcp_policy_t *pol, bool brief) { (void)brief; /* quiet compiler warning portbly */ if ( pol == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pol->version); DISPLAY("%s hash_alg: %s\n", prefix, 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 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(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.8.2/lcptools/readpol.c0000644000175000017500000002047212365404265014522 0ustar rqwrqw/* * 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 #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 = strlen(password); 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.8.2/lcptools/polelt.h0000644000175000017500000000422212365404265014373 0ustar rqwrqw/* * polelt.h: * * Copyright (c) 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 __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.8.2/lcptools/crtpconf.c0000644000175000017500000001344512365404264014713 0ustar rqwrqw/* * 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. */ /* * crtpconf.c * * Command: lcp_crtpconf. * * This command can create PConf data for use when creating LCP policy data. * */ #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_INDEX 24 static uint8_t locality = 0x1f; static char *file = NULL; static unsigned char *pcr_val = NULL; static int help_input = 0; static const char *short_option = "hp:f:"; static const char *usage_string = "lcp_crtpconf "\ "-p PCR_index1,PCR_index2,...,PCR_indexn "\ "[-f filename] [-h]\n"; static const char * option_strings[] ={ "-p PCR_Index1,PCR_Index2,...: uint8. \n", "-f file name of SRTMMeasurement: string. Content is appended.\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 'p': pcr_val = (unsigned char *)optarg; break; case 'f': file = optarg; 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[]) { uint16_t i = 0; uint32_t index[MAX_INDEX] = {0}; uint32_t idx_num = 0; FILE *p_file = NULL; unsigned char* srtm_data = NULL; uint32_t data_len = 0; TPM_LOCALITY_SELECTION local_sel; 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; } /* * Parse command line string to get the PCR numbers. */ if ( pcr_val == NULL ) { log_error("Must input PCR numbers to creat PConf data.\n"); ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } idx_num = MAX_INDEX; str_split((char *)pcr_val, index, &idx_num); for ( i = 0; i < idx_num; i++ ) { if ( index[i] > 23 ) { ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } } local_sel = (TPM_LOCALITY_SELECTION)locality; ret_value = lcp_create_pconf(idx_num, index, 0, NULL, local_sel, &data_len, &srtm_data); if ( ret_value == LCP_SUCCESS ) { if ( file != NULL ) { /* * Write Platform configure data to file. */ p_file = fopen(file, "a"); if ( !p_file ) { log_error("Open file %s error!\n", file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } log_debug("Data length is %d.\n", data_len); if ( data_len != fwrite(srtm_data, 1, data_len, p_file) ) { log_error("Write SRTM data into file error!"\ "Data length is %d.\n",data_len); fclose(p_file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } fclose(p_file); } else print_hexmsg("the PConf data is:\n", data_len, srtm_data); free(srtm_data); } else goto _error_end; return LCP_SUCCESS; _error_end: /* * Error when execute. */ if ( srtm_data ) free(srtm_data); log_error("\nCommand CrtPConf failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.2/lcptools/lcputils.c0000644000175000017500000004321512365404265014733 0ustar rqwrqw/* * 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 #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(*container, object, size); (*container) += size; } void lcp_unloaddata(uint32_t size, unsigned char **container, unsigned char *object) { if ( *container == NULL || object == NULL ) return; memcpy(object, *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(pselect->pcrSelect, 0, bytes_to_hold); /* * 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(&pselect->pcrSelect[pselect->sizeOfSelect], 0, bytes_to_hold - pselect->sizeOfSelect); 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 ) sprintf(s, "unknown (%x)", (unsigned int)loc); else { if ( !(loc & 0x1f) ) strcat(s, "--, "); if ( loc & TPM_LOC_ZERO ) strcat(s, "0, "); if ( loc & TPM_LOC_ONE ) strcat(s, "1, "); if ( loc & TPM_LOC_TWO ) strcat(s, "2, "); if ( loc & TPM_LOC_THREE ) strcat(s, "3, "); if ( loc & TPM_LOC_FOUR ) strcat(s, "4, "); /* remove trailing ", " */ s[strlen(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.8.2/lcptools/lock.c0000644000175000017500000001062012365404265014016 0ustar rqwrqw/* * 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 confirm_lock[4] = {0}; 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 ) { int dummy; /* * 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) "); dummy = scanf("%3s", confirm_lock); if ( dummy <= 0 ) return LCP_E_COMD_INTERNAL_ERR; c = confirm_lock[0] | ' '; } 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.8.2/lcptools/crtpollist.c0000644000175000017500000004320212365404265015267 0ustar rqwrqw/* * crtpollist.c: Intel(R) TXT policy list (LCP_POLICY_LIST) creation tool * * Copyright (c) 2009-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 #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/lcp2.h" #include "../include/lcp_hlp.h" #include "polelt_plugin.h" #include "pollist.h" #include "polelt.h" #include "lcputils2.h" static const char help[] = "Usage: lcp_crtpollist [OPTION]\n" "Create an Intel(R) TXT policy list.\n\n" "--create\n" " [--ver ] version\n" " --out policy list file\n" " [FILE]... policy element files\n" "--sign\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\n" "--addsig\n" " --sig file containing signature (big-endian)\n" " --out policy list file\n" "--show\n" " policy list file\n" "--help\n" "--verbose enable verbose output; can be\n" " specified with any command\n\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'}, /* options */ {"ver", required_argument, NULL, 'v'}, {"out", required_argument, NULL, 'o'}, {"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'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; #define MAX_FILES 32 static uint16_t version = LCP_DEFAULT_POLICY_LIST_VERSION; static char pollist_file[MAX_PATH] = ""; 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 lcp_signature_t *read_pubkey_file(const char *file) { FILE *fp = fopen(file, "r"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", file, strerror(errno)); return NULL; } RSA *pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); 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(); return NULL; } unsigned int keysize = RSA_size(pubkey); if ( keysize == 0 ) { ERROR("Error: public key size is 0\n"); RSA_free(pubkey); return NULL; } lcp_signature_t *sig = malloc(sizeof(*sig) + 2*keysize); if ( sig == NULL ) { ERROR("Error: failed to allocate sig\n"); RSA_free(pubkey); return NULL; } memset(sig, 0, sizeof(*sig) + 2*keysize); sig->pubkey_size = keysize; if ( (unsigned int)BN_num_bytes(pubkey->n) != keysize ) { ERROR("Error: modulus size not match key size\n"); free(sig); RSA_free(pubkey); return NULL; } unsigned char key[keysize]; BN_bn2bin(pubkey->n, key); /* openssl key is big-endian and policy requires little-endian, so reverse bytes */ for ( unsigned int i = 0; i < keysize; i++ ) sig->pubkey_value[i] = *(key + (keysize - i - 1)); if ( verbose ) { LOG("signature:\n"); display_signature(" ", sig, false); } RSA_free(pubkey); return sig; } static bool sign_list_data(lcp_policy_list_t *pollist, const char *privkey_file) { if ( pollist == NULL || privkey_file == NULL ) return false; lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return false; /* read private key */ FILE *fp = fopen(privkey_file, "r"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", privkey_file, strerror(errno)); return false; } RSA *privkey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); if ( privkey == NULL ) { ERR_load_crypto_strings(); ERROR("Error: failed to read .pem file %s: %s\n", privkey_file, ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); return false; } if ( RSA_size(privkey) != sig->pubkey_size ) { ERROR("Error: private and public key sizes don't match\n"); RSA_free(privkey); return false; } /* first create digest of list (all except sig_block) */ tb_hash_t digest; if ( !hash_buffer((const unsigned char *)pollist, get_policy_list_size(pollist) - sig->pubkey_size, &digest, TB_HALG_SHA1_LG) ) { ERROR("Error: failed to hash list\n"); RSA_free(privkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(TB_HALG_SHA1_LG)); } /* sign digest */ /* work on buffer because we need to byte swap before putting in policy */ uint8_t sigblock[sig->pubkey_size]; unsigned int sig_len = sig->pubkey_size; if ( !RSA_sign(NID_sha1, (const unsigned char *)&digest, get_hash_size(TB_HALG_SHA1_LG), sigblock, &sig_len, privkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to sign list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(privkey); return false; } if ( sig_len != sig->pubkey_size ) { ERROR("Error: signature length mismatch\n"); RSA_free(privkey); return false; } RSA_free(privkey); /* sigblock is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->pubkey_size; i++ ) *(get_sig_block(pollist) + i) = *(sigblock + (sig->pubkey_size - i - 1)); if ( verbose ) { LOG("signature:\n"); display_signature(" ", sig, false); } return true; } static int create(void) { lcp_policy_list_t *pollist = create_empty_policy_list(); if ( pollist == NULL ) return 1; pollist->version = version; 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; } pollist = add_policy_element(pollist, elt); if ( pollist == NULL ) return 1; } bool write_ok = write_policy_list_file(pollist_file, pollist); free(pollist); return write_ok ? 0 : 1; } static int sign(void) { /* read existing policy list file */ bool no_sigblock_ok = true; lcp_policy_list_t *pollist = read_policy_list_file(pollist_file, false, &no_sigblock_ok); if ( pollist == NULL ) return 1; /* read public key file */ lcp_signature_t *sig = read_pubkey_file(pubkey_file); if ( sig == NULL ) { free(pollist); return 1; } /* check public key size */ if ( (sig->pubkey_size != 128 /* 1024 bits */) && (sig->pubkey_size != 256 /* 2048 bits */) && (sig->pubkey_size != 384 /* 3072 bits */) ) { ERROR("Error: public key size is not 1024/2048/3072 bits\n"); free(sig); free(pollist); return 1; } sig->revocation_counter = rev_ctr; pollist = add_signature(pollist, sig); if ( pollist == NULL ) { free(sig); return 1; } pollist->sig_alg = LCP_POLSALG_RSA_PKCS_15; if ( no_sigblock ) memset(get_sig_block(pollist), 0, sig->pubkey_size); else { if ( !sign_list_data(pollist, privkey_file) ) { free(sig); free(pollist); return 1; } } bool write_ok = write_policy_list_file(pollist_file, pollist); free(sig); free(pollist); return write_ok ? 0 : 1; } static int addsig(void) { /* read existing policy list file */ bool no_sigblock_ok = true; lcp_policy_list_t *pollist = read_policy_list_file(pollist_file, false, &no_sigblock_ok); if ( pollist == NULL ) return 1; lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) { free(pollist); return 1; } /* check public key size */ if ( (sig->pubkey_size != 128 /* 1024 bits */) && (sig->pubkey_size != 256 /* 2048 bits */) && (sig->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->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_signature((const unsigned char *)pollist, get_policy_list_size(pollist) - sig->pubkey_size, sig->pubkey_value, sig->pubkey_size, data, false) ) { ERROR("Error: signature file does not match policy list\n"); free(pollist); free(data); return 1; } LOG("signature file verified\n"); /* data is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->pubkey_size; i++ ) *(get_sig_block(pollist) + i) = *(data + (sig->pubkey_size - i - 1)); if ( verbose ) { LOG("signature:\n"); display_signature(" ", sig, false); } bool write_ok = write_policy_list_file(pollist_file, pollist); free(pollist); free(data); return write_ok ? 0 : 1; } static int show(void) { /* read existing file */ bool no_sigblock_ok = true; lcp_policy_list_t *pollist = read_policy_list_file(files[0], false, &no_sigblock_ok); if ( pollist == NULL ) return 1; DISPLAY("policy list file: %s\n", files[0]); display_policy_list("", pollist, false); if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 && !no_sigblock_ok ) { if ( verify_pollist_sig(pollist) ) DISPLAY("signature verified\n"); else DISPLAY("failed to verify signature\n"); } return 0; } 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); switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* sign */ case 'A': /* addsig */ case 'W': /* show */ 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 'v': /* version */ version = strtoul(optarg, NULL, 0); LOG("cmdline opt: ver: 0x%x (%u)\n", version, version); break; case 'o': /* out */ strlcpy(pollist_file, optarg, sizeof(pollist_file)); LOG("cmdline opt: out: %s\n", pollist_file); 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 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; } return create(); } else if ( cmd == 'S' ) { /* --sign */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } 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; } } 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(); } 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.8.2/lcptools/crtpol.c0000644000175000017500000004120112365404264014367 0ustar rqwrqw/* * 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. */ /* * crtpol.c * * Command: lcp_crtpol * * This command can create the LCP policy. * */ #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 MAX_LISTNUM 2 #define BUFFER_SIZE 1024 static uint8_t pol_type = 0xff; static uint32_t alg = LCP_POLHALG_SHA1; static uint8_t ver = 0; static uint32_t pcf_val = 0; static uint8_t sinit_revoc = 0; static char *pol_file = NULL; static char *mle_file = NULL; static char *pol_data_file = NULL; static char *srtm_file = NULL; static int help_input = 0; static const char * short_option = "ht:a:v:s:m:o:b:"; static struct option longopts[]= { {"sr", 1, 0, 'n'}, {"pcf", 1, 0, 'p'}, {0, 0, 0, 0}, }; static const char *usage_string = "lcp_crtpol -t policy_type [-a hashalg] " "[-v version] [-sr SINIT revocation_counter] [-s srtm_file] " "[-m mle_file] [-o policyfile] [-b policydata_file] [-h]\n"; static const char *option_strings[] = { "-t Policy type: uint8/string.\n" "\tPolicy type is:\n" "\tLCP_POLTYPE_HASHONLY: 0 or \"hashonly\" \n" "\tLCP_POLTYPE_UNSIGNED: 1 or \"unsigned\" \n" "\tLCP_POLTYPE_SIGNED: 2 or \"signed\" \n" "\tLCP_POLTYPE_ANY: 3 or \"any\" \n" "\tLCP_POLTYPE_FORCEOWNERPOLICY: 4 or \"forceowner\" \n", "-a algorithm: uint8/string. algorithm used in the policy.\n" "\tAlgorithm choice:\n" "\t\tLCP_POLHALG_SHA1: 0 or \"sha1\" \n" "\tCurrently we only support SHA-1 algorithm.\n", "-v version: uint8. version number.\n" "\tCurrently 0 or 1 is allowed.\n", "-s PConf file name: String. File name of PConf data.\n", "-m MLE hash file name: String. File containing the MLE hashes.\n", "-o LCPPOLICY file name: String. File to save the output Policy.\n", "-b LCPPOLICYDATA file name: String. File to save Policy data.\n", "-sr SINIT Revocation count number: uint8.\n", "-pcf Policy Control Field: uint32.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t poltype_option_table[] = { {"hashonly", LCP_POLTYPE_HASHONLY}, {"unsigned", LCP_POLTYPE_UNSIGNED}, {"signed", LCP_POLTYPE_SIGNED}, {"any", LCP_POLTYPE_ANY}, {"forceowner", LCP_POLTYPE_FORCEOWNERPOLICY}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; unsigned int temp = 0; while ((c = getopt_long_only(argc, (char ** const)argv, short_option, longopts, NULL)) != -1) switch (c) { case 't': /* check whether user inputs the string for policy type*/ temp = parse_input_option(poltype_option_table, optarg); /* * if not, then the users should input the 0~4 number, */ if ( temp == (unsigned int)-1 ) if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if ( temp > 4 ) { log_error("policy type out of range.\n"); return LCP_E_INVALID_PARAMETER; } pol_type = temp; break; case 'a': if ( strcasecmp(optarg, "sha1") == 0 ) alg = LCP_POLHALG_SHA1; else if ( strtonum(optarg, &alg) ) return LCP_E_INVALID_PARAMETER; if ( alg != LCP_POLHALG_SHA1 ) { log_error("Policy algorithm not supported!\n"); return LCP_E_INVALID_PARAMETER; } break; case 'v': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; /* * Currently we only support version 0 or 1. */ if ( temp > 1 ) { log_error("version %d is not supported!\n", ver); return LCP_E_INVALID_PARAMETER; } ver = temp; break; case 's': srtm_file = optarg; break; case 'm': mle_file = optarg; break; case 'o': pol_file = optarg; break; case 'b': pol_data_file = optarg; break; case 'n': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if ( temp > 0xff ) return LCP_E_INVALID_PARAMETER; sinit_revoc = temp; break; case 'p': if ( strtonum(optarg, &pcf_val) ) 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; } /* read data from file */ static int read_data(const char *filename, unsigned int *size, unsigned char *data) { FILE *pfile = NULL; unsigned int len; if ( filename == NULL || data == NULL ) return -1; pfile = fopen(filename, "rb"); if ( pfile == NULL ) { //log_error("Can't open MLE/PConf file\n"); return -1; } fseek(pfile, 0, SEEK_END); len = ftell(pfile); fseek(pfile, 0, SEEK_SET); if ( len > BUFFER_SIZE ) { log_error("the file %s is too long. File size is %d.\n", filename, len); fclose(pfile); return -1; } if ( len != fread(data, 1, len, pfile) ) { fclose(pfile); log_error("Read data from file error!\n"); return -1; } *size = len; fclose(pfile); return 0; } /* save data to file */ static int save_data(unsigned char *data, unsigned int len, const char *file) { FILE *pfile = NULL; if ( data == NULL || file == NULL ) return -1; pfile = fopen(file, "wb"); if ( pfile == NULL ) { log_error("Open file %s error!\n", file); return -1; } if ( len != fwrite(data, 1, len, pfile) ) { fclose(pfile); log_error("Write data into file error!\n"); return -1; } fclose(pfile); return 0; } static int convert_hashes(unsigned int mle_len_ascii, unsigned char *mle_data_ascii, unsigned int *mle_len, unsigned char *mle_data) { unsigned long data; unsigned char *curr, *next; char tmp[3]; curr = mle_data_ascii; *mle_len = 0; while ( curr < (mle_data_ascii + mle_len_ascii) ) { errno = 0; data = 0; data = strtoul((char *)curr, (char **)&next, 16); /* overflow, which means there were no spaces in input */ if ( errno == ERANGE || (data & ~0xff) != 0 ) { /* copy 2 chars into separate buffer and convert them */ tmp[0] = *curr; tmp[1] = *(curr+1); tmp[2] = '\0'; data = strtoul(tmp, NULL, 16); next = curr + 2; } else if ( errno != 0 ) /* some other error */ break; if ( next == curr ) /* done */ break; mle_data[(*mle_len)++] = (unsigned char)data; curr = next; } if ( curr < (mle_data_ascii + mle_len_ascii - 1) ) return -1; else return 0; } /* create policy and policy data */ static lcp_result_t create_policy(lcp_policy_t *lcppolicy, unsigned char *mledata, unsigned int mlelen, unsigned char *pconfdata, unsigned int pconflen, unsigned char *policy, unsigned int *policylen, unsigned char *poldata, unsigned int *poldatalen) { pdlist_src_t listdata[MAX_LISTNUM]; unsigned int listnum = 0; uint32_t poldataver = 0; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; switch (pol_type) { case LCP_POLTYPE_HASHONLY: if ( (mledata == NULL) || (mlelen == 0) ) { log_error("Please use MLE file to input the HASH value!\n"); return LCP_E_INVALID_PARAMETER; } if ( (ret_value = lcp_create_policy(lcppolicy, mlelen, mledata, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_UNSIGNED: if ( ((mledata == NULL) || (mlelen == 0)) && ((pconfdata == NULL) || (pconflen == 0)) ) { log_error("Haven't input MLE file or PConf file.\n"); return LCP_E_INVALID_PARAMETER; } if ( mlelen != 0 ) { //print_hexmsg("the mle data is:\n", mlelen, mledata); listdata[listnum].algorithm = alg; listdata[listnum].type = LCP_POLDESC_MLE_UNSIGNED; listdata[listnum].list_version = 0;/*default value*/ listdata[listnum].listdata_length = mlelen; listdata[listnum].listdata= mledata; listnum++; } if ( pconflen != 0 ) { //print_hexmsg("the pconf data is:\n", pconflen, pconfdata); listdata[listnum].algorithm = alg; listdata[listnum].type= LCP_POLDESC_PCONF_UNSIGNED; listdata[listnum].list_version = 0;/*default value*/ listdata[listnum].listdata_length= pconflen; listdata[listnum].listdata = pconfdata; listnum++; } if ( (ret_value = lcp_create_unsigned_poldata(poldataver, listnum, listdata, poldatalen, poldata)) != LCP_SUCCESS ) { log_error("create policy data error\n"); return ret_value; } if ( (ret_value = lcp_create_policy(lcppolicy, *poldatalen, poldata, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_ANY: if ( (ret_value = lcp_create_policy(lcppolicy, 0, NULL, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_FORCEOWNERPOLICY: if ( (ret_value = lcp_create_policy(lcppolicy, 0, NULL, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_SIGNED: default: log_error("Unsupported Policy type!\n"); return LCP_E_INVALID_PARAMETER; } return LCP_SUCCESS; } static unsigned char policy_data[BUFFER_SIZE]; static unsigned char policy[BUFFER_SIZE]; static unsigned char mle_data_ascii[BUFFER_SIZE]; static unsigned char mle_data[BUFFER_SIZE]; static unsigned char srtm_data[BUFFER_SIZE]; int main (int argc, char *argv[]) { unsigned int pol_len = BUFFER_SIZE; unsigned int pol_data_len = BUFFER_SIZE; unsigned int srtm_len = 0; unsigned int mle_len = 0, mle_len_ascii = 0; lcp_policy_t lcppolicy; 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 ( pol_type == 0xff ) { log_error("No Policy type value has been input. "\ "Must input Policy type value to create Policy Object! \n"); ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } lcppolicy.version = ver; lcppolicy.hash_alg = alg; lcppolicy.policy_type = pol_type; lcppolicy.sinit_revocation_counter = sinit_revoc; lcppolicy.reserved[0] = 0; lcppolicy.reserved[1] = 0; lcppolicy.reserved[2] = 0; lcppolicy.policy_control = pcf_val; if ( mle_file ) { /* read ASCII hash data */ if ( read_data(mle_file, &mle_len_ascii, mle_data_ascii) < 0 ) { log_error("Can't open mle file.\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } /* ensure that convert_hashes() won't overrun the buffer */ mle_data_ascii[BUFFER_SIZE - 1] = '\0'; /* convert ASCII hashes to binary */ if ( convert_hashes(mle_len_ascii, mle_data_ascii, &mle_len, mle_data) < 0 ) { log_error("Can't convert ASCII MLE hashes to binary.\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } if ( srtm_file ) { if ( read_data(srtm_file, &srtm_len, srtm_data) < 0 ) { log_error("Can't open PConf file.\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } /* * Create policy data and policy. */ if ( (ret_value = create_policy(&lcppolicy, mle_data, mle_len, srtm_data, srtm_len, policy, &pol_len, policy_data, &pol_data_len)) != LCP_SUCCESS ) { log_error("Create policy data and policy error!\n"); goto _error_end; } /* * Write policy into file. */ if ( pol_file != NULL ) { if ( save_data(policy, pol_len, pol_file) < 0 ) { log_error("Write policy into file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } else print_hexmsg("the policy is:\n", pol_len, policy); if ( pol_type == LCP_POLTYPE_UNSIGNED ) { /* * Write policy data into file. */ if ( pol_data_file != NULL ) { if ( save_data(policy_data, pol_data_len, pol_data_file) < 0 ) { log_error("Write policy data into file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } else print_hexmsg("the policy data is:\n", pol_data_len, policy_data); printf("Successfully create the policy and the policy data\n"); } else printf("Successfully create the policy\n"); return LCP_SUCCESS; _error_end: /* * Error when execution. */ log_error("\nCommand CrtPol failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.2/lcptools/pollist.c0000644000175000017500000003551612365404265014567 0ustar rqwrqw/* * pollist.c: * * Copyright (c) 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. * */ #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/lcp_hlp.h" #include "polelt_plugin.h" #include "pollist.h" #include "polelt.h" #include "lcputils2.h" bool verify_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_DEFAULT_POLICY_LIST_VERSION || MAJOR_VER(pollist->version) != MAJOR_VER(LCP_DEFAULT_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_signature_size(sig) > size + sig->pubkey_size ) { ERROR("Error: size incorrect (sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size + get_signature_size(sig), size + sig->pubkey_size); return false; } else if ( size_is_exact && base_size + pollist->policy_elements_size + get_signature_size(sig) != size ) { /* check size w/o sig_block */ if ( base_size + pollist->policy_elements_size + get_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_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_pollist_sig(pollist) ) { ERROR("Error: signature does not verify\n"); return false; } } } else { if ( no_sigblock != NULL ) *no_sigblock = false; } return true; } void display_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: %s\n", prefix, 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[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", 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_signature(pollist); if ( sig != NULL ) { DISPLAY("%s signature:\n", prefix); display_signature(new_prefix, sig, brief); if ( verify_pollist_sig(pollist) ) DISPLAY("%s signature verifies\n", prefix); else DISPLAY("%s signature fails to verify\n", prefix); } } lcp_policy_list_t *create_empty_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_DEFAULT_POLICY_LIST_VERSION; pollist->reserved = 0; pollist->sig_alg = LCP_POLSALG_NONE; pollist->policy_elements_size = 0; return pollist; } lcp_policy_list_t *add_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_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((void *)&new_pollist->policy_elements + elt->size, &new_pollist->policy_elements, old_size - offsetof(lcp_policy_list_t, policy_elements)); memcpy(&new_pollist->policy_elements, elt, elt->size); new_pollist->policy_elements_size += elt->size; return new_pollist; } bool del_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_policy_list_size(pollist); size_t elt_size = elt->size; memmove(elt, (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_pollist_sig(const lcp_policy_list_t *pollist) { lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return true; return verify_signature((const unsigned char *)pollist, get_policy_list_size(pollist) - sig->pubkey_size, sig->pubkey_value, sig->pubkey_size, get_sig_block(pollist), true); } void display_signature(const char *prefix, const lcp_signature_t *sig, bool brief) { char new_prefix[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s\t", prefix); 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_signature(lcp_policy_list_t *pollist, const lcp_signature_t *sig) { if ( pollist == NULL || sig == NULL ) return NULL; /* adding a signature requires growing the policy list */ size_t old_size = get_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_signature(new_pollist); if ( curr_sig != NULL ) sig_begin = (void *)curr_sig - (void *)new_pollist; memcpy((void *)new_pollist + sig_begin, sig, sig_size); return new_pollist; } unsigned char *get_sig_block(const lcp_policy_list_t *pollist) { lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return NULL; return (unsigned char *)&sig->pubkey_value + sig->pubkey_size; } void calc_policy_list_hash(const lcp_policy_list_t *pollist, lcp_hash_t *hash, uint8_t hash_alg) { uint8_t *buf_start = (uint8_t *)pollist; size_t len = get_policy_list_size(pollist); if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) { lcp_signature_t *sig = get_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); } lcp_policy_list_t *read_policy_list_file(const char *file, bool fail_ok, bool *no_sigblock_ok) { if ( file == NULL || *file == '\0' || no_sigblock_ok == NULL ) return NULL; /* read existing file, if it exists */ size_t len; lcp_policy_list_t *pollist = read_file(file, &len, fail_ok); if ( pollist == NULL ) return NULL; bool no_sigblock; if ( !verify_policy_list(pollist, 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_signature(pollist); 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((void *)pollist + len, 0, keysize); } *no_sigblock_ok = no_sigblock; return pollist; } bool write_policy_list_file(const char *file, const lcp_policy_list_t *pollist) { size_t len = get_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_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); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/lcputils.h0000644000175000017500000001210612365404265014733 0ustar rqwrqw/* * 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.8.2/lcptools/lcptools.h0000644000175000017500000001711212365404265014735 0ustar rqwrqw/* * 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.8.2/lcptools/pol.h0000644000175000017500000000410512365404265013666 0ustar rqwrqw/* * pol.h: * * Copyright (c) 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 __POL_H__ #define __POL_H__ extern size_t get_policy_size(const lcp_policy_t *pol); extern bool verify_policy(const lcp_policy_t *pol, size_t size, bool silent); extern void display_policy(const char *prefix, const lcp_policy_t *pol, bool brief); 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.8.2/lcptools/lcputils2.c0000644000175000017500000002217512365404265015017 0ustar rqwrqw/* * lcputils2.c: misc. LCP helper fns * * Copyright (c) 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. * */ #include #include #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/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" 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) { strncpy(dst, src, siz-1); if ( siz != 0 ) *(dst + siz-1) = '\0'; return strlen(src); } 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); } if ( nr == *nr_ints ) ERROR("Error: too many items in list\n"); *nr_ints = nr; return; } void *read_file(const char *file, size_t *length, bool fail_ok) { 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); 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; return data; } bool write_file(const char *file, const void *data, size_t size) { 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); return true; } bool parse_line_hashes(const char *line, tb_hash_t *hash) { /* 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; hash->sha1[i++] = (uint8_t)strtoul(line, &next, 16); 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(TB_HALG_SHA1_LG) ) { 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[128]; while ( true ) { char *s = fgets(line, sizeof(line), fp); if ( s == NULL ) { fclose(fp); return true; } LOG("read line: %s", line); if ( !(*parse_line)(line) ) { fclose(fp); return false; } } fclose(fp); return false; } const char *hash_alg_to_str(uint8_t alg) { static const char *alg_str[] = { "LCP_POLHALG_SHA1" }; static char buf[32]; if ( alg > ARRAY_SIZE(alg_str) ) { snprintf(buf, sizeof(buf), "unknown (%u)", alg); return buf; } else return alg_str[alg]; } size_t get_lcp_hash_size(uint8_t hash_alg) { if ( hash_alg != LCP_POLHALG_SHA1 ) return 0; return SHA1_LENGTH; } bool verify_signature(const uint8_t *data, size_t data_size, const uint8_t *pubkey, size_t pubkey_size, const uint8_t *sig, bool is_sig_little_endian) { unsigned int i; /* policy key is little-endian and openssl wants big-endian, so reverse */ uint8_t key[pubkey_size]; for ( i = 0; i < pubkey_size; i++ ) key[i] = *(pubkey + (pubkey_size - i - 1)); /* create RSA public key struct */ RSA *rsa_pubkey = RSA_new(); if ( rsa_pubkey == NULL ) { ERROR("Error: failed to allocate key\n"); return false; } rsa_pubkey->n = BN_bin2bn(key, pubkey_size, NULL); /* uses fixed exponent (LCP_SIG_EXPONENT) */ char exp[32]; snprintf(exp, sizeof(exp), "%u", LCP_SIG_EXPONENT); rsa_pubkey->e = NULL; BN_dec2bn(&rsa_pubkey->e, exp); rsa_pubkey->d = rsa_pubkey->p = rsa_pubkey->q = NULL; /* first create digest of data */ tb_hash_t digest; if ( !hash_buffer(data, data_size, &digest, TB_HALG_SHA1_LG) ) { ERROR("Error: failed to hash list\n"); RSA_free(rsa_pubkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(TB_HALG_SHA1_LG)); } /* sigblock is little-endian and openssl wants big-endian, so reverse */ uint8_t sigblock[pubkey_size]; if ( is_sig_little_endian ) { for ( i = 0; i < pubkey_size; i++ ) sigblock[i] = *(sig + (pubkey_size - i - 1)); sig = sigblock; } if ( verbose ) { /* raw decryption of sigblock */ uint8_t unsig[pubkey_size]; if ( RSA_public_decrypt(pubkey_size, sig, unsig, rsa_pubkey, RSA_NO_PADDING) == -1 ) { ERR_load_crypto_strings(); ERROR("Error: failed to decrypt sig: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); } else { LOG("decrypted sig:\n"); print_hex("", unsig, pubkey_size); } } /* verify digest */ if ( !RSA_verify(NID_sha1, (const unsigned char *)&digest, get_hash_size(TB_HALG_SHA1_LG), (uint8_t *)sig, pubkey_size, rsa_pubkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to verify list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(rsa_pubkey); return false; } RSA_free(rsa_pubkey); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.2/lcptools/polelt_plugin.h0000644000175000017500000000554312365404265015760 0ustar rqwrqw/* * polelt_plugin.h: policy element plugin support * * Copyright (c) 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 __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.8.2/lcptools/defindex.c0000644000175000017500000002751012365404265014662 0ustar rqwrqw/* * 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 #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 = strlen(password); 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 = strlen(auth_value); 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.8.2/COPYING0000644000175000017500000000027412365404264012121 0ustar rqwrqwFiles which do not contain any copyright information are assumed to be copyrighted by Intel Corporation. All other files contain their copyright and license at the beginning of the file. tboot-1.8.2/Makefile0000644000175000017500000000443412365404264012530 0ustar rqwrqw# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # Grand Unified Makefile for tboot # # define ROOTDIR export ROOTDIR=$(CURDIR) # import global build config include Config.mk # (txt-test is not included because it requires pathing to Linux src) SUBDIRS := tboot lcptools lcptools-v2 tb_polgen utils docs # # build rules # # # manifest # .PHONY: manifest manifest : build lcptools/lcp_mlehash tboot/tboot.gz > mle_file lcptools/lcp_crtpol -t 0 -m mle_file -o policy_file # # install # install : @set -e; for i in $(SUBDIRS); do \ $(MAKE) install-$$i; \ done install-% : $(MAKE) -C $* install # # build # build : @set -e; for i in $(SUBDIRS); do \ $(MAKE) build-$$i; \ done build-% : $(MAKE) -C $* build # # dist # dist : $(patsubst %,dist-%,$(SUBDIRS)) [ -d $(DISTDIR) ] || $(INSTALL_DIR) $(DISTDIR) $(INSTALL_DATA) COPYING $(DISTDIR) $(INSTALL_DATA) README $(DISTDIR) dist-% : $(MAKE) -C $* dist # # world # # build tboot and tools, and place them in the install directory. # 'make install' should then copy them to the normal system directories .PHONY: world world : $(MAKE) clean $(MAKE) dist # # clean # clean : rm -f *~ include/*~ docs/*~ @set -e; for i in $(SUBDIRS); do \ $(MAKE) clean-$$i; \ done clean-% : $(MAKE) -C $* clean # # distclean # distclean : @set -e; for i in $(SUBDIRS); do \ $(MAKE) distclean-$$i; \ done distclean-% : $(MAKE) -C $* distclean # # mrproper # # Linux name for GNU distclean mrproper : distclean # # help # .PHONY: help help : @echo 'Installation targets:' @echo ' install - build and install everything' @echo ' install-* - build and install the * module' @echo '' @echo 'Building targets:' @echo ' dist - build and install everything into local dist directory' @echo ' world - clean everything' @echo '' @echo 'Cleaning targets:' @echo ' clean - clean sboot and tools' @echo ' distclean - clean and local downloaded files' @echo '' @echo ' uninstall - attempt to remove installed tools' @echo ' (use with extreme care!)' # # uninstall # # Use this target with extreme care! .PHONY: uninstall uninstall : D=$(DESTDIR) uninstall : rm -rf $(D)/boot/tboot* tboot-1.8.2/README0000644000175000017500000004441312365404264011751 0ustar rqwrqw****************************************************************************** * This version of tboot will not work with Xen versions < 3.4 (c/s < 19115) * ****************************************************************************** Trusted Boot (tboot) is an open source, pre-kernel/VMM module that uses Intel(R) Trusted Execution Technology (Intel(R) TXT) to perform a measured and verified launch of an OS kernel/VMM. This version of tboot supports Intel (both retail and Software Development Platforms (SDPs)) and OEM systems that are Intel TXT-capable. This version of tboot only supports both the Xen virtual machine monitor (versions >= 3.4) and Linux kernel versions >= 2.6.33. The mercurial source code repository for this project is located at: http://hg.code.sf.net/p/tboot/code. Updates to the mercurial repository are automatically sent to the mailing list tboot-changelog@lists.sourceforge.net. Overview of Tboot Functionality: -------------------------------- o Measured Launch. If the processor is detected as being TXT-capable and enabled then the code will attempt to perform a measured launch. If the measured launch process fails (processor is not capable, TXT is not enabled, missing SINIT, corrupted data, etc.)) then it will fall-through to a non-TXT boot. o Teardown of measured environment. When the system is shutdown, the measured environment will be torn down properly. This support S3/S4/S5 sleep states. o Reset data protection. Intel TXT hardware prevents access to secrets if the system is reset without clearing them from memory (as part of a TXT teardown). This code will support this by setting the flag indicating that memory should be so protected during the measured launch and clearing the flag just before teardown. o Protection of TXT memory ranges. Intel TXT reserves certain regions of RAM for its use and also defines several MMIO regions. These regions (excluding the TXT public configuration space) are protected from use by any domains (including dom0). o Intel TXT Launch Control Policy (LCP) tools. The lcptools project contains a set of tools (and basic documentation) that can be used to create and provision TXT Launch Control policies. LCP uses TPM non-volatile storage (TPM NV) to hold a launch policy, which the SINIT AC module reads and uses to enforce which measured launched environments (MLEs) (e.g. tboot) can be launched (based on a SHA-1 hash). These tools require a TPM Software Stack (TSS) that supports the Tspi_NV_* API. Versions of the TrouSerS project >0.3.0 support them. o Verified Launch. Tboot will extend verifcation from the MLE to the VMM and dom0, using policies similar to the LCP and also stored in TPM NV. These policies can be created and managed by the tb_polgen tool and provisioned into TPM NV using the lcptools. Instructions for Building: ------------------------- o The trousers sub-project has been removed (it was using an out-of-date version and was often problematic to build). Instead, the trosuers and trousers-devel packages must already be installed in order to build the lcptools sub-project. Most distrubtions either provide these packages by default or optionally; otherwise they can be found on various package sites and manually installed. Instructions for Use: -------------------- o The new tboot module must be added as the 'kernel' 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 GRUB2 does not pass the file name in the command line field of the multiboot entry (module_t::string). Since the tboot code is expecting the file name as the first part of the string, it tries to remove it to determine the command line arguments, which will cause a verification error. The "official" workaround for kernels/etc. that depend on the file name is to duplicate the file name in the grub.config file like below: menuentry 'Xen w/ Intel(R) Trusted Execution Technology' { recordfail insmod part_msdos insmod ext2 set root='(/dev/sda,msdos5)' search --no-floppy --fs-uuid --set=root 4efb64c6-7e11-482e-8bab-07034a52de39 multiboot /tboot.gz /tboot.gz logging=vga,memory,serial module /xen.gz /xen.gz iommu=required dom0_mem=524288 com1=115200,8n1 module /vmlinuz-2.6.18-xen /vmlinuz-2.6.18-xen root=/dev/VolGroup... module /initrd-2.6.18-xen.img /initrd-2.6.18-xen.img module /Q35_SINIT_17.BIN } o The appropriate SINIT AC Module can be downloaded from the tboot SourceForge project site. 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. o 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. o 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. o 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 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. o 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. o 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 o 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. o 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). o Tboot provides support to launch Revocation ACM (RACM) to revoke old buggy SINIT version if following command line option is used (default vaule 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. o 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. 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. o Tboot support TPM NV measuring via extended Verified Launch Tboot Policy. This works only for TPM1.2 by far. TPM NV measuring is defaultly 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. o 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. PCR Usage: --------- o 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. o 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. Interesting Items of Note: -------------------------- o A Xen or Linux version that does not support tboot can still be launched by tboot, however it will not protect any of the TXT memory nor tboot itself. And it will hang on reboot/shutdown. Aside from this, it will behave normally. o Tboot will copy and alter the e820 table provided by GRUB to "reserve" its own memory plus the TXT memory regions. These are marked as E820_UNUSABLE or E820_RESERVED so that the patched Xen code can prevent them from being assigned to dom0. The e820 table is not altered if the measured launch fails for any reason. o Tboot is always built 32bit and runs in protected mode without PAE or paging enabled. Tboot loads and executes at 0x800000 (8MB). o The code requires that VT be enabled as well as TXT. This is because the mechanism for bringing up the APs uses VMX to create a mini-VM in order to trap on INIT-SIPI-SIPI. If OS/VMM support tboot's new AP wakeup mechanism based on MWAIT, then VT is not required to be enabled. o The tools/txt-stat project is a Linux application that reads some of the TXT registers and will display the tboot boot log if tboot was run with 'logging=memory'. Contributing to the project: --------------------------- Contributions to any files in this project require the contributor(s) to certify the following: Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. If the above can be certified by the contributor(s), then he/they should include a signed-off-by line along with the changes that indicate this: Signed-off-by: John Developer tboot-1.8.2/utils/0000755000175000017500000000000012365404267012226 5ustar rqwrqwtboot-1.8.2/utils/parse_err.c0000644000175000017500000001133512365404267014357 0ustar rqwrqw/* * 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.8.2/utils/txt-stat.c0000644000175000017500000003303112365404267014162 0ustar rqwrqw/* * 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 #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" 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", 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) { verify_bios_data(heap); } static void display_tboot_log(void *log_base) { static char buf[512]; tboot_log_t *log = (tboot_log_t *)log_base; 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=%x\n", log->max_size); printf("\t curr_pos=%x\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 */ char *log_buf = log->buf; /* log is too big for single printk(), so break it up */ for ( unsigned int curr_pos = 0; curr_pos < log->curr_pos; curr_pos += sizeof(buf)-1 ) { strncpy(buf, log_buf + curr_pos, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; 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: */ tboot-1.8.2/utils/Makefile0000644000175000017500000000205112365404267013664 0ustar rqwrqw# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # utils makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TARGETS := txt-stat acminfo parse_err CFLAGS += -D_LARGEFILE64_SOURCE # # 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 $@ acminfo : acminfo.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ parse_err : parse_err.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ %.o : %.c $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.8.2/utils/acminfo.c0000644000175000017500000001546212365404267014016 0ustar rqwrqw/* * 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 #define printk printf #include "../include/config.h" #include "../include/uuid.h" #include "../include/mle.h" #include "../tboot/include/compiler.h" #include "../tboot/include/processor.h" #include "../tboot/include/misc.h" #include "../tboot/include/txt/acmod.h" #include "../tboot/include/txt/config_regs.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"); return 0; } /* lseek() to MSR # */ if ( lseek(fd, msr, SEEK_SET) == (off_t)-1 ) printf("Error: failed to find MSR 0x%x\n", msr); else { if ( read(fd, &val, sizeof(val)) != sizeof(val) ) printf("Error: failed to read MSR 0x%x value\n", msr); } close(fd); return val; } #define MSR_IA32_PLATFORM_ID 0x17 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 MAX_OS_SINIT_DATA_VER 6 #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; 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.8.2/Config.mk0000644000175000017500000000370312365404264012624 0ustar rqwrqw# 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 \ -D_FORTIFY_SOURCE=2 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 endif ifeq ($(TARGET_ARCH),x86_64) LIBDIR := lib64 CFLAGS += -m64 else LIBDIR := lib CFLAGS += -m32 -march=i686 endif # common dummy rule to force execution .PHONY: FORCE FORCE : @: # do nothing tboot-1.8.2/txt-test/0000755000175000017500000000000012365404267012662 5ustar rqwrqwtboot-1.8.2/txt-test/Makefile0000644000175000017500000000144612365404267014327 0ustar rqwrqw# 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.8.2/txt-test/Kbuild0000644000175000017500000000002312365404267014012 0ustar rqwrqwobj-m = txt-test.o tboot-1.8.2/txt-test/txt-test.c0000644000175000017500000002061512365404267014626 0ustar rqwrqw/* * 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.8.2/CHANGELOG0000644000175000017500000004237012365404264012303 0ustar rqwrqw20140728: 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 ouput conditional Changes TBOOT_S3_WAKEUP_ADDR to 0x8a000 to ensure no conflicts 20071026: Initial version. tboot-1.8.2/test-patches/0000755000175000017500000000000012365404267013472 5ustar rqwrqwtboot-1.8.2/test-patches/vsprintf-test.patch0000644000175000017500000000411412365404267017343 0ustar rqwrqw--- 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.8.2/test-patches/tpm-test.patch0000644000175000017500000032142012365404267016272 0ustar rqwrqwdiff -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.8.2/test-patches/e820-test.patch0000644000175000017500000001653512365404267016160 0ustar rqwrqwdiff -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.8.2/test-patches/mtrrs-test.patch0000644000175000017500000004305112365404267016642 0ustar rqwrqw--- 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);