1# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""A module containing TPM handler class used by SAFT.""" 6 7FW_NV_ADDRESS = 0x1007 8KERNEL_NV_ADDRESS = 0x1008 9 10class TpmError(Exception): 11 pass 12 13class TpmNvRam(object): 14 """An object representing TPM NvRam. 15 16 Attributes: 17 addr: a number, NvRAm address in TPM. 18 size: a number, count of bites in this NvRam section. 19 os_if: an instance of the OS interface (os_interface or a mock object). 20 version_offset: - a number, offset into the NvRam contents where the the 21 versions are stored. The total version field size is 4 bytes, the 22 first two bytes are the body version, the second two bytes are the key 23 version. Numbers are stored in little endian format. 24 pattern: optional, a tuple of two elements, the first element is the 25 offset of the pattern expected to be present in the NvRam, and the 26 second element is an array of bytes the pattern must match. 27 contents: an array of bytes, the contents of the NvRam. 28 """ 29 30 def __init__(self, addr, size, version_offset, data_pattern=None): 31 self.addr = addr 32 self.size = size 33 self.os_if = None 34 self.version_offset = version_offset 35 self.pattern = data_pattern 36 self.contents = [] 37 38 def init(self, os_if): 39 self.os_if = os_if 40 cmd = 'tpmc read 0x%x 0x%x' % (self.addr, self.size) 41 nvram_data = self.os_if.run_shell_command_get_output(cmd)[0].split() 42 self.contents = [int(x, 16) for x in nvram_data] 43 if self.pattern: 44 pattern_offset = self.pattern[0] 45 pattern_data = self.pattern[1] 46 contents_pattern = self.contents[pattern_offset:pattern_offset + 47 len(pattern_data)] 48 if contents_pattern != pattern_data: 49 raise TpmError('Nvram pattern does not match') 50 51 def get_body_version(self): 52 return self.contents[ 53 self.version_offset + 1] * 256 + self.contents[self.version_offset] 54 55 def get_key_version(self): 56 return self.contents[ 57 self.version_offset + 3] * 256 + self.contents[ 58 self.version_offset + 2] 59 60class TpmHandler(object): 61 """An object to control TPM device's NVRAM. 62 63 Attributes: 64 os_if: an instance of the OS interface (os_interface or a mock object). 65 nvrams: A dictionary where the keys are the nvram names, and the values 66 are instances of TpmNvRam objects, providing access to the 67 appropriate TPM NvRam sections. 68 """ 69 70 def __init__(self): 71 self.os_if = None 72 self.nvrams = { 73 'kernel': TpmNvRam(KERNEL_NV_ADDRESS, 13, 5, ( 74 1, [0x4c, 0x57, 0x52, 0x47])), 75 'bios': TpmNvRam(FW_NV_ADDRESS, 10, 2) 76 } 77 self.trunksd_started = False 78 self.tcsd_started = False 79 80 def init(self, os_if): 81 self.os_if = os_if 82 self.stop_daemon() 83 for nvram in self.nvrams.itervalues(): 84 nvram.init(self.os_if) 85 self.restart_daemon() 86 87 def get_fw_version(self): 88 return self.nvrams['bios'].get_body_version() 89 90 def get_fw_key_version(self): 91 return self.nvrams['bios'].get_key_version() 92 93 def get_kernel_version(self): 94 return self.nvrams['kernel'].get_body_version() 95 96 def get_kernel_key_version(self): 97 return self.nvrams['kernel'].get_key_version() 98 99 def stop_daemon(self): 100 """Stop TPM related daemon.""" 101 if self.trunksd_started or self.tcsd_started: 102 raise TpmError('Called stop_daemon() before') 103 104 cmd = 'initctl status tcsd || initctl status trunksd' 105 status = self.os_if.run_shell_command_get_output(cmd) or [''] 106 # Expected status is like ['trunksd start/running, process 2375'] 107 self.trunksd_started = status[0].startswith('trunksd start/running') 108 if self.trunksd_started: 109 self.os_if.run_shell_command('stop trunksd') 110 else: 111 self.tcsd_started = status[0].startswith('tcsd start/running') 112 if self.tcsd_started: 113 self.os_if.run_shell_command('stop tcsd') 114 115 def restart_daemon(self): 116 """Restart TPM related daemon which was stopped by stop_daemon().""" 117 if self.trunksd_started: 118 self.os_if.run_shell_command('start trunksd') 119 self.trunksd_started = False 120 elif self.tcsd_started: 121 self.os_if.run_shell_command('start tcsd') 122 self.tcsd_started = False 123