1# Copyright 2014 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 5import hashlib, logging 6 7from autotest_lib.client.common_lib import error 8from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 9 10 11class firmware_TPMExtend(FirmwareTest): 12 """Test to ensure TPM PCRs are extended correctly.""" 13 version = 1 14 NEEDS_SERVO_USB = True 15 16 def initialize(self, host, cmdline_args): 17 super(firmware_TPMExtend, self).initialize(host, cmdline_args) 18 self.switcher.setup_mode('normal') 19 self.setup_usbkey(usbkey=True, host=False) 20 fwver = self.faft_client.system.run_shell_command_get_output( 21 'crossystem fwid')[0] 22 try: 23 fwver_major = int(fwver.split('.')[1]) 24 except ValueError: 25 raise error.TestFail('Could not determine firmware version') 26 self.disable_hwid_check = fwver_major < 6425 27 28 def _tpm1_check_pcr(self, num, hash_obj): 29 pcrs_file = '/sys/class/*/tpm0/device/pcrs' 30 pcrs = '\n'.join(self.faft_client.system.run_shell_command_get_output( 31 'cat %s' % pcrs_file)) 32 logging.debug('Dumping PCRs read from device: \n%s', pcrs) 33 extended = hashlib.sha1(b'\0' * 20 + hash_obj.digest()[:20]).hexdigest() 34 spaced = ' '.join(extended[i:i+2] for i in xrange(0, len(extended), 2)) 35 logging.debug('PCR %d should contain hash: %s', num, spaced) 36 return ('PCR-%.2d: %s' % (num, spaced.upper())) in pcrs 37 38 def _tpm2_check_pcr(self, num, hash_obj): 39 out = self.faft_client.system.run_shell_command_get_output( 40 'trunks_client --read_pcr --index=%d' % num)[0] 41 logging.debug('PCR %d read from device: %s', num, out) 42 padded = (hash_obj.digest() + b'\0' * 12)[:32] 43 extended = hashlib.sha256(b'\0' * 32 + padded).hexdigest().upper() 44 logging.debug('PCR %d should contain hash: %s', num, extended) 45 return extended in out 46 47 def _check_pcr(self, num, hash_obj): 48 """Returns true iff PCR |num| was extended with hashlib |hash_obj|.""" 49 if '1.' in self.faft_client.tpm.get_tpm_version(): 50 return self._tpm1_check_pcr(num, hash_obj) 51 else: 52 return self._tpm2_check_pcr(num, hash_obj) 53 54 def run_once(self): 55 """Runs a single iteration of the test.""" 56 if self.disable_hwid_check: 57 logging.info( 58 'Skip testing HWID digest in PCR1 due to firmware version') 59 else: 60 logging.info('Verifying HWID digest in PCR1') 61 hwid = self.faft_client.system.run_shell_command_get_output( 62 'crossystem hwid')[0] 63 logging.debug('HWID reported by device is: %s', hwid) 64 if not self._check_pcr(1, hashlib.sha256(hwid)): 65 raise error.TestFail( 66 'PCR1 was not extended with SHA256 of HWID!') 67 68 logging.info('Verifying bootmode digest in PCR0 in normal mode') 69 self.check_state((self.checkers.crossystem_checker, { 70 'devsw_boot': '0', 71 'mainfw_type': 'normal' 72 })) 73 # dev_mode: 0, rec_mode: 0, keyblock_flags: "normal" (1) 74 if not self._check_pcr(0, hashlib.sha1(chr(0) + chr(0) + chr(1))): 75 raise error.TestFail('PCR0 was not extended with bootmode 0|0|1!') 76 77 logging.info('Verifying bootmode digest in PCR0 in recovery mode') 78 self.switcher.reboot_to_mode(to_mode='rec') 79 self.check_state((self.checkers.crossystem_checker, { 80 'devsw_boot': '0', 81 'mainfw_type': 'recovery' 82 })) 83 # dev_mode: 0, rec_mode: 1, keyblock_flags: "unknown" (0) 84 if not self._check_pcr(0, hashlib.sha1(chr(0) + chr(1) + chr(0))): 85 raise error.TestFail('PCR0 was not extended with bootmode 0|1|0!') 86 87 logging.info('Transitioning to dev mode for next test') 88 self.switcher.reboot_to_mode(to_mode='dev') 89 90 logging.info('Verifying bootmode digest in PCR0 in developer mode') 91 self.check_state((self.checkers.crossystem_checker, { 92 'devsw_boot': '1', 93 'mainfw_type': 'developer' 94 })) 95 # dev_mode: 1, rec_mode: 0, keyblock_flags: "normal" (1) 96 if not self._check_pcr(0, hashlib.sha1(chr(1) + chr(0) + chr(1))): 97 raise error.TestFail('PCR0 was not extended with bootmode 1|0|1!') 98 99 logging.info('Verifying bootmode digest in PCR0 in dev-recovery mode') 100 self.switcher.reboot_to_mode(to_mode='rec') 101 self.check_state((self.checkers.crossystem_checker, { 102 'devsw_boot': '1', 103 'mainfw_type': 'recovery' 104 })) 105 # dev_mode: 1, rec_mode: 1, keyblock_flags: "unknown" (0) 106 if not self._check_pcr(0, hashlib.sha1(chr(1) + chr(1) + chr(0))): 107 raise error.TestFail('PCR0 was not extended with bootmode 1|1|0!') 108 109 logging.info('All done, returning to normal mode') 110 self.switcher.reboot_to_mode(to_mode='normal') 111