Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Unified Diff: tpm_handler.py

Issue 3781016: Introduce SAFT TPM testing support. (Closed) Base URL: http://git.chromium.org/git/saft.git
Patch Set: Addressed review comments. Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test_tpm_handler.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tpm_handler.py
diff --git a/tpm_handler.py b/tpm_handler.py
new file mode 100755
index 0000000000000000000000000000000000000000..526dbf4976e38e1ae7ef785c7c747368cfe0a8ee
--- /dev/null
+++ b/tpm_handler.py
@@ -0,0 +1,161 @@
+#!/usr/bin/python
+# 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.'''
+import os
+import re
+import shutil
+
+FW_NV_ADDRESS = 0x1007
+KERNEL_NV_ADDRESS = 0x1008
+COMMENT_PATTERN = '#saft'
+
+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 (chromeos_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]
+
+ def set_body_version(self, new_version):
+ new_contents = list(self.contents)
+ new_contents[self.version_offset + 1] = (new_version >> 8) & 0xff
+ new_contents[self.version_offset] = new_version & 0xff
+ if new_contents != self.contents:
+ self.contents = new_contents
+ cmd = 'tpmc write 0x%x %s' % (
+ self.addr, ' '.join('0x%2.2x' % x for x in new_contents))
+ self.os_if.run_shell_command(cmd)
+ else:
+ self.os_if.log('no version change for 0x%x' % self.addr)
+
+class TpmHandler(object):
+ '''An object to control TPM device's NVRAM.
+
+ Attributes:
+ cros_if: an instance of the OS interface (chromeos_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.cros_if = None
+ self.nvrams = {
+ 'kernel': TpmNvRam(KERNEL_NV_ADDRESS, 13, 5, (
+ 1, [0x4c, 0x57, 0x52, 0x47])),
+ 'bios': TpmNvRam(FW_NV_ADDRESS, 10, 2)
+ }
+
+ def init(self, cros_if):
+ self.cros_if = cros_if
+ status = self.cros_if.run_shell_command_get_output(
+ 'initctl status tcsd')[0]
+ if status.startswith('tcsd start/running'):
+ self.cros_if.run_shell_command('stop tcsd')
+
+ for nvram in self.nvrams.itervalues():
+ nvram.init(self.cros_if)
+
+ def get_fw_version(self):
+ return self.nvrams['bios'].get_body_version()
+
+ def get_kernel_version(self):
+ return self.nvrams['kernel'].get_body_version()
+
+ def set_kernel_version(self, new_version):
+ return self.nvrams['kernel'].set_body_version(new_version)
+
+ def _version_good(self, nvram, version_a, version_b):
+ return self.nvrams[nvram].get_body_version() == max(
+ version_a, version_b)
+
+ def kernel_version_good(self, version_a, version_b):
+ return self._version_good('kernel', version_a, version_b)
+
+ def fw_version_good(self, version_a, version_b):
+ return self._version_good('bios', version_a, version_b)
+
+ def enable_write_access(self, config_file_name='/etc/init/tcsd.conf'):
+ '''Enable TPM write access on the next recovery mode restart.
+
+ Comment out from the TPM upstart script the following lines locking
+ the TPM (and thus preventing write access):
+
+ tpmc block || logger "tpmc block: status $?"
+ tpmc pplock || logger "tpmc pplock: status $?"
+
+ Save the original file in the state directory for future recovery.
+ '''
+
+ pattern = re.compile('^\s+tpmc\s+(b|pp)lock\s+\|\|')
+ new_file_name = self.cros_if.state_dir_file(
+ os.path.basename(config_file_name))
+ shutil.copyfile(config_file_name, new_file_name + '.bak')
+ config_file = open(config_file_name, 'r')
+ new_file = open(new_file_name, 'w')
+ for line in config_file.readlines():
+ if pattern.search(line):
+ new_file.write('%s%s' % (COMMENT_PATTERN, line))
+ else:
+ new_file.write(line)
+ new_file.close()
+ config_file.close()
+ shutil.move(new_file_name, config_file_name)
+
+ def disable_write_access(self, config_file_name='/etc/init/tcsd.conf'):
+ '''Disable TPM write access.
+
+ Restore previously edited startup file to lock the TPM on the next
+ restart.
+ '''
+ backup_file_name = self.cros_if.state_dir_file(
+ os.path.basename(config_file_name) + '.bak')
+ shutil.move(backup_file_name, config_file_name)
« no previous file with comments | « test_tpm_handler.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698