blktrace: remove unnessary stop block trace in 'blk_trace_shutdown'
[linux-block.git] / tools / testing / selftests / tpm2 / tpm2.py
1 # SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2
3 import hashlib
4 import os
5 import socket
6 import struct
7 import sys
8 import unittest
9 import fcntl
10 import select
11
12 TPM2_ST_NO_SESSIONS = 0x8001
13 TPM2_ST_SESSIONS = 0x8002
14
15 TPM2_CC_FIRST = 0x01FF
16
17 TPM2_CC_CREATE_PRIMARY = 0x0131
18 TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET = 0x0139
19 TPM2_CC_CREATE = 0x0153
20 TPM2_CC_LOAD = 0x0157
21 TPM2_CC_UNSEAL = 0x015E
22 TPM2_CC_FLUSH_CONTEXT = 0x0165
23 TPM2_CC_START_AUTH_SESSION = 0x0176
24 TPM2_CC_GET_CAPABILITY  = 0x017A
25 TPM2_CC_GET_RANDOM = 0x017B
26 TPM2_CC_PCR_READ = 0x017E
27 TPM2_CC_POLICY_PCR = 0x017F
28 TPM2_CC_PCR_EXTEND = 0x0182
29 TPM2_CC_POLICY_PASSWORD = 0x018C
30 TPM2_CC_POLICY_GET_DIGEST = 0x0189
31
32 TPM2_SE_POLICY = 0x01
33 TPM2_SE_TRIAL = 0x03
34
35 TPM2_ALG_RSA = 0x0001
36 TPM2_ALG_SHA1 = 0x0004
37 TPM2_ALG_AES = 0x0006
38 TPM2_ALG_KEYEDHASH = 0x0008
39 TPM2_ALG_SHA256 = 0x000B
40 TPM2_ALG_NULL = 0x0010
41 TPM2_ALG_CBC = 0x0042
42 TPM2_ALG_CFB = 0x0043
43
44 TPM2_RH_OWNER = 0x40000001
45 TPM2_RH_NULL = 0x40000007
46 TPM2_RH_LOCKOUT = 0x4000000A
47 TPM2_RS_PW = 0x40000009
48
49 TPM2_RC_SIZE            = 0x01D5
50 TPM2_RC_AUTH_FAIL       = 0x098E
51 TPM2_RC_POLICY_FAIL     = 0x099D
52 TPM2_RC_COMMAND_CODE    = 0x0143
53
54 TSS2_RC_LAYER_SHIFT = 16
55 TSS2_RESMGR_TPM_RC_LAYER = (11 << TSS2_RC_LAYER_SHIFT)
56
57 TPM2_CAP_HANDLES = 0x00000001
58 TPM2_CAP_COMMANDS = 0x00000002
59 TPM2_CAP_PCRS = 0x00000005
60 TPM2_CAP_TPM_PROPERTIES = 0x00000006
61
62 TPM2_PT_FIXED = 0x100
63 TPM2_PT_TOTAL_COMMANDS = TPM2_PT_FIXED + 41
64
65 HR_SHIFT = 24
66 HR_LOADED_SESSION = 0x02000000
67 HR_TRANSIENT = 0x80000000
68
69 SHA1_DIGEST_SIZE = 20
70 SHA256_DIGEST_SIZE = 32
71
72 TPM2_VER0_ERRORS = {
73     0x000: "TPM_RC_SUCCESS",
74     0x030: "TPM_RC_BAD_TAG",
75 }
76
77 TPM2_VER1_ERRORS = {
78     0x000: "TPM_RC_FAILURE",
79     0x001: "TPM_RC_FAILURE",
80     0x003: "TPM_RC_SEQUENCE",
81     0x00B: "TPM_RC_PRIVATE",
82     0x019: "TPM_RC_HMAC",
83     0x020: "TPM_RC_DISABLED",
84     0x021: "TPM_RC_EXCLUSIVE",
85     0x024: "TPM_RC_AUTH_TYPE",
86     0x025: "TPM_RC_AUTH_MISSING",
87     0x026: "TPM_RC_POLICY",
88     0x027: "TPM_RC_PCR",
89     0x028: "TPM_RC_PCR_CHANGED",
90     0x02D: "TPM_RC_UPGRADE",
91     0x02E: "TPM_RC_TOO_MANY_CONTEXTS",
92     0x02F: "TPM_RC_AUTH_UNAVAILABLE",
93     0x030: "TPM_RC_REBOOT",
94     0x031: "TPM_RC_UNBALANCED",
95     0x042: "TPM_RC_COMMAND_SIZE",
96     0x043: "TPM_RC_COMMAND_CODE",
97     0x044: "TPM_RC_AUTHSIZE",
98     0x045: "TPM_RC_AUTH_CONTEXT",
99     0x046: "TPM_RC_NV_RANGE",
100     0x047: "TPM_RC_NV_SIZE",
101     0x048: "TPM_RC_NV_LOCKED",
102     0x049: "TPM_RC_NV_AUTHORIZATION",
103     0x04A: "TPM_RC_NV_UNINITIALIZED",
104     0x04B: "TPM_RC_NV_SPACE",
105     0x04C: "TPM_RC_NV_DEFINED",
106     0x050: "TPM_RC_BAD_CONTEXT",
107     0x051: "TPM_RC_CPHASH",
108     0x052: "TPM_RC_PARENT",
109     0x053: "TPM_RC_NEEDS_TEST",
110     0x054: "TPM_RC_NO_RESULT",
111     0x055: "TPM_RC_SENSITIVE",
112     0x07F: "RC_MAX_FM0",
113 }
114
115 TPM2_FMT1_ERRORS = {
116     0x001: "TPM_RC_ASYMMETRIC",
117     0x002: "TPM_RC_ATTRIBUTES",
118     0x003: "TPM_RC_HASH",
119     0x004: "TPM_RC_VALUE",
120     0x005: "TPM_RC_HIERARCHY",
121     0x007: "TPM_RC_KEY_SIZE",
122     0x008: "TPM_RC_MGF",
123     0x009: "TPM_RC_MODE",
124     0x00A: "TPM_RC_TYPE",
125     0x00B: "TPM_RC_HANDLE",
126     0x00C: "TPM_RC_KDF",
127     0x00D: "TPM_RC_RANGE",
128     0x00E: "TPM_RC_AUTH_FAIL",
129     0x00F: "TPM_RC_NONCE",
130     0x010: "TPM_RC_PP",
131     0x012: "TPM_RC_SCHEME",
132     0x015: "TPM_RC_SIZE",
133     0x016: "TPM_RC_SYMMETRIC",
134     0x017: "TPM_RC_TAG",
135     0x018: "TPM_RC_SELECTOR",
136     0x01A: "TPM_RC_INSUFFICIENT",
137     0x01B: "TPM_RC_SIGNATURE",
138     0x01C: "TPM_RC_KEY",
139     0x01D: "TPM_RC_POLICY_FAIL",
140     0x01F: "TPM_RC_INTEGRITY",
141     0x020: "TPM_RC_TICKET",
142     0x021: "TPM_RC_RESERVED_BITS",
143     0x022: "TPM_RC_BAD_AUTH",
144     0x023: "TPM_RC_EXPIRED",
145     0x024: "TPM_RC_POLICY_CC",
146     0x025: "TPM_RC_BINDING",
147     0x026: "TPM_RC_CURVE",
148     0x027: "TPM_RC_ECC_POINT",
149 }
150
151 TPM2_WARN_ERRORS = {
152     0x001: "TPM_RC_CONTEXT_GAP",
153     0x002: "TPM_RC_OBJECT_MEMORY",
154     0x003: "TPM_RC_SESSION_MEMORY",
155     0x004: "TPM_RC_MEMORY",
156     0x005: "TPM_RC_SESSION_HANDLES",
157     0x006: "TPM_RC_OBJECT_HANDLES",
158     0x007: "TPM_RC_LOCALITY",
159     0x008: "TPM_RC_YIELDED",
160     0x009: "TPM_RC_CANCELED",
161     0x00A: "TPM_RC_TESTING",
162     0x010: "TPM_RC_REFERENCE_H0",
163     0x011: "TPM_RC_REFERENCE_H1",
164     0x012: "TPM_RC_REFERENCE_H2",
165     0x013: "TPM_RC_REFERENCE_H3",
166     0x014: "TPM_RC_REFERENCE_H4",
167     0x015: "TPM_RC_REFERENCE_H5",
168     0x016: "TPM_RC_REFERENCE_H6",
169     0x018: "TPM_RC_REFERENCE_S0",
170     0x019: "TPM_RC_REFERENCE_S1",
171     0x01A: "TPM_RC_REFERENCE_S2",
172     0x01B: "TPM_RC_REFERENCE_S3",
173     0x01C: "TPM_RC_REFERENCE_S4",
174     0x01D: "TPM_RC_REFERENCE_S5",
175     0x01E: "TPM_RC_REFERENCE_S6",
176     0x020: "TPM_RC_NV_RATE",
177     0x021: "TPM_RC_LOCKOUT",
178     0x022: "TPM_RC_RETRY",
179     0x023: "TPM_RC_NV_UNAVAILABLE",
180     0x7F: "TPM_RC_NOT_USED",
181 }
182
183 RC_VER1 = 0x100
184 RC_FMT1 = 0x080
185 RC_WARN = 0x900
186
187 ALG_DIGEST_SIZE_MAP = {
188     TPM2_ALG_SHA1: SHA1_DIGEST_SIZE,
189     TPM2_ALG_SHA256: SHA256_DIGEST_SIZE,
190 }
191
192 ALG_HASH_FUNCTION_MAP = {
193     TPM2_ALG_SHA1: hashlib.sha1,
194     TPM2_ALG_SHA256: hashlib.sha256
195 }
196
197 NAME_ALG_MAP = {
198     "sha1": TPM2_ALG_SHA1,
199     "sha256": TPM2_ALG_SHA256,
200 }
201
202
203 class UnknownAlgorithmIdError(Exception):
204     def __init__(self, alg):
205         self.alg = alg
206
207     def __str__(self):
208         return '0x%0x' % (alg)
209
210
211 class UnknownAlgorithmNameError(Exception):
212     def __init__(self, name):
213         self.name = name
214
215     def __str__(self):
216         return name
217
218
219 class UnknownPCRBankError(Exception):
220     def __init__(self, alg):
221         self.alg = alg
222
223     def __str__(self):
224         return '0x%0x' % (alg)
225
226
227 class ProtocolError(Exception):
228     def __init__(self, cc, rc):
229         self.cc = cc
230         self.rc = rc
231
232         if (rc & RC_FMT1) == RC_FMT1:
233             self.name = TPM2_FMT1_ERRORS.get(rc & 0x3f, "TPM_RC_UNKNOWN")
234         elif (rc & RC_WARN) == RC_WARN:
235             self.name = TPM2_WARN_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN")
236         elif (rc & RC_VER1) == RC_VER1:
237             self.name = TPM2_VER1_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN")
238         else:
239             self.name = TPM2_VER0_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN")
240
241     def __str__(self):
242         if self.cc:
243             return '%s: cc=0x%08x, rc=0x%08x' % (self.name, self.cc, self.rc)
244         else:
245             return '%s: rc=0x%08x' % (self.name, self.rc)
246
247
248 class AuthCommand(object):
249     """TPMS_AUTH_COMMAND"""
250
251     def __init__(self, session_handle=TPM2_RS_PW, nonce=bytes(),
252                  session_attributes=0, hmac=bytes()):
253         self.session_handle = session_handle
254         self.nonce = nonce
255         self.session_attributes = session_attributes
256         self.hmac = hmac
257
258     def __bytes__(self):
259         fmt = '>I H%us B H%us' % (len(self.nonce), len(self.hmac))
260         return struct.pack(fmt, self.session_handle, len(self.nonce),
261                            self.nonce, self.session_attributes, len(self.hmac),
262                            self.hmac)
263
264     def __len__(self):
265         fmt = '>I H%us B H%us' % (len(self.nonce), len(self.hmac))
266         return struct.calcsize(fmt)
267
268
269 class SensitiveCreate(object):
270     """TPMS_SENSITIVE_CREATE"""
271
272     def __init__(self, user_auth=bytes(), data=bytes()):
273         self.user_auth = user_auth
274         self.data = data
275
276     def __bytes__(self):
277         fmt = '>H%us H%us' % (len(self.user_auth), len(self.data))
278         return struct.pack(fmt, len(self.user_auth), self.user_auth,
279                            len(self.data), self.data)
280
281     def __len__(self):
282         fmt = '>H%us H%us' % (len(self.user_auth), len(self.data))
283         return struct.calcsize(fmt)
284
285
286 class Public(object):
287     """TPMT_PUBLIC"""
288
289     FIXED_TPM = (1 << 1)
290     FIXED_PARENT = (1 << 4)
291     SENSITIVE_DATA_ORIGIN = (1 << 5)
292     USER_WITH_AUTH = (1 << 6)
293     RESTRICTED = (1 << 16)
294     DECRYPT = (1 << 17)
295
296     def __fmt(self):
297         return '>HHIH%us%usH%us' % \
298             (len(self.auth_policy), len(self.parameters), len(self.unique))
299
300     def __init__(self, object_type, name_alg, object_attributes,
301                  auth_policy=bytes(), parameters=bytes(),
302                  unique=bytes()):
303         self.object_type = object_type
304         self.name_alg = name_alg
305         self.object_attributes = object_attributes
306         self.auth_policy = auth_policy
307         self.parameters = parameters
308         self.unique = unique
309
310     def __bytes__(self):
311         return struct.pack(self.__fmt(),
312                            self.object_type,
313                            self.name_alg,
314                            self.object_attributes,
315                            len(self.auth_policy),
316                            self.auth_policy,
317                            self.parameters,
318                            len(self.unique),
319                            self.unique)
320
321     def __len__(self):
322         return struct.calcsize(self.__fmt())
323
324
325 def get_digest_size(alg):
326     ds = ALG_DIGEST_SIZE_MAP.get(alg)
327     if not ds:
328         raise UnknownAlgorithmIdError(alg)
329     return ds
330
331
332 def get_hash_function(alg):
333     f = ALG_HASH_FUNCTION_MAP.get(alg)
334     if not f:
335         raise UnknownAlgorithmIdError(alg)
336     return f
337
338
339 def get_algorithm(name):
340     alg = NAME_ALG_MAP.get(name)
341     if not alg:
342         raise UnknownAlgorithmNameError(name)
343     return alg
344
345
346 def hex_dump(d):
347     d = [format(ord(x), '02x') for x in d]
348     d = [d[i: i + 16] for i in range(0, len(d), 16)]
349     d = [' '.join(x) for x in d]
350     d = os.linesep.join(d)
351
352     return d
353
354 class Client:
355     FLAG_DEBUG = 0x01
356     FLAG_SPACE = 0x02
357     FLAG_NONBLOCK = 0x04
358     TPM_IOC_NEW_SPACE = 0xa200
359
360     def __init__(self, flags = 0):
361         self.flags = flags
362
363         if (self.flags & Client.FLAG_SPACE) == 0:
364             self.tpm = open('/dev/tpm0', 'r+b', buffering=0)
365         else:
366             self.tpm = open('/dev/tpmrm0', 'r+b', buffering=0)
367
368         if (self.flags & Client.FLAG_NONBLOCK):
369             flags = fcntl.fcntl(self.tpm, fcntl.F_GETFL)
370             flags |= os.O_NONBLOCK
371             fcntl.fcntl(self.tpm, fcntl.F_SETFL, flags)
372             self.tpm_poll = select.poll()
373
374     def close(self):
375         self.tpm.close()
376
377     def send_cmd(self, cmd):
378         self.tpm.write(cmd)
379
380         if (self.flags & Client.FLAG_NONBLOCK):
381             self.tpm_poll.register(self.tpm, select.POLLIN)
382             self.tpm_poll.poll(10000)
383
384         rsp = self.tpm.read()
385
386         if (self.flags & Client.FLAG_NONBLOCK):
387             self.tpm_poll.unregister(self.tpm)
388
389         if (self.flags & Client.FLAG_DEBUG) != 0:
390             sys.stderr.write('cmd' + os.linesep)
391             sys.stderr.write(hex_dump(cmd) + os.linesep)
392             sys.stderr.write('rsp' + os.linesep)
393             sys.stderr.write(hex_dump(rsp) + os.linesep)
394
395         rc = struct.unpack('>I', rsp[6:10])[0]
396         if rc != 0:
397             cc = struct.unpack('>I', cmd[6:10])[0]
398             raise ProtocolError(cc, rc)
399
400         return rsp
401
402     def read_pcr(self, i, bank_alg = TPM2_ALG_SHA1):
403         pcrsel_len = max((i >> 3) + 1, 3)
404         pcrsel = [0] * pcrsel_len
405         pcrsel[i >> 3] = 1 << (i & 7)
406         pcrsel = ''.join(map(chr, pcrsel)).encode()
407
408         fmt = '>HII IHB%us' % (pcrsel_len)
409         cmd = struct.pack(fmt,
410                           TPM2_ST_NO_SESSIONS,
411                           struct.calcsize(fmt),
412                           TPM2_CC_PCR_READ,
413                           1,
414                           bank_alg,
415                           pcrsel_len, pcrsel)
416
417         rsp = self.send_cmd(cmd)
418
419         pcr_update_cnt, pcr_select_cnt = struct.unpack('>II', rsp[10:18])
420         assert pcr_select_cnt == 1
421         rsp = rsp[18:]
422
423         alg2, pcrsel_len2 = struct.unpack('>HB', rsp[:3])
424         assert bank_alg == alg2 and pcrsel_len == pcrsel_len2
425         rsp = rsp[3 + pcrsel_len:]
426
427         digest_cnt = struct.unpack('>I', rsp[:4])[0]
428         if digest_cnt == 0:
429             return None
430         rsp = rsp[6:]
431
432         return rsp
433
434     def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1):
435         ds = get_digest_size(bank_alg)
436         assert(ds == len(dig))
437
438         auth_cmd = AuthCommand()
439
440         fmt = '>HII I I%us IH%us' % (len(auth_cmd), ds)
441         cmd = struct.pack(
442             fmt,
443             TPM2_ST_SESSIONS,
444             struct.calcsize(fmt),
445             TPM2_CC_PCR_EXTEND,
446             i,
447             len(auth_cmd),
448             bytes(auth_cmd),
449             1, bank_alg, dig)
450
451         self.send_cmd(cmd)
452
453     def start_auth_session(self, session_type, name_alg = TPM2_ALG_SHA1):
454         fmt = '>HII IIH16sHBHH'
455         cmd = struct.pack(fmt,
456                           TPM2_ST_NO_SESSIONS,
457                           struct.calcsize(fmt),
458                           TPM2_CC_START_AUTH_SESSION,
459                           TPM2_RH_NULL,
460                           TPM2_RH_NULL,
461                           16,
462                           ('\0' * 16).encode(),
463                           0,
464                           session_type,
465                           TPM2_ALG_NULL,
466                           name_alg)
467
468         return struct.unpack('>I', self.send_cmd(cmd)[10:14])[0]
469
470     def __calc_pcr_digest(self, pcrs, bank_alg = TPM2_ALG_SHA1,
471                           digest_alg = TPM2_ALG_SHA1):
472         x = []
473         f = get_hash_function(digest_alg)
474
475         for i in pcrs:
476             pcr = self.read_pcr(i, bank_alg)
477             if pcr is None:
478                 return None
479             x += pcr
480
481         return f(bytearray(x)).digest()
482
483     def policy_pcr(self, handle, pcrs, bank_alg = TPM2_ALG_SHA1,
484                    name_alg = TPM2_ALG_SHA1):
485         ds = get_digest_size(name_alg)
486         dig = self.__calc_pcr_digest(pcrs, bank_alg, name_alg)
487         if not dig:
488             raise UnknownPCRBankError(bank_alg)
489
490         pcrsel_len = max((max(pcrs) >> 3) + 1, 3)
491         pcrsel = [0] * pcrsel_len
492         for i in pcrs:
493             pcrsel[i >> 3] |= 1 << (i & 7)
494         pcrsel = ''.join(map(chr, pcrsel)).encode()
495
496         fmt = '>HII IH%usIHB3s' % ds
497         cmd = struct.pack(fmt,
498                           TPM2_ST_NO_SESSIONS,
499                           struct.calcsize(fmt),
500                           TPM2_CC_POLICY_PCR,
501                           handle,
502                           len(dig),
503                           bytes(dig),
504                           1,
505                           bank_alg,
506                           pcrsel_len, pcrsel)
507
508         self.send_cmd(cmd)
509
510     def policy_password(self, handle):
511         fmt = '>HII I'
512         cmd = struct.pack(fmt,
513                           TPM2_ST_NO_SESSIONS,
514                           struct.calcsize(fmt),
515                           TPM2_CC_POLICY_PASSWORD,
516                           handle)
517
518         self.send_cmd(cmd)
519
520     def get_policy_digest(self, handle):
521         fmt = '>HII I'
522         cmd = struct.pack(fmt,
523                           TPM2_ST_NO_SESSIONS,
524                           struct.calcsize(fmt),
525                           TPM2_CC_POLICY_GET_DIGEST,
526                           handle)
527
528         return self.send_cmd(cmd)[12:]
529
530     def flush_context(self, handle):
531         fmt = '>HIII'
532         cmd = struct.pack(fmt,
533                           TPM2_ST_NO_SESSIONS,
534                           struct.calcsize(fmt),
535                           TPM2_CC_FLUSH_CONTEXT,
536                           handle)
537
538         self.send_cmd(cmd)
539
540     def create_root_key(self, auth_value = bytes()):
541         attributes = \
542             Public.FIXED_TPM | \
543             Public.FIXED_PARENT | \
544             Public.SENSITIVE_DATA_ORIGIN | \
545             Public.USER_WITH_AUTH | \
546             Public.RESTRICTED | \
547             Public.DECRYPT
548
549         auth_cmd = AuthCommand()
550         sensitive = SensitiveCreate(user_auth=auth_value)
551
552         public_parms = struct.pack(
553             '>HHHHHI',
554             TPM2_ALG_AES,
555             128,
556             TPM2_ALG_CFB,
557             TPM2_ALG_NULL,
558             2048,
559             0)
560
561         public = Public(
562             object_type=TPM2_ALG_RSA,
563             name_alg=TPM2_ALG_SHA1,
564             object_attributes=attributes,
565             parameters=public_parms)
566
567         fmt = '>HIII I%us H%us H%us HI' % \
568             (len(auth_cmd), len(sensitive), len(public))
569         cmd = struct.pack(
570             fmt,
571             TPM2_ST_SESSIONS,
572             struct.calcsize(fmt),
573             TPM2_CC_CREATE_PRIMARY,
574             TPM2_RH_OWNER,
575             len(auth_cmd),
576             bytes(auth_cmd),
577             len(sensitive),
578             bytes(sensitive),
579             len(public),
580             bytes(public),
581             0, 0)
582
583         return struct.unpack('>I', self.send_cmd(cmd)[10:14])[0]
584
585     def seal(self, parent_key, data, auth_value, policy_dig,
586              name_alg = TPM2_ALG_SHA1):
587         ds = get_digest_size(name_alg)
588         assert(not policy_dig or ds == len(policy_dig))
589
590         attributes = 0
591         if not policy_dig:
592             attributes |= Public.USER_WITH_AUTH
593             policy_dig = bytes()
594
595         auth_cmd =  AuthCommand()
596         sensitive = SensitiveCreate(user_auth=auth_value, data=data)
597
598         public = Public(
599             object_type=TPM2_ALG_KEYEDHASH,
600             name_alg=name_alg,
601             object_attributes=attributes,
602             auth_policy=policy_dig,
603             parameters=struct.pack('>H', TPM2_ALG_NULL))
604
605         fmt = '>HIII I%us H%us H%us HI' % \
606             (len(auth_cmd), len(sensitive), len(public))
607         cmd = struct.pack(
608             fmt,
609             TPM2_ST_SESSIONS,
610             struct.calcsize(fmt),
611             TPM2_CC_CREATE,
612             parent_key,
613             len(auth_cmd),
614             bytes(auth_cmd),
615             len(sensitive),
616             bytes(sensitive),
617             len(public),
618             bytes(public),
619             0, 0)
620
621         rsp = self.send_cmd(cmd)
622
623         return rsp[14:]
624
625     def unseal(self, parent_key, blob, auth_value, policy_handle):
626         private_len = struct.unpack('>H', blob[0:2])[0]
627         public_start = private_len + 2
628         public_len = struct.unpack('>H', blob[public_start:public_start + 2])[0]
629         blob = blob[:private_len + public_len + 4]
630
631         auth_cmd = AuthCommand()
632
633         fmt = '>HII I I%us %us' % (len(auth_cmd), len(blob))
634         cmd = struct.pack(
635             fmt,
636             TPM2_ST_SESSIONS,
637             struct.calcsize(fmt),
638             TPM2_CC_LOAD,
639             parent_key,
640             len(auth_cmd),
641             bytes(auth_cmd),
642             blob)
643
644         data_handle = struct.unpack('>I', self.send_cmd(cmd)[10:14])[0]
645
646         if policy_handle:
647             auth_cmd = AuthCommand(session_handle=policy_handle, hmac=auth_value)
648         else:
649             auth_cmd = AuthCommand(hmac=auth_value)
650
651         fmt = '>HII I I%us' % (len(auth_cmd))
652         cmd = struct.pack(
653             fmt,
654             TPM2_ST_SESSIONS,
655             struct.calcsize(fmt),
656             TPM2_CC_UNSEAL,
657             data_handle,
658             len(auth_cmd),
659             bytes(auth_cmd))
660
661         try:
662             rsp = self.send_cmd(cmd)
663         finally:
664             self.flush_context(data_handle)
665
666         data_len = struct.unpack('>I', rsp[10:14])[0] - 2
667
668         return rsp[16:16 + data_len]
669
670     def reset_da_lock(self):
671         auth_cmd = AuthCommand()
672
673         fmt = '>HII I I%us' % (len(auth_cmd))
674         cmd = struct.pack(
675             fmt,
676             TPM2_ST_SESSIONS,
677             struct.calcsize(fmt),
678             TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET,
679             TPM2_RH_LOCKOUT,
680             len(auth_cmd),
681             bytes(auth_cmd))
682
683         self.send_cmd(cmd)
684
685     def __get_cap_cnt(self, cap, pt, cnt):
686         handles = []
687         fmt = '>HII III'
688
689         cmd = struct.pack(fmt,
690                           TPM2_ST_NO_SESSIONS,
691                           struct.calcsize(fmt),
692                           TPM2_CC_GET_CAPABILITY,
693                           cap, pt, cnt)
694
695         rsp = self.send_cmd(cmd)[10:]
696         more_data, cap, cnt = struct.unpack('>BII', rsp[:9])
697         rsp = rsp[9:]
698
699         for i in range(0, cnt):
700             handle = struct.unpack('>I', rsp[:4])[0]
701             handles.append(handle)
702             rsp = rsp[4:]
703
704         return handles, more_data
705
706     def get_cap(self, cap, pt):
707         handles = []
708
709         more_data = True
710         while more_data:
711             next_handles, more_data = self.__get_cap_cnt(cap, pt, 1)
712             handles += next_handles
713             pt += 1
714
715         return handles
716
717     def get_cap_pcrs(self):
718         pcr_banks = {}
719
720         fmt = '>HII III'
721
722         cmd = struct.pack(fmt,
723                           TPM2_ST_NO_SESSIONS,
724                           struct.calcsize(fmt),
725                           TPM2_CC_GET_CAPABILITY,
726                           TPM2_CAP_PCRS, 0, 1)
727         rsp = self.send_cmd(cmd)[10:]
728         _, _, cnt = struct.unpack('>BII', rsp[:9])
729         rsp = rsp[9:]
730
731         # items are TPMS_PCR_SELECTION's
732         for i in range(0, cnt):
733               hash, sizeOfSelect = struct.unpack('>HB', rsp[:3])
734               rsp = rsp[3:]
735
736               pcrSelect = 0
737               if sizeOfSelect > 0:
738                   pcrSelect, = struct.unpack('%ds' % sizeOfSelect,
739                                              rsp[:sizeOfSelect])
740                   rsp = rsp[sizeOfSelect:]
741                   pcrSelect = int.from_bytes(pcrSelect, byteorder='big')
742
743               pcr_banks[hash] = pcrSelect
744
745         return pcr_banks