Home | History | Annotate | Download | only in cros
      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 
      5 """
      6 Provides a utility function for working with TPM DAM logic.
      7 
      8 Dictionary Attack Mitigation (DAM) logic causes TPMs to enter a locked down
      9 state to defend against dictionary attacks. Authentication failures cause a
     10 counter to increment and when the counter exceeds some threshold, the defense
     11 mechanism is triggered.
     12 """
     13 
     14 import os, re
     15 
     16 from autotest_lib.client.common_lib import utils
     17 from autotest_lib.client.cros import service_stopper
     18 
     19 def get_dictionary_attack_counter():
     20     """Returns the current dictionary attack counter."""
     21     tpm_command_info = {
     22         '0x49465800': {  # Infineon
     23             'command': ('00 c1 '         # Tag = TPM_TAG_RQU_COMMAND
     24                         '00 00 00 16 '   # Size = 22
     25                         '00 00 00 65 '   # Ordinal = TPM_ORD_GetCapability
     26                         '00 00 00 10 '   # Capability Area = TPM_CAP_MFR
     27                         '00 00 00 04 '   # Size = 4
     28                         '00 00 08 02'),  # Vendor-specific
     29             'response_offset': 23},      # Vendor-specific
     30         '0x57454300': {  # Nuvoton
     31             'command': ('00 c1 '         # Tag = TPM_TAG_RQU_COMMAND
     32                         '00 00 00 14 '   # Size = 20
     33                         '00 00 00 65 '   # Ordinal = TPM_ORD_GetCapability
     34                         '00 00 00 19 '   # Capability Area = TPM_CAP_DA_LOGIC
     35                         '00 00 00 02 '   # Size = 2
     36                         '00 04'),        # Entity Type = TPM_ET_SRK
     37             'response_offset': 18},      # TPM_DA_INFO.currentCount LSB
     38         '0x53544d20': {  # STMicro
     39             'command': ('00 c1 '         # Tag = TPM_TAG_RQU_COMMAND
     40                         '00 00 00 14 '   # Size = 20
     41                         '00 00 00 65 '   # Ordinal = TPM_ORD_GetCapability
     42                         '00 00 00 19 '   # Capability Area = TPM_CAP_DA_LOGIC
     43                         '00 00 00 02 '   # Size = 2
     44                         '00 04'),        # Entity Type = TPM_ET_SRK
     45             'response_offset': 18}}      # TPM_DA_INFO.currentCount LSB
     46     caps_file='/sys/class/misc/tpm0/device/caps'
     47     if not os.path.exists(caps_file):
     48         caps_file='/sys/class/tpm/tpm0/device/caps'
     49     try:
     50         with open(caps_file, 'r') as fp:
     51             caps = fp.read()
     52     except IOError:
     53         return 'Could not read TPM device caps.'
     54     match = re.search(r'Manufacturer: (0x[0-9A-Fa-f]*)', caps)
     55     if not match:
     56         return 'Could not find TPM manufacturer.'
     57     manufacturer = match.group(1)
     58     if manufacturer not in tpm_command_info:
     59         return 'TPM manufacturer not supported.'
     60     with service_stopper.ServiceStopper(['cryptohomed',
     61                                          'chapsd',
     62                                          'tcsd']):
     63         # The output of 'tpmc raw' is a series of bytes in the form
     64         # '0x00 0x01 0x02 ...'.
     65         tpm_response = utils.system_output(
     66                 'tpmc raw %s' % tpm_command_info[manufacturer]['command'],
     67                 ignore_status=True).split()
     68     offset = tpm_command_info[manufacturer]['response_offset']
     69     if (len(tpm_response) <= offset):
     70         return 'Unexpected TPM response (length = %d).' % len(tpm_response)
     71     return int(tpm_response[offset], base=16)
     72 
     73 
     74