16ea3dfe1SJarkko Sakkinen# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
26ea3dfe1SJarkko Sakkinen
36ea3dfe1SJarkko Sakkinenfrom argparse import ArgumentParser
46ea3dfe1SJarkko Sakkinenfrom argparse import FileType
56ea3dfe1SJarkko Sakkinenimport os
66ea3dfe1SJarkko Sakkinenimport sys
76ea3dfe1SJarkko Sakkinenimport tpm2
86ea3dfe1SJarkko Sakkinenfrom tpm2 import ProtocolError
96ea3dfe1SJarkko Sakkinenimport unittest
106ea3dfe1SJarkko Sakkinenimport logging
116ea3dfe1SJarkko Sakkinenimport struct
126ea3dfe1SJarkko Sakkinen
136ea3dfe1SJarkko Sakkinenclass SmokeTest(unittest.TestCase):
146ea3dfe1SJarkko Sakkinen    def setUp(self):
156ea3dfe1SJarkko Sakkinen        self.client = tpm2.Client()
166ea3dfe1SJarkko Sakkinen        self.root_key = self.client.create_root_key()
176ea3dfe1SJarkko Sakkinen
186ea3dfe1SJarkko Sakkinen    def tearDown(self):
196ea3dfe1SJarkko Sakkinen        self.client.flush_context(self.root_key)
206ea3dfe1SJarkko Sakkinen        self.client.close()
216ea3dfe1SJarkko Sakkinen
226ea3dfe1SJarkko Sakkinen    def test_seal_with_auth(self):
236ea3dfe1SJarkko Sakkinen        data = 'X' * 64
246ea3dfe1SJarkko Sakkinen        auth = 'A' * 15
256ea3dfe1SJarkko Sakkinen
266ea3dfe1SJarkko Sakkinen        blob = self.client.seal(self.root_key, data, auth, None)
276ea3dfe1SJarkko Sakkinen        result = self.client.unseal(self.root_key, blob, auth, None)
286ea3dfe1SJarkko Sakkinen        self.assertEqual(data, result)
296ea3dfe1SJarkko Sakkinen
306ea3dfe1SJarkko Sakkinen    def test_seal_with_policy(self):
316ea3dfe1SJarkko Sakkinen        handle = self.client.start_auth_session(tpm2.TPM2_SE_TRIAL)
326ea3dfe1SJarkko Sakkinen
336ea3dfe1SJarkko Sakkinen        data = 'X' * 64
346ea3dfe1SJarkko Sakkinen        auth = 'A' * 15
356ea3dfe1SJarkko Sakkinen        pcrs = [16]
366ea3dfe1SJarkko Sakkinen
376ea3dfe1SJarkko Sakkinen        try:
386ea3dfe1SJarkko Sakkinen            self.client.policy_pcr(handle, pcrs)
396ea3dfe1SJarkko Sakkinen            self.client.policy_password(handle)
406ea3dfe1SJarkko Sakkinen
416ea3dfe1SJarkko Sakkinen            policy_dig = self.client.get_policy_digest(handle)
426ea3dfe1SJarkko Sakkinen        finally:
436ea3dfe1SJarkko Sakkinen            self.client.flush_context(handle)
446ea3dfe1SJarkko Sakkinen
456ea3dfe1SJarkko Sakkinen        blob = self.client.seal(self.root_key, data, auth, policy_dig)
466ea3dfe1SJarkko Sakkinen
476ea3dfe1SJarkko Sakkinen        handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
486ea3dfe1SJarkko Sakkinen
496ea3dfe1SJarkko Sakkinen        try:
506ea3dfe1SJarkko Sakkinen            self.client.policy_pcr(handle, pcrs)
516ea3dfe1SJarkko Sakkinen            self.client.policy_password(handle)
526ea3dfe1SJarkko Sakkinen
536ea3dfe1SJarkko Sakkinen            result = self.client.unseal(self.root_key, blob, auth, handle)
546ea3dfe1SJarkko Sakkinen        except:
556ea3dfe1SJarkko Sakkinen            self.client.flush_context(handle)
566ea3dfe1SJarkko Sakkinen            raise
576ea3dfe1SJarkko Sakkinen
586ea3dfe1SJarkko Sakkinen        self.assertEqual(data, result)
596ea3dfe1SJarkko Sakkinen
606ea3dfe1SJarkko Sakkinen    def test_unseal_with_wrong_auth(self):
616ea3dfe1SJarkko Sakkinen        data = 'X' * 64
626ea3dfe1SJarkko Sakkinen        auth = 'A' * 20
636ea3dfe1SJarkko Sakkinen        rc = 0
646ea3dfe1SJarkko Sakkinen
656ea3dfe1SJarkko Sakkinen        blob = self.client.seal(self.root_key, data, auth, None)
666ea3dfe1SJarkko Sakkinen        try:
676ea3dfe1SJarkko Sakkinen            result = self.client.unseal(self.root_key, blob, auth[:-1] + 'B', None)
686ea3dfe1SJarkko Sakkinen        except ProtocolError, e:
696ea3dfe1SJarkko Sakkinen            rc = e.rc
706ea3dfe1SJarkko Sakkinen
716ea3dfe1SJarkko Sakkinen        self.assertEqual(rc, tpm2.TPM2_RC_AUTH_FAIL)
726ea3dfe1SJarkko Sakkinen
736ea3dfe1SJarkko Sakkinen    def test_unseal_with_wrong_policy(self):
746ea3dfe1SJarkko Sakkinen        handle = self.client.start_auth_session(tpm2.TPM2_SE_TRIAL)
756ea3dfe1SJarkko Sakkinen
766ea3dfe1SJarkko Sakkinen        data = 'X' * 64
776ea3dfe1SJarkko Sakkinen        auth = 'A' * 17
786ea3dfe1SJarkko Sakkinen        pcrs = [16]
796ea3dfe1SJarkko Sakkinen
806ea3dfe1SJarkko Sakkinen        try:
816ea3dfe1SJarkko Sakkinen            self.client.policy_pcr(handle, pcrs)
826ea3dfe1SJarkko Sakkinen            self.client.policy_password(handle)
836ea3dfe1SJarkko Sakkinen
846ea3dfe1SJarkko Sakkinen            policy_dig = self.client.get_policy_digest(handle)
856ea3dfe1SJarkko Sakkinen        finally:
866ea3dfe1SJarkko Sakkinen            self.client.flush_context(handle)
876ea3dfe1SJarkko Sakkinen
886ea3dfe1SJarkko Sakkinen        blob = self.client.seal(self.root_key, data, auth, policy_dig)
896ea3dfe1SJarkko Sakkinen
906ea3dfe1SJarkko Sakkinen        # Extend first a PCR that is not part of the policy and try to unseal.
916ea3dfe1SJarkko Sakkinen        # This should succeed.
926ea3dfe1SJarkko Sakkinen
936ea3dfe1SJarkko Sakkinen        ds = tpm2.get_digest_size(tpm2.TPM2_ALG_SHA1)
946ea3dfe1SJarkko Sakkinen        self.client.extend_pcr(1, 'X' * ds)
956ea3dfe1SJarkko Sakkinen
966ea3dfe1SJarkko Sakkinen        handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
976ea3dfe1SJarkko Sakkinen
986ea3dfe1SJarkko Sakkinen        try:
996ea3dfe1SJarkko Sakkinen            self.client.policy_pcr(handle, pcrs)
1006ea3dfe1SJarkko Sakkinen            self.client.policy_password(handle)
1016ea3dfe1SJarkko Sakkinen
1026ea3dfe1SJarkko Sakkinen            result = self.client.unseal(self.root_key, blob, auth, handle)
1036ea3dfe1SJarkko Sakkinen        except:
1046ea3dfe1SJarkko Sakkinen            self.client.flush_context(handle)
1056ea3dfe1SJarkko Sakkinen            raise
1066ea3dfe1SJarkko Sakkinen
1076ea3dfe1SJarkko Sakkinen        self.assertEqual(data, result)
1086ea3dfe1SJarkko Sakkinen
1096ea3dfe1SJarkko Sakkinen        # Then, extend a PCR that is part of the policy and try to unseal.
1106ea3dfe1SJarkko Sakkinen        # This should fail.
1116ea3dfe1SJarkko Sakkinen        self.client.extend_pcr(16, 'X' * ds)
1126ea3dfe1SJarkko Sakkinen
1136ea3dfe1SJarkko Sakkinen        handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
1146ea3dfe1SJarkko Sakkinen
1156ea3dfe1SJarkko Sakkinen        rc = 0
1166ea3dfe1SJarkko Sakkinen
1176ea3dfe1SJarkko Sakkinen        try:
1186ea3dfe1SJarkko Sakkinen            self.client.policy_pcr(handle, pcrs)
1196ea3dfe1SJarkko Sakkinen            self.client.policy_password(handle)
1206ea3dfe1SJarkko Sakkinen
1216ea3dfe1SJarkko Sakkinen            result = self.client.unseal(self.root_key, blob, auth, handle)
1226ea3dfe1SJarkko Sakkinen        except ProtocolError, e:
1236ea3dfe1SJarkko Sakkinen            rc = e.rc
1246ea3dfe1SJarkko Sakkinen            self.client.flush_context(handle)
1256ea3dfe1SJarkko Sakkinen        except:
1266ea3dfe1SJarkko Sakkinen            self.client.flush_context(handle)
1276ea3dfe1SJarkko Sakkinen            raise
1286ea3dfe1SJarkko Sakkinen
1296ea3dfe1SJarkko Sakkinen        self.assertEqual(rc, tpm2.TPM2_RC_POLICY_FAIL)
1306ea3dfe1SJarkko Sakkinen
1316ea3dfe1SJarkko Sakkinen    def test_seal_with_too_long_auth(self):
1326ea3dfe1SJarkko Sakkinen        ds = tpm2.get_digest_size(tpm2.TPM2_ALG_SHA1)
1336ea3dfe1SJarkko Sakkinen        data = 'X' * 64
1346ea3dfe1SJarkko Sakkinen        auth = 'A' * (ds + 1)
1356ea3dfe1SJarkko Sakkinen
1366ea3dfe1SJarkko Sakkinen        rc = 0
1376ea3dfe1SJarkko Sakkinen        try:
1386ea3dfe1SJarkko Sakkinen            blob = self.client.seal(self.root_key, data, auth, None)
1396ea3dfe1SJarkko Sakkinen        except ProtocolError, e:
1406ea3dfe1SJarkko Sakkinen            rc = e.rc
1416ea3dfe1SJarkko Sakkinen
1426ea3dfe1SJarkko Sakkinen        self.assertEqual(rc, tpm2.TPM2_RC_SIZE)
1436ea3dfe1SJarkko Sakkinen
1446ea3dfe1SJarkko Sakkinen    def test_too_short_cmd(self):
1456ea3dfe1SJarkko Sakkinen        rejected = False
1466ea3dfe1SJarkko Sakkinen        try:
1476ea3dfe1SJarkko Sakkinen            fmt = '>HIII'
1486ea3dfe1SJarkko Sakkinen            cmd = struct.pack(fmt,
1496ea3dfe1SJarkko Sakkinen                              tpm2.TPM2_ST_NO_SESSIONS,
1506ea3dfe1SJarkko Sakkinen                              struct.calcsize(fmt) + 1,
1516ea3dfe1SJarkko Sakkinen                              tpm2.TPM2_CC_FLUSH_CONTEXT,
1526ea3dfe1SJarkko Sakkinen                              0xDEADBEEF)
1536ea3dfe1SJarkko Sakkinen
1546ea3dfe1SJarkko Sakkinen            self.client.send_cmd(cmd)
1556ea3dfe1SJarkko Sakkinen        except IOError, e:
1566ea3dfe1SJarkko Sakkinen            rejected = True
1576ea3dfe1SJarkko Sakkinen        except:
1586ea3dfe1SJarkko Sakkinen            pass
1596ea3dfe1SJarkko Sakkinen        self.assertEqual(rejected, True)
1606ea3dfe1SJarkko Sakkinen
161f1a0ba6cSTadeusz Struk    def test_read_partial_resp(self):
162f1a0ba6cSTadeusz Struk        try:
163f1a0ba6cSTadeusz Struk            fmt = '>HIIH'
164f1a0ba6cSTadeusz Struk            cmd = struct.pack(fmt,
165f1a0ba6cSTadeusz Struk                              tpm2.TPM2_ST_NO_SESSIONS,
166f1a0ba6cSTadeusz Struk                              struct.calcsize(fmt),
167f1a0ba6cSTadeusz Struk                              tpm2.TPM2_CC_GET_RANDOM,
168f1a0ba6cSTadeusz Struk                              0x20)
169f1a0ba6cSTadeusz Struk            self.client.tpm.write(cmd)
170f1a0ba6cSTadeusz Struk            hdr = self.client.tpm.read(10)
171f1a0ba6cSTadeusz Struk            sz = struct.unpack('>I', hdr[2:6])[0]
172f1a0ba6cSTadeusz Struk            rsp = self.client.tpm.read()
173f1a0ba6cSTadeusz Struk        except:
174f1a0ba6cSTadeusz Struk            pass
175f1a0ba6cSTadeusz Struk        self.assertEqual(sz, 10 + 2 + 32)
176f1a0ba6cSTadeusz Struk        self.assertEqual(len(rsp), 2 + 32)
177f1a0ba6cSTadeusz Struk
178f1a0ba6cSTadeusz Struk    def test_read_partial_overwrite(self):
179f1a0ba6cSTadeusz Struk        try:
180f1a0ba6cSTadeusz Struk            fmt = '>HIIH'
181f1a0ba6cSTadeusz Struk            cmd = struct.pack(fmt,
182f1a0ba6cSTadeusz Struk                              tpm2.TPM2_ST_NO_SESSIONS,
183f1a0ba6cSTadeusz Struk                              struct.calcsize(fmt),
184f1a0ba6cSTadeusz Struk                              tpm2.TPM2_CC_GET_RANDOM,
185f1a0ba6cSTadeusz Struk                              0x20)
186f1a0ba6cSTadeusz Struk            self.client.tpm.write(cmd)
187f1a0ba6cSTadeusz Struk            # Read part of the respone
188f1a0ba6cSTadeusz Struk            rsp1 = self.client.tpm.read(15)
189f1a0ba6cSTadeusz Struk
190f1a0ba6cSTadeusz Struk            # Send a new cmd
191f1a0ba6cSTadeusz Struk            self.client.tpm.write(cmd)
192f1a0ba6cSTadeusz Struk
193f1a0ba6cSTadeusz Struk            # Read the whole respone
194f1a0ba6cSTadeusz Struk            rsp2 = self.client.tpm.read()
195f1a0ba6cSTadeusz Struk        except:
196f1a0ba6cSTadeusz Struk            pass
197f1a0ba6cSTadeusz Struk        self.assertEqual(len(rsp1), 15)
198f1a0ba6cSTadeusz Struk        self.assertEqual(len(rsp2), 10 + 2 + 32)
199f1a0ba6cSTadeusz Struk
200f1a0ba6cSTadeusz Struk    def test_send_two_cmds(self):
201f1a0ba6cSTadeusz Struk        rejected = False
202f1a0ba6cSTadeusz Struk        try:
203f1a0ba6cSTadeusz Struk            fmt = '>HIIH'
204f1a0ba6cSTadeusz Struk            cmd = struct.pack(fmt,
205f1a0ba6cSTadeusz Struk                              tpm2.TPM2_ST_NO_SESSIONS,
206f1a0ba6cSTadeusz Struk                              struct.calcsize(fmt),
207f1a0ba6cSTadeusz Struk                              tpm2.TPM2_CC_GET_RANDOM,
208f1a0ba6cSTadeusz Struk                              0x20)
209f1a0ba6cSTadeusz Struk            self.client.tpm.write(cmd)
210f1a0ba6cSTadeusz Struk
211f1a0ba6cSTadeusz Struk            # expect the second one to raise -EBUSY error
212f1a0ba6cSTadeusz Struk            self.client.tpm.write(cmd)
213f1a0ba6cSTadeusz Struk            rsp = self.client.tpm.read()
214f1a0ba6cSTadeusz Struk
215f1a0ba6cSTadeusz Struk        except IOError, e:
216f1a0ba6cSTadeusz Struk            # read the response
217f1a0ba6cSTadeusz Struk            rsp = self.client.tpm.read()
218f1a0ba6cSTadeusz Struk            rejected = True
219f1a0ba6cSTadeusz Struk            pass
220f1a0ba6cSTadeusz Struk        except:
221f1a0ba6cSTadeusz Struk            pass
222f1a0ba6cSTadeusz Struk        self.assertEqual(rejected, True)
223f1a0ba6cSTadeusz Struk
2246ea3dfe1SJarkko Sakkinenclass SpaceTest(unittest.TestCase):
2256ea3dfe1SJarkko Sakkinen    def setUp(self):
2266ea3dfe1SJarkko Sakkinen        logging.basicConfig(filename='SpaceTest.log', level=logging.DEBUG)
2276ea3dfe1SJarkko Sakkinen
2286ea3dfe1SJarkko Sakkinen    def test_make_two_spaces(self):
2296ea3dfe1SJarkko Sakkinen        log = logging.getLogger(__name__)
2306ea3dfe1SJarkko Sakkinen        log.debug("test_make_two_spaces")
2316ea3dfe1SJarkko Sakkinen
2326ea3dfe1SJarkko Sakkinen        space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
2336ea3dfe1SJarkko Sakkinen        root1 = space1.create_root_key()
2346ea3dfe1SJarkko Sakkinen        space2 = tpm2.Client(tpm2.Client.FLAG_SPACE)
2356ea3dfe1SJarkko Sakkinen        root2 = space2.create_root_key()
2366ea3dfe1SJarkko Sakkinen        root3 = space2.create_root_key()
2376ea3dfe1SJarkko Sakkinen
2386ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (root1))
2396ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (root2))
2406ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (root3))
2416ea3dfe1SJarkko Sakkinen
2426ea3dfe1SJarkko Sakkinen    def test_flush_context(self):
2436ea3dfe1SJarkko Sakkinen        log = logging.getLogger(__name__)
2446ea3dfe1SJarkko Sakkinen        log.debug("test_flush_context")
2456ea3dfe1SJarkko Sakkinen
2466ea3dfe1SJarkko Sakkinen        space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
2476ea3dfe1SJarkko Sakkinen        root1 = space1.create_root_key()
2486ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (root1))
2496ea3dfe1SJarkko Sakkinen
2506ea3dfe1SJarkko Sakkinen        space1.flush_context(root1)
2516ea3dfe1SJarkko Sakkinen
2526ea3dfe1SJarkko Sakkinen    def test_get_handles(self):
2536ea3dfe1SJarkko Sakkinen        log = logging.getLogger(__name__)
2546ea3dfe1SJarkko Sakkinen        log.debug("test_get_handles")
2556ea3dfe1SJarkko Sakkinen
2566ea3dfe1SJarkko Sakkinen        space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
2576ea3dfe1SJarkko Sakkinen        space1.create_root_key()
2586ea3dfe1SJarkko Sakkinen        space2 = tpm2.Client(tpm2.Client.FLAG_SPACE)
2596ea3dfe1SJarkko Sakkinen        space2.create_root_key()
2606ea3dfe1SJarkko Sakkinen        space2.create_root_key()
2616ea3dfe1SJarkko Sakkinen
2626ea3dfe1SJarkko Sakkinen        handles = space2.get_cap(tpm2.TPM2_CAP_HANDLES, tpm2.HR_TRANSIENT)
2636ea3dfe1SJarkko Sakkinen
2646ea3dfe1SJarkko Sakkinen        self.assertEqual(len(handles), 2)
2656ea3dfe1SJarkko Sakkinen
2666ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (handles[0]))
2676ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (handles[1]))
2686ea3dfe1SJarkko Sakkinen
2696ea3dfe1SJarkko Sakkinen    def test_invalid_cc(self):
2706ea3dfe1SJarkko Sakkinen        log = logging.getLogger(__name__)
2716ea3dfe1SJarkko Sakkinen        log.debug(sys._getframe().f_code.co_name)
2726ea3dfe1SJarkko Sakkinen
2736ea3dfe1SJarkko Sakkinen        TPM2_CC_INVALID = tpm2.TPM2_CC_FIRST - 1
2746ea3dfe1SJarkko Sakkinen
2756ea3dfe1SJarkko Sakkinen        space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
2766ea3dfe1SJarkko Sakkinen        root1 = space1.create_root_key()
2776ea3dfe1SJarkko Sakkinen        log.debug("%08x" % (root1))
2786ea3dfe1SJarkko Sakkinen
2796ea3dfe1SJarkko Sakkinen        fmt = '>HII'
2806ea3dfe1SJarkko Sakkinen        cmd = struct.pack(fmt, tpm2.TPM2_ST_NO_SESSIONS, struct.calcsize(fmt),
2816ea3dfe1SJarkko Sakkinen                          TPM2_CC_INVALID)
2826ea3dfe1SJarkko Sakkinen
2836ea3dfe1SJarkko Sakkinen        rc = 0
2846ea3dfe1SJarkko Sakkinen        try:
2856ea3dfe1SJarkko Sakkinen            space1.send_cmd(cmd)
2866ea3dfe1SJarkko Sakkinen        except ProtocolError, e:
2876ea3dfe1SJarkko Sakkinen            rc = e.rc
2886ea3dfe1SJarkko Sakkinen
2896ea3dfe1SJarkko Sakkinen        self.assertEqual(rc, tpm2.TPM2_RC_COMMAND_CODE |
2906ea3dfe1SJarkko Sakkinen                         tpm2.TSS2_RESMGR_TPM_RC_LAYER)
291