From b3c265bcf3c412244644c788b2c94ba335222ea0 Mon Sep 17 00:00:00 2001 From: ghecko Date: Mon, 20 Jun 2022 10:23:09 +0200 Subject: [PATCH] Adding TPM v1.2 support --- .../decoders/spi_tpm/README.md | 28 + .../decoders/spi_tpm/RangeDict.py | 598 +++++++++--------- libsigrokdecode4DSL/decoders/spi_tpm/lists.py | 277 +++++--- libsigrokdecode4DSL/decoders/spi_tpm/pd.py | 102 ++- 4 files changed, 581 insertions(+), 424 deletions(-) create mode 100644 libsigrokdecode4DSL/decoders/spi_tpm/README.md diff --git a/libsigrokdecode4DSL/decoders/spi_tpm/README.md b/libsigrokdecode4DSL/decoders/spi_tpm/README.md new file mode 100644 index 00000000..662f4a7d --- /dev/null +++ b/libsigrokdecode4DSL/decoders/spi_tpm/README.md @@ -0,0 +1,28 @@ +# libsigrokdecoder_spi-tpm + +libsigrok stacked Protocol Decoder for TPM 2.0 & TPM 1.2 transactions from an SPI bus. +BitLocker Volume Master Key (VMK) is automatically extracted. + +## How to use + +### CLI + +Example from a previous capture (Value Change Dump - .vcd format): + +1. Identifying channels name: + +`sigrok-cli -i capture.vcd --show` + +2. Extracting BitLocker VMK (filter output to extract only VMK annotations) + +`.\sigrok-cli.exe -i C:\Users\jovre\Documents\tpm_spi_comm_2.vcd -I vcd:numchannels=6 -P spi:wordsize=8:cs_polarity=active-high:miso=libsigrok4DSL.3:mosi=libsigrok4DSL.1:clk=libsigrok4DSL.2:cs=libsigrok4DSL.0,spi_tpm:tpm_version=1.2 -A spi_tpm=VMK` + +***command output:*** + +`spi_tpm-1: VMK header: 2c0005000100000003200000` + +`spi_tpm-1: VMK: 85e5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxee00` + +### GUI + +Use and configure the SPI Protocol Decoder and then select SPI TPM Stack Decoder. diff --git a/libsigrokdecode4DSL/decoders/spi_tpm/RangeDict.py b/libsigrokdecode4DSL/decoders/spi_tpm/RangeDict.py index a2ecabca..665512cb 100644 --- a/libsigrokdecode4DSL/decoders/spi_tpm/RangeDict.py +++ b/libsigrokdecode4DSL/decoders/spi_tpm/RangeDict.py @@ -1,299 +1,299 @@ -# Source: https://raw.githubusercontent.com/WKPlus/rangedict/master/rangedict.py -__all__ = ['RangeDict'] - - -class Color(object): - BLACK = 0 - RED = 1 - - -class Node(object): - __slots__ = ('r', 'left', 'right', 'value', 'color', 'parent') - - def __init__(self, r, value, parent=None, color=Color.RED): - self.r = r - self.value = value - self.parent = parent - self.color = color - self.left = None - self.right = None - - def value_copy(self, other): - self.r = other.r - self.value = other.value - - -class RangeDict(dict): - - def __init__(self): - self._root = None - - def __setitem__(self, r, v): - if r[1] < r[0]: - raise KeyError - node = self._insert(r, v) - self._insert_adjust(node) - - def _insert(self, r, v): - if not self._root: - self._root = Node(r, v) - return self._root - cur = self._root - while True: - if r[1] < cur.r[0]: - if not cur.left: - cur.left = Node(r, v, cur) - return cur.left - cur = cur.left - elif r[0] > cur.r[1]: - if not cur.right: - cur.right = Node(r, v, cur) - return cur.right - cur = cur.right - else: - raise KeyError # overlap not supported - - def _insert_adjust(self, node): - ''' adjust to make the tree still a red black tree ''' - if not node.parent: - node.color = Color.BLACK - return - if node.parent.color == Color.BLACK: - return - uncle = self.sibling(node.parent) - if node_color(uncle) == Color.RED: - node.parent.color = Color.BLACK - uncle.color = Color.BLACK - node.parent.parent.color = Color.RED - return self._insert_adjust(node.parent.parent) - - #parent is red and uncle is black - # since parent is red, grandparent must exists and be black - parent = node.parent - grandparent = parent.parent - if self.is_left_son(parent, grandparent): - if self.is_left_son(node, parent): - self.right_rotate(grandparent) - grandparent.color = Color.RED - parent.color = Color.BLACK - else: - self.left_rotate(parent) - self.right_rotate(grandparent) - grandparent.color = Color.RED - node.color = Color.BLACK - else: - if self.is_left_son(node, parent): - self.right_rotate(parent) - self.left_rotate(grandparent) - grandparent.color = Color.RED - node.color = Color.BLACK - else: - self.left_rotate(grandparent) - grandparent.color = Color.RED - parent.color = Color.BLACK - - def _find_key(self, key): - cur = self._root - while cur: - if key > cur.r[1]: - cur = cur.right - elif key < cur.r[0]: - cur = cur.left - else: - break - return cur - - def _find_range(self, r): - cur = self._root - while cur: - if r[1] < cur.r[0]: - cur = cur.left - elif r[0] > cur.r[1]: - cur = cur.right - elif r[0] == cur.r[0] and r[1] == cur.r[1]: - return cur - else: - raise KeyError - raise KeyError - - def __getitem__(self, key): - tar = self._find_key(key) - if tar: - return tar.value - raise KeyError - - def __contains__(self, key): - return bool(self._find_key(key)) - - def __delitem__(self, r): - node = self._find_range(r) - if node.left and node.right: - left_rightest_child = self.find_rightest(node.left) - node.value_copy(left_rightest_child) - node = left_rightest_child - self._delete(node) - - def _delete(self, node): - # node has at most one child - child = node.left if node.left else node.right - if not node.parent: # node is root - self._root = child - if self._root: - self._root.parent = None - self._root.color = Color.BLACK - return - - parent = node.parent - if not child: - child = Node(None, None, parent, Color.BLACK) - if self.is_left_son(node, parent): - parent.left = child - else: - parent.right = child - child.parent = parent - - if node.color == Color.RED: - # no need to adjust when deleting a red node - return - if node_color(child) == Color.RED: - child.color = Color.BLACK - return - self._delete_adjust(child) - if not child.r: - # mock a None node for adjust, need to delete it after that - parent = child.parent - if self.is_left_son(child, parent): - parent.left = None - else: - parent.right = None - - def _delete_adjust(self, node): - if not node.parent: - node.color = Color.BLACK - return - - parent = node.parent - sibling = self.sibling(node) - if node_color(sibling) == Color.RED: - if self.is_left_son(node, parent): - self.left_rotate(parent) - else: - self.right_rotate(parent) - parent.color = Color.RED - sibling.color = Color.BLACK - sibling = self.sibling(node) # must be black - - # sibling must be black now - if not self.is_black(parent) and self.is_black(sibling.left) and \ - self.is_black(sibling.right): - parent.color = Color.BLACK - sibling.color = Color.RED - return - - if self.is_black(parent) and self.is_black(sibling.left) and \ - self.is_black(sibling.right): - sibling.color = Color.RED - return self._delete_adjust(parent) - - if self.is_left_son(node, parent): - if not self.is_black(sibling.left) and \ - self.is_black(sibling.right): - sibling.left.color = Color.BLACK - sibling.color = Color.RED - self.right_rotate(sibling) - sibling = sibling.parent - - # sibling.right must be red - sibling.color = parent.color - parent.color = Color.BLACK - sibling.right.color = Color.BLACK - self.left_rotate(parent) - else: - if not self.is_black(sibling.right) and \ - self.is_black(sibling.left): - sibling.right.color = Color.BLACK - sibling.color = Color.RED - self.left_rotate(parent) - sibling = sibling.parent - - # sibling.left must be red - sibling.color = parent.color - parent.color = Color.BLACK - sibling.left.color = Color.RED - self.right_rotate(parent) - - def left_rotate(self, node): - right_son = node.right - - if not node.parent: - self._root = right_son - elif self.is_left_son(node, node.parent): - node.parent.left = right_son - else: - node.parent.right = right_son - right_son.parent = node.parent - - node.parent = right_son - node.right = right_son.left - right_son.left = node - - def right_rotate(self, node): - left_son = node.left - if not node.parent: - self._root = left_son - elif self.is_left_son(node, node.parent): - node.parent.left = left_son - else: - node.parent.right = left_son - left_son.parent = node.parent - - node.parent = left_son - node.left = left_son.right - left_son.right = node - - @staticmethod - def sibling(node): - if node.parent.left == node: - return node.parent.right - else: - return node.parent.left - - @staticmethod - def is_left_son(child, parent): - if parent.left == child: - return True - else: - return False - - @staticmethod - def find_rightest(node): - while node.right: - node = node.right - return node - - @staticmethod - def is_black(node): - return node_color(node) == Color.BLACK - - -def node_color(node): - if not node: - return Color.BLACK - return node.color - - -def in_order(root): - ret = [] - if not root: - return [] - return in_order(root.left) + [root.value] + in_order(root.right) - - -def height(root): - if not root: - return 0 - return 1 + max(height(root.left), height(root.right)) - - -if __name__ == '__main__': - pass +# Source: https://raw.githubusercontent.com/WKPlus/rangedict/master/rangedict.py +__all__ = ['RangeDict'] + + +class Color(object): + BLACK = 0 + RED = 1 + + +class Node(object): + __slots__ = ('r', 'left', 'right', 'value', 'color', 'parent') + + def __init__(self, r, value, parent=None, color=Color.RED): + self.r = r + self.value = value + self.parent = parent + self.color = color + self.left = None + self.right = None + + def value_copy(self, other): + self.r = other.r + self.value = other.value + + +class RangeDict(dict): + + def __init__(self): + self._root = None + + def __setitem__(self, r, v): + if r[1] < r[0]: + raise KeyError + node = self._insert(r, v) + self._insert_adjust(node) + + def _insert(self, r, v): + if not self._root: + self._root = Node(r, v) + return self._root + cur = self._root + while True: + if r[1] < cur.r[0]: + if not cur.left: + cur.left = Node(r, v, cur) + return cur.left + cur = cur.left + elif r[0] > cur.r[1]: + if not cur.right: + cur.right = Node(r, v, cur) + return cur.right + cur = cur.right + else: + raise KeyError # overlap not supported + + def _insert_adjust(self, node): + ''' adjust to make the tree still a red black tree ''' + if not node.parent: + node.color = Color.BLACK + return + if node.parent.color == Color.BLACK: + return + uncle = self.sibling(node.parent) + if node_color(uncle) == Color.RED: + node.parent.color = Color.BLACK + uncle.color = Color.BLACK + node.parent.parent.color = Color.RED + return self._insert_adjust(node.parent.parent) + + #parent is red and uncle is black + # since parent is red, grandparent must exists and be black + parent = node.parent + grandparent = parent.parent + if self.is_left_son(parent, grandparent): + if self.is_left_son(node, parent): + self.right_rotate(grandparent) + grandparent.color = Color.RED + parent.color = Color.BLACK + else: + self.left_rotate(parent) + self.right_rotate(grandparent) + grandparent.color = Color.RED + node.color = Color.BLACK + else: + if self.is_left_son(node, parent): + self.right_rotate(parent) + self.left_rotate(grandparent) + grandparent.color = Color.RED + node.color = Color.BLACK + else: + self.left_rotate(grandparent) + grandparent.color = Color.RED + parent.color = Color.BLACK + + def _find_key(self, key): + cur = self._root + while cur: + if key > cur.r[1]: + cur = cur.right + elif key < cur.r[0]: + cur = cur.left + else: + break + return cur + + def _find_range(self, r): + cur = self._root + while cur: + if r[1] < cur.r[0]: + cur = cur.left + elif r[0] > cur.r[1]: + cur = cur.right + elif r[0] == cur.r[0] and r[1] == cur.r[1]: + return cur + else: + raise KeyError + raise KeyError + + def __getitem__(self, key): + tar = self._find_key(key) + if tar: + return tar.value + raise KeyError + + def __contains__(self, key): + return bool(self._find_key(key)) + + def __delitem__(self, r): + node = self._find_range(r) + if node.left and node.right: + left_rightest_child = self.find_rightest(node.left) + node.value_copy(left_rightest_child) + node = left_rightest_child + self._delete(node) + + def _delete(self, node): + # node has at most one child + child = node.left if node.left else node.right + if not node.parent: # node is root + self._root = child + if self._root: + self._root.parent = None + self._root.color = Color.BLACK + return + + parent = node.parent + if not child: + child = Node(None, None, parent, Color.BLACK) + if self.is_left_son(node, parent): + parent.left = child + else: + parent.right = child + child.parent = parent + + if node.color == Color.RED: + # no need to adjust when deleting a red node + return + if node_color(child) == Color.RED: + child.color = Color.BLACK + return + self._delete_adjust(child) + if not child.r: + # mock a None node for adjust, need to delete it after that + parent = child.parent + if self.is_left_son(child, parent): + parent.left = None + else: + parent.right = None + + def _delete_adjust(self, node): + if not node.parent: + node.color = Color.BLACK + return + + parent = node.parent + sibling = self.sibling(node) + if node_color(sibling) == Color.RED: + if self.is_left_son(node, parent): + self.left_rotate(parent) + else: + self.right_rotate(parent) + parent.color = Color.RED + sibling.color = Color.BLACK + sibling = self.sibling(node) # must be black + + # sibling must be black now + if not self.is_black(parent) and self.is_black(sibling.left) and \ + self.is_black(sibling.right): + parent.color = Color.BLACK + sibling.color = Color.RED + return + + if self.is_black(parent) and self.is_black(sibling.left) and \ + self.is_black(sibling.right): + sibling.color = Color.RED + return self._delete_adjust(parent) + + if self.is_left_son(node, parent): + if not self.is_black(sibling.left) and \ + self.is_black(sibling.right): + sibling.left.color = Color.BLACK + sibling.color = Color.RED + self.right_rotate(sibling) + sibling = sibling.parent + + # sibling.right must be red + sibling.color = parent.color + parent.color = Color.BLACK + sibling.right.color = Color.BLACK + self.left_rotate(parent) + else: + if not self.is_black(sibling.right) and \ + self.is_black(sibling.left): + sibling.right.color = Color.BLACK + sibling.color = Color.RED + self.left_rotate(parent) + sibling = sibling.parent + + # sibling.left must be red + sibling.color = parent.color + parent.color = Color.BLACK + sibling.left.color = Color.RED + self.right_rotate(parent) + + def left_rotate(self, node): + right_son = node.right + + if not node.parent: + self._root = right_son + elif self.is_left_son(node, node.parent): + node.parent.left = right_son + else: + node.parent.right = right_son + right_son.parent = node.parent + + node.parent = right_son + node.right = right_son.left + right_son.left = node + + def right_rotate(self, node): + left_son = node.left + if not node.parent: + self._root = left_son + elif self.is_left_son(node, node.parent): + node.parent.left = left_son + else: + node.parent.right = left_son + left_son.parent = node.parent + + node.parent = left_son + node.left = left_son.right + left_son.right = node + + @staticmethod + def sibling(node): + if node.parent.left == node: + return node.parent.right + else: + return node.parent.left + + @staticmethod + def is_left_son(child, parent): + if parent.left == child: + return True + else: + return False + + @staticmethod + def find_rightest(node): + while node.right: + node = node.right + return node + + @staticmethod + def is_black(node): + return node_color(node) == Color.BLACK + + +def node_color(node): + if not node: + return Color.BLACK + return node.color + + +def in_order(root): + ret = [] + if not root: + return [] + return in_order(root.left) + [root.value] + in_order(root.right) + + +def height(root): + if not root: + return 0 + return 1 + max(height(root.left), height(root.right)) + + +if __name__ == '__main__': + pass diff --git a/libsigrokdecode4DSL/decoders/spi_tpm/lists.py b/libsigrokdecode4DSL/decoders/spi_tpm/lists.py index 40481ccc..26890ac4 100644 --- a/libsigrokdecode4DSL/decoders/spi_tpm/lists.py +++ b/libsigrokdecode4DSL/decoders/spi_tpm/lists.py @@ -23,96 +23,187 @@ from .RangeDict import RangeDict # Register space Addresses is defined on the paragraph 6.3.2 of the following document: https://trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2p0-v1p05p_r14_pub.pdf # Credit: https://github.com/FSecureLABS/bitlocker-spi-toolkit -fifo_registers = RangeDict() -fifo_registers[(0x0000, 0x0000)] = "TPM_ACCESS_0" -fifo_registers[(0x0001, 0x0007)] = "Reserved" -fifo_registers[(0x0008, 0x000b)] = "TPM_INT_ENABLE_0" -fifo_registers[(0x000c, 0x000c)] = "TPM_INT_VECTOR_0" -fifo_registers[(0x000d, 0x000f)] = "Reserved" -fifo_registers[(0x0010, 0x0013)] = "TPM_INT_STATUS_0" -fifo_registers[(0x0014, 0x0017)] = "TPM_INTF_CAPABILITY_0" -fifo_registers[(0x0018, 0x001b)] = "TPM_STS_0" -fifo_registers[(0x001c, 0x0023)] = "Reserved" -fifo_registers[(0x0024, 0x0027)] = "TPM_DATA_FIFO_0" -fifo_registers[(0x0028, 0x002f)] = "Reserved" -fifo_registers[(0x0030, 0x0033)] = "TPM_INTERFACE_ID_0" -fifo_registers[(0x0034, 0x007f)] = "Reserved" -fifo_registers[(0x0080, 0x0083)] = "TPM_XDATA_FIFO_0" -fifo_registers[(0x0084, 0x0881)] = "Reserved" -fifo_registers[(0x0f00, 0x0f03)] = "TPM_DID_VID_0" -fifo_registers[(0x0f04, 0x0f04)] = "TPM_RID_0" -fifo_registers[(0x0f90, 0x0fff)] = "Reserved" -fifo_registers[(0x1000, 0x1000)] = "TPM_ACCESS_1" -fifo_registers[(0x1001, 0x1007)] = "Reserved" -fifo_registers[(0x1008, 0x100b)] = "TPM_INT_ENABLE_1" -fifo_registers[(0x100c, 0x100c)] = "TPM_INT_VECTOR_1" -fifo_registers[(0x100d, 0x100f)] = "Reserved" -fifo_registers[(0x1010, 0x1013)] = "TPM_INT_STATUS_1" -fifo_registers[(0x1014, 0x1017)] = "TPM_INTF_CAPABILITY_1" -fifo_registers[(0x1018, 0x101b)] = "TPM_STS_1" -fifo_registers[(0x101c, 0x1023)] = "Reserved" -fifo_registers[(0x1024, 0x1027)] = "TPM_DATA_FIFO_1" -fifo_registers[(0x1028, 0x102f)] = "Reserved" -fifo_registers[(0x1030, 0x1030)] = "TPM_INTERFACE_ID_1" -fifo_registers[(0x1037, 0x107f)] = "Reserved" -fifo_registers[(0x1080, 0x1083)] = "TPM_XDATA_FIFO_1" -fifo_registers[(0x1084, 0x1eff)] = "Reserved" -fifo_registers[(0x1f00, 0x1f03)] = "TPM_DID_VID_1" -fifo_registers[(0x1f04, 0x1f04)] = "TPM_RID_1" -fifo_registers[(0x1f05, 0x1fff)] = "Reserved" -fifo_registers[(0x2000, 0x2000)] = "TPM_ACCESS_2" -fifo_registers[(0x2001, 0x2007)] = "Reserved" -fifo_registers[(0x2008, 0x200b)] = "TPM_INT_ENABLE_2" -fifo_registers[(0x200c, 0x200c)] = "TPM_INT_VECTOR_2" -fifo_registers[(0x200d, 0x200f)] = "Reserved" -fifo_registers[(0x2010, 0x2013)] = "TPM_INT_STATUS_2" -fifo_registers[(0x2014, 0x2017)] = "TPM_INTF_CAPABILITY_2" -fifo_registers[(0x2018, 0x201b)] = "TPM_STS_2" -fifo_registers[(0x201c, 0x2023)] = "Reserved" -fifo_registers[(0x2024, 0x2027)] = "TPM_DATA_FIFO_2" -fifo_registers[(0x2028, 0x202f)] = "Reserved" -fifo_registers[(0x2030, 0x2033)] = "TPM_INTERFACE_ID_2" -fifo_registers[(0x2034, 0x207f)] = "Reserved" -fifo_registers[(0x2080, 0x2083)] = "TPM_XDATA_FIFO_2" -fifo_registers[(0x2084, 0x2eff)] = "Reserved" -fifo_registers[(0x2f00, 0x2f03)] = "TPM_DID_VID_2" -fifo_registers[(0x2f04, 0x2f04)] = "TPM_RID_2" -fifo_registers[(0x2f05, 0x2fff)] = "Reserved" -fifo_registers[(0x3000, 0x3000)] = "TPM_ACCESS_3" -fifo_registers[(0x3001, 0x3007)] = "Reserved" -fifo_registers[(0x3008, 0x300b)] = "TPM_INT_ENABLE_3" -fifo_registers[(0x300c, 0x300c)] = "TPM_INT_VECTOR_3" -fifo_registers[(0x300d, 0x300f)] = "Reserved" -fifo_registers[(0x3010, 0x3013)] = "TPM_INT_STATUS_3" -fifo_registers[(0x3014, 0x3017)] = "TPM_INTF_CAPABILITY_3" -fifo_registers[(0x3018, 0x301b)] = "TPM_STS_3" -fifo_registers[(0x301c, 0x3023)] = "Reserved" -fifo_registers[(0x3024, 0x3027)] = "TPM_DATA_FIFO_3" -fifo_registers[(0x3028, 0x302f)] = "Reserved" -fifo_registers[(0x3030, 0x3033)] = "TPM_INTERFACE_ID_3" -fifo_registers[(0x3034, 0x307f)] = "Reserved" -fifo_registers[(0x3080, 0x3083)] = "TPM_XDATA_FIFO_3" -fifo_registers[(0x3084, 0x3eff)] = "Reserved" -fifo_registers[(0x3f00, 0x3f03)] = "TPM_DID_VID_3" -fifo_registers[(0x3f04, 0x3f04)] = "TPM_RID_3" -fifo_registers[(0x3f05, 0x3fff)] = "Reserved" -fifo_registers[(0x4000, 0x4000)] = "TPM_ACCESS_4" -fifo_registers[(0x4001, 0x4007)] = "Reserved" -fifo_registers[(0x4008, 0x400b)] = "TPM_INT_ENABLE_4" -fifo_registers[(0x400c, 0x400c)] = "TPM_INT_VECTOR_4" -fifo_registers[(0x400d, 0x400f)] = "Reserved" -fifo_registers[(0x4010, 0x4013)] = "TPM_INT_STATUS_4" -fifo_registers[(0x4014, 0x4017)] = "TPM_INTF_CAPABILITY_4" -fifo_registers[(0x4018, 0x401b)] = "TPM_STS_4" -fifo_registers[(0x401c, 0x401f)] = "Reserved" -fifo_registers[(0x4020, 0x4023)] = "TPM_HASH_END" -fifo_registers[(0x4024, 0x4027)] = "TPM_DATA_FIFO_4" -fifo_registers[(0x4028, 0x402f)] = "TPM_HASH_START" -fifo_registers[(0x4030, 0x4033)] = "TPM_INTERFACE_ID_4" -fifo_registers[(0x4034, 0x407f)] = "Reserved" -fifo_registers[(0x4080, 0x4083)] = "TPM_XDATA_FIFO_4" -fifo_registers[(0x4084, 0x4eff)] = "Reserved" -fifo_registers[(0x4f00, 0x4f03)] = "TPM_DID_VID_4" -fifo_registers[(0x4f04, 0x4f04)] = "TPM_RID_4" -fifo_registers[(0x4f05, 0x4fff)] = "Reserved" -fifo_registers[(0x5000, 0x5fff)] = "Reserved" +# TPM 2.0 registers +fifo_registers2 = RangeDict() +fifo_registers2[(0x0000, 0x0000)] = "TPM_ACCESS_0" +fifo_registers2[(0x0001, 0x0007)] = "Reserved" +fifo_registers2[(0x0008, 0x000b)] = "TPM_INT_ENABLE_0" +fifo_registers2[(0x000c, 0x000c)] = "TPM_INT_VECTOR_0" +fifo_registers2[(0x000d, 0x000f)] = "Reserved" +fifo_registers2[(0x0010, 0x0013)] = "TPM_INT_STATUS_0" +fifo_registers2[(0x0014, 0x0017)] = "TPM_INTF_CAPABILITY_0" +fifo_registers2[(0x0018, 0x001b)] = "TPM_STS_0" +fifo_registers2[(0x001c, 0x0023)] = "Reserved" +fifo_registers2[(0x0024, 0x0027)] = "TPM_DATA_FIFO_0" +fifo_registers2[(0x0028, 0x002f)] = "Reserved" +fifo_registers2[(0x0030, 0x0033)] = "TPM_INTERFACE_ID_0" +fifo_registers2[(0x0034, 0x007f)] = "Reserved" +fifo_registers2[(0x0080, 0x0083)] = "TPM_XDATA_FIFO_0" +fifo_registers2[(0x0084, 0x0881)] = "Reserved" +fifo_registers2[(0x0f00, 0x0f03)] = "TPM_DID_VID_0" +fifo_registers2[(0x0f04, 0x0f04)] = "TPM_RID_0" +fifo_registers2[(0x0f90, 0x0fff)] = "Reserved" +fifo_registers2[(0x1000, 0x1000)] = "TPM_ACCESS_1" +fifo_registers2[(0x1001, 0x1007)] = "Reserved" +fifo_registers2[(0x1008, 0x100b)] = "TPM_INT_ENABLE_1" +fifo_registers2[(0x100c, 0x100c)] = "TPM_INT_VECTOR_1" +fifo_registers2[(0x100d, 0x100f)] = "Reserved" +fifo_registers2[(0x1010, 0x1013)] = "TPM_INT_STATUS_1" +fifo_registers2[(0x1014, 0x1017)] = "TPM_INTF_CAPABILITY_1" +fifo_registers2[(0x1018, 0x101b)] = "TPM_STS_1" +fifo_registers2[(0x101c, 0x1023)] = "Reserved" +fifo_registers2[(0x1024, 0x1027)] = "TPM_DATA_FIFO_1" +fifo_registers2[(0x1028, 0x102f)] = "Reserved" +fifo_registers2[(0x1030, 0x1030)] = "TPM_INTERFACE_ID_1" +fifo_registers2[(0x1037, 0x107f)] = "Reserved" +fifo_registers2[(0x1080, 0x1083)] = "TPM_XDATA_FIFO_1" +fifo_registers2[(0x1084, 0x1eff)] = "Reserved" +fifo_registers2[(0x1f00, 0x1f03)] = "TPM_DID_VID_1" +fifo_registers2[(0x1f04, 0x1f04)] = "TPM_RID_1" +fifo_registers2[(0x1f05, 0x1fff)] = "Reserved" +fifo_registers2[(0x2000, 0x2000)] = "TPM_ACCESS_2" +fifo_registers2[(0x2001, 0x2007)] = "Reserved" +fifo_registers2[(0x2008, 0x200b)] = "TPM_INT_ENABLE_2" +fifo_registers2[(0x200c, 0x200c)] = "TPM_INT_VECTOR_2" +fifo_registers2[(0x200d, 0x200f)] = "Reserved" +fifo_registers2[(0x2010, 0x2013)] = "TPM_INT_STATUS_2" +fifo_registers2[(0x2014, 0x2017)] = "TPM_INTF_CAPABILITY_2" +fifo_registers2[(0x2018, 0x201b)] = "TPM_STS_2" +fifo_registers2[(0x201c, 0x2023)] = "Reserved" +fifo_registers2[(0x2024, 0x2027)] = "TPM_DATA_FIFO_2" +fifo_registers2[(0x2028, 0x202f)] = "Reserved" +fifo_registers2[(0x2030, 0x2033)] = "TPM_INTERFACE_ID_2" +fifo_registers2[(0x2034, 0x207f)] = "Reserved" +fifo_registers2[(0x2080, 0x2083)] = "TPM_XDATA_FIFO_2" +fifo_registers2[(0x2084, 0x2eff)] = "Reserved" +fifo_registers2[(0x2f00, 0x2f03)] = "TPM_DID_VID_2" +fifo_registers2[(0x2f04, 0x2f04)] = "TPM_RID_2" +fifo_registers2[(0x2f05, 0x2fff)] = "Reserved" +fifo_registers2[(0x3000, 0x3000)] = "TPM_ACCESS_3" +fifo_registers2[(0x3001, 0x3007)] = "Reserved" +fifo_registers2[(0x3008, 0x300b)] = "TPM_INT_ENABLE_3" +fifo_registers2[(0x300c, 0x300c)] = "TPM_INT_VECTOR_3" +fifo_registers2[(0x300d, 0x300f)] = "Reserved" +fifo_registers2[(0x3010, 0x3013)] = "TPM_INT_STATUS_3" +fifo_registers2[(0x3014, 0x3017)] = "TPM_INTF_CAPABILITY_3" +fifo_registers2[(0x3018, 0x301b)] = "TPM_STS_3" +fifo_registers2[(0x301c, 0x3023)] = "Reserved" +fifo_registers2[(0x3024, 0x3027)] = "TPM_DATA_FIFO_3" +fifo_registers2[(0x3028, 0x302f)] = "Reserved" +fifo_registers2[(0x3030, 0x3033)] = "TPM_INTERFACE_ID_3" +fifo_registers2[(0x3034, 0x307f)] = "Reserved" +fifo_registers2[(0x3080, 0x3083)] = "TPM_XDATA_FIFO_3" +fifo_registers2[(0x3084, 0x3eff)] = "Reserved" +fifo_registers2[(0x3f00, 0x3f03)] = "TPM_DID_VID_3" +fifo_registers2[(0x3f04, 0x3f04)] = "TPM_RID_3" +fifo_registers2[(0x3f05, 0x3fff)] = "Reserved" +fifo_registers2[(0x4000, 0x4000)] = "TPM_ACCESS_4" +fifo_registers2[(0x4001, 0x4007)] = "Reserved" +fifo_registers2[(0x4008, 0x400b)] = "TPM_INT_ENABLE_4" +fifo_registers2[(0x400c, 0x400c)] = "TPM_INT_VECTOR_4" +fifo_registers2[(0x400d, 0x400f)] = "Reserved" +fifo_registers2[(0x4010, 0x4013)] = "TPM_INT_STATUS_4" +fifo_registers2[(0x4014, 0x4017)] = "TPM_INTF_CAPABILITY_4" +fifo_registers2[(0x4018, 0x401b)] = "TPM_STS_4" +fifo_registers2[(0x401c, 0x401f)] = "Reserved" +fifo_registers2[(0x4020, 0x4023)] = "TPM_HASH_END" +fifo_registers2[(0x4024, 0x4027)] = "TPM_DATA_FIFO_4" +fifo_registers2[(0x4028, 0x402f)] = "TPM_HASH_START" +fifo_registers2[(0x4030, 0x4033)] = "TPM_INTERFACE_ID_4" +fifo_registers2[(0x4034, 0x407f)] = "Reserved" +fifo_registers2[(0x4080, 0x4083)] = "TPM_XDATA_FIFO_4" +fifo_registers2[(0x4084, 0x4eff)] = "Reserved" +fifo_registers2[(0x4f00, 0x4f03)] = "TPM_DID_VID_4" +fifo_registers2[(0x4f04, 0x4f04)] = "TPM_RID_4" +fifo_registers2[(0x4f05, 0x4fff)] = "Reserved" +fifo_registers2[(0x5000, 0x5fff)] = "Reserved" + +# TPM 1.2 registers +fifo_registers1 = RangeDict() +fifo_registers1[(0x0000, 0x0000)] = "TPM_ACCESS_0" +fifo_registers1[(0x0008, 0x000b)] = "TPM_INT_ENABLE_0" +fifo_registers1[(0x000c, 0x000c)] = "TPM_INT_VECTOR_0" +fifo_registers1[(0x0010, 0x0013)] = "TPM_INT_STATUS_0" +fifo_registers1[(0x0014, 0x0017)] = "TPM_INTF_CAPABILITY_0" +fifo_registers1[(0x0018, 0x001a)] = "TPM_STS_0" +fifo_registers1[(0x0024, 0x0027)] = "TPM_DATA_FIFO_0" +fifo_registers1[(0x0080, 0x0083)] = "TPM_XDATA_FIFO_0" +fifo_registers1[(0x0084, 0x00bf)] = "Reserved" +fifo_registers1[(0x0f00, 0x0f03)] = "TPM_DID_VID_0" +fifo_registers1[(0x0f04, 0x0f04)] = "TPM_RID_0" +fifo_registers1[(0x0f05, 0x0f7f)] = "Reserved" +fifo_registers1[(0x0f80, 0x0f80)] = "FIRST_LEGACY_ADDRESS_0" +fifo_registers1[(0x0f84, 0x0f84)] = "FIRST_LEGACY_ADDRESS_EXTENSION_0" +fifo_registers1[(0x0f88, 0x0f88)] = "SECOND_LEGACY_ADDRESS_0" +fifo_registers1[(0x0f8c, 0x0f8c)] = "SECOND_LEGACY_ADDRESS_EXTENSION_0" +fifo_registers1[(0x0f90, 0x0fff)] = "VENDOR_DEFINED" +fifo_registers1[(0x1000, 0x1000)] = "TPM_ACCESS_1" +fifo_registers1[(0x1008, 0x100b)] = "TPM_INT_ENABLE_1" +fifo_registers1[(0x100c, 0x100c)] = "TPM_INT_VECTOR_1" +fifo_registers1[(0x1010, 0x1013)] = "TPM_INT_STATUS_1" +fifo_registers1[(0x1014, 0x1017)] = "TPM_INTF_CAPABILITY_1" +fifo_registers1[(0x1018, 0x101a)] = "TPM_STS_1" +fifo_registers1[(0x1024, 0x1027)] = "TPM_DATA_FIFO_1" +fifo_registers1[(0x1080, 0x1083)] = "TPM_XDATA_FIFO_1" +fifo_registers1[(0x1084, 0x10bf)] = "Reserved" +fifo_registers1[(0x1f00, 0x1f03)] = "TPM_DID_VID_1" +fifo_registers1[(0x1f04, 0x1f04)] = "TPM_RID_1" +fifo_registers1[(0x1f05, 0x1f7f)] = "Reserved" +fifo_registers1[(0x1f80, 0x1f80)] = "Reserved" +fifo_registers1[(0x1f84, 0x1f84)] = "Reserved" +fifo_registers1[(0x1f88, 0x1f88)] = "Reserved" +fifo_registers1[(0x1f8c, 0x1f8c)] = "Reserved" +fifo_registers1[(0x1f90, 0x1fff)] = "VENDOR_DEFINED" +fifo_registers1[(0x2000, 0x2000)] = "TPM_ACCESS_2" +fifo_registers1[(0x2008, 0x200b)] = "TPM_INT_ENABLE_2" +fifo_registers1[(0x200c, 0x200c)] = "TPM_INT_VECTOR_2" +fifo_registers1[(0x2010, 0x2013)] = "TPM_INT_STATUS_2" +fifo_registers1[(0x2014, 0x2017)] = "TPM_INTF_CAPABILITY_2" +fifo_registers1[(0x2018, 0x201a)] = "TPM_STS_2" +fifo_registers1[(0x2024, 0x2027)] = "TPM_DATA_FIFO_2" +fifo_registers1[(0x2080, 0x2083)] = "TPM_XDATA_FIFO_2" +fifo_registers1[(0x2084, 0x20bf)] = "Reserved" +fifo_registers1[(0x2f00, 0x2f03)] = "TPM_DID_VID_2" +fifo_registers1[(0x2f04, 0x2f04)] = "TPM_RID_2" +fifo_registers1[(0x2f05, 0x2f7f)] = "Reserved" +fifo_registers1[(0x2f80, 0x2f80)] = "Reserved" +fifo_registers1[(0x2f84, 0x2f84)] = "Reserved" +fifo_registers1[(0x2f88, 0x2f88)] = "Reserved" +fifo_registers1[(0x2f8c, 0x2f8c)] = "Reserved" +fifo_registers1[(0x2f90, 0x2fff)] = "VENDOR_DEFINED" +fifo_registers1[(0x3000, 0x3000)] = "TPM_ACCESS_3" +fifo_registers1[(0x3008, 0x300b)] = "TPM_INT_ENABLE_3" +fifo_registers1[(0x300c, 0x300c)] = "TPM_INT_VECTOR_3" +fifo_registers1[(0x3010, 0x3013)] = "TPM_INT_STATUS_3" +fifo_registers1[(0x3014, 0x3017)] = "TPM_INTF_CAPABILITY_3" +fifo_registers1[(0x3018, 0x301a)] = "TPM_STS_3" +fifo_registers1[(0x3024, 0x3027)] = "TPM_DATA_FIFO_3" +fifo_registers1[(0x3080, 0x3083)] = "TPM_XDATA_FIFO_3" +fifo_registers1[(0x3084, 0x30bf)] = "Reserved" +fifo_registers1[(0x3f00, 0x3f03)] = "TPM_DID_VID_3" +fifo_registers1[(0x3f04, 0x3f04)] = "TPM_RID_3" +fifo_registers1[(0x3f05, 0x3f7f)] = "Reserved" +fifo_registers1[(0x3f80, 0x3f80)] = "Reserved" +fifo_registers1[(0x3f84, 0x3f84)] = "Reserved" +fifo_registers1[(0x3f88, 0x3f88)] = "Reserved" +fifo_registers1[(0x3f8c, 0x3f8c)] = "Reserved" +fifo_registers1[(0x3f90, 0x3fff)] = "VENDOR_DEFINED" +fifo_registers1[(0x4000, 0x4000)] = "TPM_ACCESS_4" +fifo_registers1[(0x4008, 0x400b)] = "TPM_INT_ENABLE_4" +fifo_registers1[(0x400c, 0x400c)] = "TPM_INT_VECTOR_4" +fifo_registers1[(0x4010, 0x4013)] = "TPM_INT_STATUS_4" +fifo_registers1[(0x4014, 0x4017)] = "TPM_INTF_CAPABILITY_4" +fifo_registers1[(0x4018, 0x401a)] = "TPM_STS_4" +fifo_registers1[(0x4020, 0x4020)] = "TPM_HASH_END" +fifo_registers1[(0x4024, 0x4027)] = "TPM_DATA_FIFO_4" +fifo_registers1[(0x4028, 0x4028)] = "TPM_HASH_START" +fifo_registers1[(0x4080, 0x4083)] = "TPM_XDATA_FIFO_4" +fifo_registers1[(0x4084, 0x40bf)] = "Reserved" +fifo_registers1[(0x4f00, 0x4f03)] = "TPM_DID_VID_4" +fifo_registers1[(0x4f04, 0x4f04)] = "TPM_RID_4" +fifo_registers1[(0x4f05, 0x4f7f)] = "Reserved" +fifo_registers1[(0x4f80, 0x4f80)] = "Reserved" +fifo_registers1[(0x4f84, 0x4f84)] = "Reserved" +fifo_registers1[(0x4f88, 0x4f88)] = "Reserved" +fifo_registers1[(0x4f8c, 0x4f8c)] = "Reserved" +fifo_registers1[(0x4f90, 0x4fff)] = "VENDOR_DEFINED" diff --git a/libsigrokdecode4DSL/decoders/spi_tpm/pd.py b/libsigrokdecode4DSL/decoders/spi_tpm/pd.py index 167d5c9e..d4cd081b 100644 --- a/libsigrokdecode4DSL/decoders/spi_tpm/pd.py +++ b/libsigrokdecode4DSL/decoders/spi_tpm/pd.py @@ -20,12 +20,12 @@ import sigrokdecode as srd import re from collections import deque -from .lists import fifo_registers +from .lists import fifo_registers2, fifo_registers1 class Ann: """ Annotation ID """ - READ, WRITE, ADDRESS, DATA, VMK = range(5) + READ, WRITE, ADDRESS, WAIT, DATA, VMK = range(6) class Operation: @@ -64,6 +64,7 @@ class Transaction: self.end_sample_op = None self.end_sample_addr = None self.end_sample_data = None + self.end_sample_wait = None self.operation = operation self.address = bytearray() self.data = bytearray() @@ -85,7 +86,7 @@ class Transaction: """ Check if all address bytes are captured. """ return len(self.address) == 3 - def frame(self): + def frame(self, fifo_registers): """ Return address and data annotation if the transaction is complete. """ if self.is_complete(): register_name = "" @@ -93,14 +94,20 @@ class Transaction: register_name = fifo_registers[int.from_bytes(self.address, "big") & 0xffff] except KeyError: register_name = "Unknown" - wait_str = '' if self.wait_count == 0 else ' (Waits: {})'.format(self.wait_count) data_str = ''.join('{:02x}'.format(x) for x in self.data) op_ann = ['Read', 'Rd'] if self.operation == Operation.READ else ['Write', 'Wr'] + wait_ann = ['Wait', 'Wt'] addr_ann = ['Register: {}'.format(register_name), '{}'.format(register_name)] - data_ann = ['{}{}'.format(data_str, wait_str), '{}'.format(data_str), data_str] - return ((self.start_sample, self.end_sample_op, op_ann), - (self.end_sample_op, self.end_sample_addr, addr_ann), - (self.end_sample_addr, self.end_sample_data, data_ann)) + data_ann = ['{}'.format(data_str), '{}'.format(data_str), data_str] + if self.wait_count > 0: + return ((self.start_sample, self.end_sample_op, op_ann), + (self.end_sample_op, self.end_sample_addr, addr_ann), + (self.end_sample_addr, self.end_sample_wait, wait_ann), + (self.end_sample_wait, self.end_sample_data, data_ann)) + else: + return ((self.start_sample, self.end_sample_op, op_ann), + (self.end_sample_op, self.end_sample_addr, addr_ann), + (self.end_sample_addr, self.end_sample_data, data_ann)) return None @@ -119,18 +126,20 @@ class Decoder(srd.Decoder): ('Write', 'Write register operation'), ('Address', 'Register address'), ('Data', 'Data'), + ('Wait', 'Wait'), ('VMK', 'Extracted BitLocker VMK'), ) annotation_rows = ( - ('Transactions', 'TPM transactions', (0, 1, 2, 3)), - ('B-VMK', 'BitLocker Volume Master Key', (4,)), + ('Transactions', 'TPM transactions', (0, 1, 2, 3, 4)), + ('B-VMK', 'BitLocker Volume Master Key', (5,)), ) options = ( - {'id': 'wait_mask', 'desc': 'TPM Wait transfer Mask', 'default': '0x00', - 'values': ('0x00', '0xFE')}, + {'id': 'tpm_version', 'desc': 'TPM Version 1.2 or 2.0', 'default': '2.0', + 'values': ('2.0', '1.2')}, ) def __init__(self): + # TPM Profile Specification for TPM 2.0 page 133-134 self.end_wait = 0x01 self.operation_mask = 0x80 self.address_mask = 0x3f @@ -142,6 +151,7 @@ class Decoder(srd.Decoder): self.reset() self.state_machine = None self.init_state_machine() + self.fifo_registers = None def reset(self): self.ss = self.es = 0 @@ -153,6 +163,12 @@ class Decoder(srd.Decoder): def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) + if self.options['tpm_version'] == "2.0": + self.wait_mask = 0x00 + self.fifo_registers = fifo_registers2 + else: + self.wait_mask = 0xFE + self.fifo_registers = fifo_registers1 def init_state_machine(self): self.state_machine = { @@ -178,7 +194,9 @@ class Decoder(srd.Decoder): def _transaction_wait(self, mosi, miso): self.current_transaction.wait_count += 1 if miso == self.end_wait: + self.current_transaction.end_sample_wait = self.es self.state = TransactionState.TRANSFER_DATA + return def _transaction_read(self, mosi, miso): # TPM operation is defined on the 7th bit of the first byte of the transaction (1=read / 0=write) @@ -200,32 +218,48 @@ class Decoder(srd.Decoder): # Get address bytes # Address is 3 bytes long self.current_transaction.address.extend(mosi.to_bytes(1, byteorder='big')) - # The transfer size byte is sent at the same time than the last byte address if self.current_transaction.is_address_complete(): self.current_transaction.end_sample_addr = self.es - self.state = TransactionState.TRANSFER_DATA + if miso == self.wait_mask: + self.state = TransactionState.WAIT + else: + self.state = TransactionState.TRANSFER_DATA return def _transaction_data(self, mosi, miso): self.current_transaction.end_sample_data = self.es - if miso == self.wait_mask: - self.state = TransactionState.WAIT - return if self.current_transaction.operation == Operation.READ: self.current_transaction.data.extend(miso.to_bytes(1, byteorder='big')) self.recover_vmk(miso) elif self.current_transaction.operation == Operation.WRITE: self.current_transaction.data.extend(mosi.to_bytes(1, byteorder='big')) # Check if the transaction is complete - annotation = self.current_transaction.frame() + annotation = self.current_transaction.frame(self.fifo_registers) if annotation: - (op_ss, op_es, op_ann), (addr_ss, addr_es, addr_ann), (data_ss, data_es, data_ann) = annotation - self.put(op_ss, op_es, self.out_ann, + if self.current_transaction.wait_count == 0: + (op_ss, op_es, op_ann), (addr_ss, addr_es, addr_ann), (data_ss, data_es, data_ann) = annotation + self.put(op_ss, op_es, self.out_ann, [Ann.READ if self.current_transaction.operation == Operation.READ else Ann.WRITE, op_ann]) - self.put(addr_ss, addr_es, self.out_ann, [Ann.ADDRESS, addr_ann]) - self.put(data_ss, data_es, self.out_ann, [Ann.DATA, data_ann]) + self.put(addr_ss, addr_es, self.out_ann, [Ann.ADDRESS, addr_ann]) + self.put(data_ss, data_es, self.out_ann, [Ann.DATA, data_ann]) + else: + (op_ss, op_es, op_ann), (addr_ss, addr_es, addr_ann), (wait_ss, wait_es, wait_ann), (data_ss, data_es, data_ann) = annotation + self.put(op_ss, op_es, self.out_ann, + [Ann.READ if self.current_transaction.operation == Operation.READ else Ann.WRITE, op_ann]) + self.put(addr_ss, addr_es, self.out_ann, [Ann.ADDRESS, addr_ann]) + self.put(wait_ss, wait_es, self.out_ann, [Ann.WAIT, wait_ann]) + self.put(data_ss, data_es, self.out_ann, [Ann.DATA, data_ann]) self.end_current_transaction() + def _is_vmk_transaction(self): + try: + if self.fifo_registers[int.from_bytes(self.current_transaction.address, "big") & 0xffff] == "TPM_DATA_FIFO_0": + return True + else: + return False + except KeyError: + return False + def check_vmk_header(self): """ Check for VMK header """ if self.queue[0] == 0x2c: @@ -239,25 +273,29 @@ class Decoder(srd.Decoder): """ Check if VMK is releasing """ if not self.saving_vmk: # Add data to the circular buffer - self.queue.append(miso) - # Add sample number to meta queue - self.vmk_meta["s_queue"].append(self.ss) - # Check if VMK header retrieved - self.check_vmk_header() + # Check if the transaction actually got the VMK. + # Sometimes, other TPM transactions occurs when recovering the VMK + if self._is_vmk_transaction(): + self.queue.append(miso) + # Add sample number to meta queue + self.vmk_meta["s_queue"].append(self.ss) + # Check if VMK header retrieved + self.check_vmk_header() else: if len(self.vmk) == 0: self.vmk_meta["vmk_ss"] = self.ss if len(self.vmk) < 32: - self.vmk.append(miso) - self.vmk_meta["vmk_es"] = self.es + # Check if the transaction actually got the VMK. + # Sometimes, other TPM transactions occurs when recovering the VMK + if self._is_vmk_transaction(): + self.vmk.append(miso) + self.vmk_meta["vmk_es"] = self.es else: self.saving_vmk = False self.put(self.vmk_meta["vmk_ss"], self.vmk_meta["vmk_es"], self.out_ann, [Ann.VMK, ['VMK: {}'.format(''.join('{:02x}'.format(x) for x in self.vmk))]]) - def decode(self, ss, es, data): - self.wait_mask = bytes.fromhex(self.options['wait_mask'].strip("0x")) - + def decode(self, ss, es, data): self.ss, self.es = ss, es ptype, mosi, miso = data