summaryrefslogtreecommitdiff
path: root/test/tpm_test/tpmtest.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/tpm_test/tpmtest.py')
-rwxr-xr-xtest/tpm_test/tpmtest.py239
1 files changed, 9 insertions, 230 deletions
diff --git a/test/tpm_test/tpmtest.py b/test/tpm_test/tpmtest.py
index 5117f2b1ad..fe866f3665 100755
--- a/test/tpm_test/tpmtest.py
+++ b/test/tpm_test/tpmtest.py
@@ -3,7 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Module for testing TPM, using both conventional and extended commands."""
+"""Module for initializing and driving a SPI TPM."""
from __future__ import print_function
@@ -11,31 +11,19 @@ import os
import struct
import sys
import traceback
-import xml.etree.ElementTree as ET
# Suppressing pylint warning about an import not at the top of the file. The
# path needs to be set *before* the last import.
# pylint: disable=C6204
root_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
sys.path.append(os.path.join(root_dir, '..', '..', 'build', 'tpm_test'))
-import ftdi_spi_tpm
-# Basic crypto operations
-DECRYPT = 0
-ENCRYPT = 1
+import crypto_test
+import ftdi_spi_tpm
# Extension command for dcypto testing
EXT_CMD = 0xbaccd00a
-# Extension subcommands for encryption types
-AES = 0
-
-if hasattr(sys.stdout, 'isatty') and sys.stdout.isatty():
- cursor_back = '\x1b[1D' # Move one space to the left.
-else:
- cursor_back = ''
-
-
class TpmError(Exception):
pass
@@ -59,6 +47,7 @@ class TPM(object):
'80 01 00 00 00 0a 00 00 01 00')
def __init__(self, freq=800*1000, debug_mode=False):
+ self._debug_enabled = debug_mode
self._handle = ftdi_spi_tpm
if not self._handle.FtdiSpiInit(freq, debug_mode):
raise TpmError()
@@ -132,229 +121,19 @@ class TPM(object):
size, len(response)))
return response[header_size:]
-
-def hex_dump(binstr):
- """Convert string into its hex representation."""
- dump_lines = ['',]
- i = 0
- while i < len(binstr):
- strsize = min(16, len(binstr) - i)
- hexstr = ' '.join('%2.2x' % ord(x) for x in binstr[i:i+strsize])
- dump_lines.append(hexstr)
- i += strsize
- dump_lines.append('')
- return '\n'.join(dump_lines)
-
-
-def get_attribute(tdesc, attr_name, required=True):
- """Retrieve an attribute value from an XML node.
-
- Args:
-
- tdesc: an Element of the ElementTree, a test descriptor containing
- necessary information to run a single encryption/description
- session.
- attr_name: a string, the name of the attribute to retrieve.
- required: a Boolean, if True - the attribute must be present in the
- descriptor, otherwise it is considered optional
- Returns:
- The attribute value as a string (ascii or binary)
- Raises:
- TpmError: on various format errors, or in case a required attribute is not
- found, the error message describes the problem.
-
- """
- # Fields stored in hex format by default.
- default_hex = ('cipher_text', 'iv', 'key')
-
- data = tdesc.find(attr_name)
- if data is None:
- if required:
- raise TpmError('node "%s" does not have attribute "%s"' %
- (tdesc.get('name'), attr_name))
- return ''
-
- # Attribute is present, does it have to be decoded from hex?
- cell_format = data.get('format')
- if not cell_format:
- if attr_name in default_hex:
- cell_format = 'hex'
- else:
- cell_format = 'ascii'
- elif cell_format not in ('hex', 'ascii'):
- raise TpmError('%s:%s, unrecognizable format "%s"' %
- (tdesc.get('name'), attr_name, cell_format))
-
- text = ' '.join(x.strip() for x in data.text.splitlines() if x)
- if cell_format == 'ascii':
- return text
-
- # Drop spaces from hex representation.
- text = text.replace(' ', '')
- if len(text) & 3:
- raise TpmError('%s:%s %swrong hex number size' %
- (tdesc.get('name'), attr_name, hex_dump(text)))
- # Convert text to binary
- value = ''
- for x in range(len(text)/8):
- try:
- value += struct.pack('<I', int('0x%s' % text[8*x:8*(x+1)], 16))
- except ValueError:
- raise TpmError('%s:%s %swrong hex value' %
- (tdesc.get('name'), attr_name, hex_dump(text)))
- return value
-
-
-class CryptoD(object):
- """A helper object to contain an encryption scheme description.
-
- Attributes:
- subcmd: a 16 bit max integer, the extension subcommand to be used with
- this encryption scheme.
- sumbodes: an optional dictionary, the keys are strings, names of the
- encryption scheme submodes, the values are integers to be included in
- the appropriate subcommand fields to communicat the submode to the
- device.
- """
-
- def __init__(self, subcommand, submodes=None):
- self.subcmd = subcommand
- if not submodes:
- submodes = {}
- self.submodes = submodes
-
-SUPPORTED_MODES = {
- 'AES': CryptoD(AES, {
- 'ECB': 0,
- 'CTR': 1,
- 'CBC': 2,
- 'GCM': 3
- }),
-}
-
-
-def crypto_run(node_name, op_type, key, iv, in_text, out_text, tpm, debug_mode):
- """Perform a basic operation(encrypt or decrypt).
-
- This function creates an extended command with the requested parameters,
- sends it to the device, and then compares the response to the expected
- value.
-
- Args:
- node_name: a string, the name of the XML node this data comes from. The
- format of the name is "<enc type>:<submode> ....", where <enc type> is
- the major encryption mode (say AED or DES) and submode - a variant of
- the major scheme, if exists.
-
- op_type: an int, encodes the operation to perform (encrypt/decrypt), passed
- directly to the device as a field in the extended command
- key: a binary string
- iv: a binary string, might be empty
- in_text: a binary string, the input of the encrypt/decrypt operation
- out_text: a binary string, might be empty, the expected output of the
- operation. Note that it could be shorter than actual output (padded to
- integer number of blocks), in which case only its length of bytes is
- compared debug_mode: a Boolean, if True - enables tracing on the console
- tpm: a TPM object to send extended commands to an initialized TPM
- debug_mode: a Boolean, if True - this function and the FTDI driver
- generate debug messated on the console.
-
- Returns:
- The actual binary string, result of the operation, if the
- comparison with the expected value was successful.
-
- Raises:
- TpmError: in case there were problems parsing the node name, or verifying
- the operation results.
- """
- mode_name, submode_name = node_name.split(':')
- submode_name = submode_name[:3].upper()
-
- mode = SUPPORTED_MODES.get(mode_name.upper())
- if not mode:
- raise TpmError('unrecognizable mode in node "%s"' % node_name)
-
- submode = mode.submodes.get(submode_name, 0)
- cmd = '%c' % op_type # Encrypt or decrypt
- cmd += '%c' % submode # A particular type of a generic algorithm.
- cmd += '%c' % len(key)
- cmd += key
- cmd += '%c' % len(iv)
- if iv:
- cmd += iv
- cmd += struct.pack('>H', len(in_text))
- cmd += in_text
- if debug_mode:
- print('%d:%d cmd size' % (op_type, mode.subcmd), len(cmd), hex_dump(cmd))
- wrapped_response = tpm.command(tpm.wrap_ext_command(mode.subcmd, cmd))
- real_out_text = tpm.unwrap_ext_response(mode.subcmd, wrapped_response)
- if out_text:
- if len(real_out_text) > len(out_text):
- real_out_text = real_out_text[:len(out_text)] # Ignore padding
- if real_out_text != out_text:
- if debug_mode:
- print('Out text mismatch in node %s:\n' % node_name)
- else:
- raise TpmError('Out text mismatch in node %s, operation %d:\n'
- 'In text:%sExpected out text:%sReal out text:%s' % (
- node_name, op_type,
- hex_dump(in_text),
- hex_dump(out_text),
- hex_dump(real_out_text)))
- return real_out_text
-
-
-def crypto_test(tdesc, tpm, debug_mode):
- """Perform a single test described in the xml file.
-
- The xml node contains all pertinent information about the test inputs and
- outputs.
-
- Args:
- tdesc: an Element of the ElementTree, a test descriptor containing
- necessary information to run a single encryption/description
- session.
- tpm: a TPM object to send extended commands to an initialized TPM
- debug_mode: a Boolean, if True - this function and the FTDI driver
- generate debug messated on the console.
- Raises:
- TpmError: on various execution errors, the details are included in the
- error message.
- """
- node_name = tdesc.get('name')
- key = get_attribute(tdesc, 'key')
- if len(key) not in (16, 24, 32):
- raise TpmError('wrong key size "%s:%s"' % (
- node_name,
- ''.join('%2.2x' % ord(x) for x in key)))
- iv = get_attribute(tdesc, 'iv', required=False)
- if iv and len(iv) != 16:
- raise TpmError('wrong iv size "%s:%s"' % (
- node_name,
- ''.join('%2.2x' % ord(x) for x in iv)))
- clear_text = get_attribute(tdesc, 'clear_text')
- if debug_mode:
- print('clear text size', len(clear_text))
- cipher_text = get_attribute(tdesc, 'cipher_text', required=False)
- real_cipher_text = crypto_run(node_name, ENCRYPT, key, iv,
- clear_text, cipher_text, tpm, debug_mode)
- crypto_run(node_name, DECRYPT, key, iv, real_cipher_text,
- clear_text, tpm, debug_mode)
- print(cursor_back + 'SUCCESS: %s' % node_name)
+ def debug_enabled(self):
+ return self._debug_enabled
if __name__ == '__main__':
- tree = ET.parse(os.path.join(root_dir, 'crypto_test.xml'))
- root = tree.getroot()
try:
debug_needed = len(sys.argv) == 2 and sys.argv[1] == '-d'
t = TPM(debug_mode=debug_needed)
- for child in root:
- crypto_test(child, t, debug_needed)
- except TpmError as e:
+ crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml'))
+ except (TpmError, crypto_test.CryptoError) as e:
print()
- print(e)
+ print('Error:', e)
if debug_needed:
traceback.print_exc()
sys.exit(1)