# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """A module containing TPM handler class used by SAFT.""" FW_NV_ADDRESS = 0x1007 KERNEL_NV_ADDRESS = 0x1008 class TpmError(Exception): pass class TpmNvRam(object): """An object representing TPM NvRam. Attributes: addr: a number, NvRAm address in TPM. size: a number, count of bites in this NvRam section. os_if: an instance of the OS interface (os_interface or a mock object). version_offset: - a number, offset into the NvRam contents where the the versions are stored. The total version field size is 4 bytes, the first two bytes are the body version, the second two bytes are the key version. Numbers are stored in little endian format. pattern: optional, a tuple of two elements, the first element is the offset of the pattern expected to be present in the NvRam, and the second element is an array of bytes the pattern must match. contents: an array of bytes, the contents of the NvRam. """ def __init__(self, addr, size, version_offset, data_pattern=None): self.addr = addr self.size = size self.os_if = None self.version_offset = version_offset self.pattern = data_pattern self.contents = [] def init(self, os_if): self.os_if = os_if cmd = 'tpmc read 0x%x 0x%x' % (self.addr, self.size) nvram_data = self.os_if.run_shell_command_get_output(cmd)[0].split() self.contents = [int(x, 16) for x in nvram_data] if self.pattern: pattern_offset = self.pattern[0] pattern_data = self.pattern[1] contents_pattern = self.contents[pattern_offset:pattern_offset + len(pattern_data)] if contents_pattern != pattern_data: raise TpmError('Nvram pattern does not match') def get_body_version(self): return self.contents[ self.version_offset + 1] * 256 + self.contents[self.version_offset] def get_key_version(self): return self.contents[ self.version_offset + 3] * 256 + self.contents[ self.version_offset + 2] class TpmHandler(object): """An object to control TPM device's NVRAM. Attributes: os_if: an instance of the OS interface (os_interface or a mock object). nvrams: A dictionary where the keys are the nvram names, and the values are instances of TpmNvRam objects, providing access to the appropriate TPM NvRam sections. """ def __init__(self): self.os_if = None self.nvrams = { 'kernel': TpmNvRam(KERNEL_NV_ADDRESS, 13, 5, ( 1, [0x4c, 0x57, 0x52, 0x47])), 'bios': TpmNvRam(FW_NV_ADDRESS, 10, 2) } self.trunksd_started = False self.tcsd_started = False def init(self, os_if): self.os_if = os_if self.stop_daemon() for nvram in self.nvrams.itervalues(): nvram.init(self.os_if) self.restart_daemon() def get_fw_version(self): return self.nvrams['bios'].get_body_version() def get_fw_key_version(self): return self.nvrams['bios'].get_key_version() def get_kernel_version(self): return self.nvrams['kernel'].get_body_version() def get_kernel_key_version(self): return self.nvrams['kernel'].get_key_version() def stop_daemon(self): """Stop TPM related daemon.""" if self.trunksd_started or self.tcsd_started: raise TpmError('Called stop_daemon() before') cmd = 'initctl status tcsd || initctl status trunksd' status = self.os_if.run_shell_command_get_output(cmd) or [''] # Expected status is like ['trunksd start/running, process 2375'] self.trunksd_started = status[0].startswith('trunksd start/running') if self.trunksd_started: self.os_if.run_shell_command('stop trunksd') else: self.tcsd_started = status[0].startswith('tcsd start/running') if self.tcsd_started: self.os_if.run_shell_command('stop tcsd') def restart_daemon(self): """Restart TPM related daemon which was stopped by stop_daemon().""" if self.trunksd_started: self.os_if.run_shell_command('start trunksd') self.trunksd_started = False elif self.tcsd_started: self.os_if.run_shell_command('start tcsd') self.tcsd_started = False