/* * 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: */