Home | History | Annotate | Download | only in utils
      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 
      7 FW_NV_ADDRESS = 0x1007
      8 KERNEL_NV_ADDRESS = 0x1008
      9 
     10 class TpmError(Exception):
     11     pass
     12 
     13 class 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 
     60 class 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