1 # SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
12 TPM2_ST_NO_SESSIONS
= 0x8001
13 TPM2_ST_SESSIONS
= 0x8002
15 TPM2_CC_FIRST
= 0x01FF
17 TPM2_CC_CREATE_PRIMARY
= 0x0131
18 TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET
= 0x0139
19 TPM2_CC_CREATE
= 0x0153
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
36 TPM2_ALG_SHA1
= 0x0004
38 TPM2_ALG_KEYEDHASH
= 0x0008
39 TPM2_ALG_SHA256
= 0x000B
40 TPM2_ALG_NULL
= 0x0010
44 TPM2_RH_OWNER
= 0x40000001
45 TPM2_RH_NULL
= 0x40000007
46 TPM2_RH_LOCKOUT
= 0x4000000A
47 TPM2_RS_PW
= 0x40000009
50 TPM2_RC_AUTH_FAIL
= 0x098E
51 TPM2_RC_POLICY_FAIL
= 0x099D
52 TPM2_RC_COMMAND_CODE
= 0x0143
54 TSS2_RC_LAYER_SHIFT
= 16
55 TSS2_RESMGR_TPM_RC_LAYER
= (11 << TSS2_RC_LAYER_SHIFT
)
57 TPM2_CAP_HANDLES
= 0x00000001
58 TPM2_CAP_COMMANDS
= 0x00000002
59 TPM2_CAP_TPM_PROPERTIES
= 0x00000006
62 TPM2_PT_TOTAL_COMMANDS
= TPM2_PT_FIXED
+ 41
65 HR_LOADED_SESSION
= 0x02000000
66 HR_TRANSIENT
= 0x80000000
69 SHA256_DIGEST_SIZE
= 32
72 0x000: "TPM_RC_SUCCESS",
73 0x030: "TPM_RC_BAD_TAG",
77 0x000: "TPM_RC_FAILURE",
78 0x001: "TPM_RC_FAILURE",
79 0x003: "TPM_RC_SEQUENCE",
80 0x00B: "TPM_RC_PRIVATE",
82 0x020: "TPM_RC_DISABLED",
83 0x021: "TPM_RC_EXCLUSIVE",
84 0x024: "TPM_RC_AUTH_TYPE",
85 0x025: "TPM_RC_AUTH_MISSING",
86 0x026: "TPM_RC_POLICY",
88 0x028: "TPM_RC_PCR_CHANGED",
89 0x02D: "TPM_RC_UPGRADE",
90 0x02E: "TPM_RC_TOO_MANY_CONTEXTS",
91 0x02F: "TPM_RC_AUTH_UNAVAILABLE",
92 0x030: "TPM_RC_REBOOT",
93 0x031: "TPM_RC_UNBALANCED",
94 0x042: "TPM_RC_COMMAND_SIZE",
95 0x043: "TPM_RC_COMMAND_CODE",
96 0x044: "TPM_RC_AUTHSIZE",
97 0x045: "TPM_RC_AUTH_CONTEXT",
98 0x046: "TPM_RC_NV_RANGE",
99 0x047: "TPM_RC_NV_SIZE",
100 0x048: "TPM_RC_NV_LOCKED",
101 0x049: "TPM_RC_NV_AUTHORIZATION",
102 0x04A: "TPM_RC_NV_UNINITIALIZED",
103 0x04B: "TPM_RC_NV_SPACE",
104 0x04C: "TPM_RC_NV_DEFINED",
105 0x050: "TPM_RC_BAD_CONTEXT",
106 0x051: "TPM_RC_CPHASH",
107 0x052: "TPM_RC_PARENT",
108 0x053: "TPM_RC_NEEDS_TEST",
109 0x054: "TPM_RC_NO_RESULT",
110 0x055: "TPM_RC_SENSITIVE",
115 0x001: "TPM_RC_ASYMMETRIC",
116 0x002: "TPM_RC_ATTRIBUTES",
117 0x003: "TPM_RC_HASH",
118 0x004: "TPM_RC_VALUE",
119 0x005: "TPM_RC_HIERARCHY",
120 0x007: "TPM_RC_KEY_SIZE",
122 0x009: "TPM_RC_MODE",
123 0x00A: "TPM_RC_TYPE",
124 0x00B: "TPM_RC_HANDLE",
126 0x00D: "TPM_RC_RANGE",
127 0x00E: "TPM_RC_AUTH_FAIL",
128 0x00F: "TPM_RC_NONCE",
130 0x012: "TPM_RC_SCHEME",
131 0x015: "TPM_RC_SIZE",
132 0x016: "TPM_RC_SYMMETRIC",
134 0x018: "TPM_RC_SELECTOR",
135 0x01A: "TPM_RC_INSUFFICIENT",
136 0x01B: "TPM_RC_SIGNATURE",
138 0x01D: "TPM_RC_POLICY_FAIL",
139 0x01F: "TPM_RC_INTEGRITY",
140 0x020: "TPM_RC_TICKET",
141 0x021: "TPM_RC_RESERVED_BITS",
142 0x022: "TPM_RC_BAD_AUTH",
143 0x023: "TPM_RC_EXPIRED",
144 0x024: "TPM_RC_POLICY_CC",
145 0x025: "TPM_RC_BINDING",
146 0x026: "TPM_RC_CURVE",
147 0x027: "TPM_RC_ECC_POINT",
151 0x001: "TPM_RC_CONTEXT_GAP",
152 0x002: "TPM_RC_OBJECT_MEMORY",
153 0x003: "TPM_RC_SESSION_MEMORY",
154 0x004: "TPM_RC_MEMORY",
155 0x005: "TPM_RC_SESSION_HANDLES",
156 0x006: "TPM_RC_OBJECT_HANDLES",
157 0x007: "TPM_RC_LOCALITY",
158 0x008: "TPM_RC_YIELDED",
159 0x009: "TPM_RC_CANCELED",
160 0x00A: "TPM_RC_TESTING",
161 0x010: "TPM_RC_REFERENCE_H0",
162 0x011: "TPM_RC_REFERENCE_H1",
163 0x012: "TPM_RC_REFERENCE_H2",
164 0x013: "TPM_RC_REFERENCE_H3",
165 0x014: "TPM_RC_REFERENCE_H4",
166 0x015: "TPM_RC_REFERENCE_H5",
167 0x016: "TPM_RC_REFERENCE_H6",
168 0x018: "TPM_RC_REFERENCE_S0",
169 0x019: "TPM_RC_REFERENCE_S1",
170 0x01A: "TPM_RC_REFERENCE_S2",
171 0x01B: "TPM_RC_REFERENCE_S3",
172 0x01C: "TPM_RC_REFERENCE_S4",
173 0x01D: "TPM_RC_REFERENCE_S5",
174 0x01E: "TPM_RC_REFERENCE_S6",
175 0x020: "TPM_RC_NV_RATE",
176 0x021: "TPM_RC_LOCKOUT",
177 0x022: "TPM_RC_RETRY",
178 0x023: "TPM_RC_NV_UNAVAILABLE",
179 0x7F: "TPM_RC_NOT_USED",
186 ALG_DIGEST_SIZE_MAP
= {
187 TPM2_ALG_SHA1
: SHA1_DIGEST_SIZE
,
188 TPM2_ALG_SHA256
: SHA256_DIGEST_SIZE
,
191 ALG_HASH_FUNCTION_MAP
= {
192 TPM2_ALG_SHA1
: hashlib
.sha1
,
193 TPM2_ALG_SHA256
: hashlib
.sha256
197 "sha1": TPM2_ALG_SHA1
,
198 "sha256": TPM2_ALG_SHA256
,
202 class UnknownAlgorithmIdError(Exception):
203 def __init__(self
, alg
):
207 return '0x%0x' % (alg
)
210 class UnknownAlgorithmNameError(Exception):
211 def __init__(self
, name
):
218 class UnknownPCRBankError(Exception):
219 def __init__(self
, alg
):
223 return '0x%0x' % (alg
)
226 class ProtocolError(Exception):
227 def __init__(self
, cc
, rc
):
231 if (rc
& RC_FMT1
) == RC_FMT1
:
232 self
.name
= TPM2_FMT1_ERRORS
.get(rc
& 0x3f, "TPM_RC_UNKNOWN")
233 elif (rc
& RC_WARN
) == RC_WARN
:
234 self
.name
= TPM2_WARN_ERRORS
.get(rc
& 0x7f, "TPM_RC_UNKNOWN")
235 elif (rc
& RC_VER1
) == RC_VER1
:
236 self
.name
= TPM2_VER1_ERRORS
.get(rc
& 0x7f, "TPM_RC_UNKNOWN")
238 self
.name
= TPM2_VER0_ERRORS
.get(rc
& 0x7f, "TPM_RC_UNKNOWN")
242 return '%s: cc=0x%08x, rc=0x%08x' % (self
.name
, self
.cc
, self
.rc
)
244 return '%s: rc=0x%08x' % (self
.name
, self
.rc
)
247 class AuthCommand(object):
248 """TPMS_AUTH_COMMAND"""
250 def __init__(self
, session_handle
=TPM2_RS_PW
, nonce
='', session_attributes
=0,
252 self
.session_handle
= session_handle
254 self
.session_attributes
= session_attributes
258 fmt
= '>I H%us B H%us' % (len(self
.nonce
), len(self
.hmac
))
259 return struct
.pack(fmt
, self
.session_handle
, len(self
.nonce
),
260 self
.nonce
, self
.session_attributes
, len(self
.hmac
),
264 fmt
= '>I H%us B H%us' % (len(self
.nonce
), len(self
.hmac
))
265 return struct
.calcsize(fmt
)
268 class SensitiveCreate(object):
269 """TPMS_SENSITIVE_CREATE"""
271 def __init__(self
, user_auth
='', data
=''):
272 self
.user_auth
= user_auth
276 fmt
= '>H%us H%us' % (len(self
.user_auth
), len(self
.data
))
277 return struct
.pack(fmt
, len(self
.user_auth
), self
.user_auth
,
278 len(self
.data
), self
.data
)
281 fmt
= '>H%us H%us' % (len(self
.user_auth
), len(self
.data
))
282 return struct
.calcsize(fmt
)
285 class Public(object):
289 FIXED_PARENT
= (1 << 4)
290 SENSITIVE_DATA_ORIGIN
= (1 << 5)
291 USER_WITH_AUTH
= (1 << 6)
292 RESTRICTED
= (1 << 16)
296 return '>HHIH%us%usH%us' % \
297 (len(self
.auth_policy
), len(self
.parameters
), len(self
.unique
))
299 def __init__(self
, object_type
, name_alg
, object_attributes
, auth_policy
='',
300 parameters
='', unique
=''):
301 self
.object_type
= object_type
302 self
.name_alg
= name_alg
303 self
.object_attributes
= object_attributes
304 self
.auth_policy
= auth_policy
305 self
.parameters
= parameters
309 return struct
.pack(self
.__fmt
(),
312 self
.object_attributes
,
313 len(self
.auth_policy
),
320 return struct
.calcsize(self
.__fmt
())
323 def get_digest_size(alg
):
324 ds
= ALG_DIGEST_SIZE_MAP
.get(alg
)
326 raise UnknownAlgorithmIdError(alg
)
330 def get_hash_function(alg
):
331 f
= ALG_HASH_FUNCTION_MAP
.get(alg
)
333 raise UnknownAlgorithmIdError(alg
)
337 def get_algorithm(name
):
338 alg
= NAME_ALG_MAP
.get(name
)
340 raise UnknownAlgorithmNameError(name
)
345 d
= [format(ord(x
), '02x') for x
in d
]
346 d
= [d
[i
: i
+ 16] for i
in xrange(0, len(d
), 16)]
347 d
= [' '.join(x
) for x
in d
]
348 d
= os
.linesep
.join(d
)
356 TPM_IOC_NEW_SPACE
= 0xa200
358 def __init__(self
, flags
= 0):
361 if (self
.flags
& Client
.FLAG_SPACE
) == 0:
362 self
.tpm
= open('/dev/tpm0', 'r+b', buffering
=0)
364 self
.tpm
= open('/dev/tpmrm0', 'r+b', buffering
=0)
366 if (self
.flags
& Client
.FLAG_NONBLOCK
):
367 flags
= fcntl
.fcntl(self
.tpm
, fcntl
.F_GETFL
)
368 flags |
= os
.O_NONBLOCK
369 fcntl
.fcntl(self
.tpm
, fcntl
.F_SETFL
, flags
)
370 self
.tpm_poll
= select
.poll()
375 def send_cmd(self
, cmd
):
378 if (self
.flags
& Client
.FLAG_NONBLOCK
):
379 self
.tpm_poll
.register(self
.tpm
, select
.POLLIN
)
380 self
.tpm_poll
.poll(10000)
382 rsp
= self
.tpm
.read()
384 if (self
.flags
& Client
.FLAG_NONBLOCK
):
385 self
.tpm_poll
.unregister(self
.tpm
)
387 if (self
.flags
& Client
.FLAG_DEBUG
) != 0:
388 sys
.stderr
.write('cmd' + os
.linesep
)
389 sys
.stderr
.write(hex_dump(cmd
) + os
.linesep
)
390 sys
.stderr
.write('rsp' + os
.linesep
)
391 sys
.stderr
.write(hex_dump(rsp
) + os
.linesep
)
393 rc
= struct
.unpack('>I', rsp
[6:10])[0]
395 cc
= struct
.unpack('>I', cmd
[6:10])[0]
396 raise ProtocolError(cc
, rc
)
400 def read_pcr(self
, i
, bank_alg
= TPM2_ALG_SHA1
):
401 pcrsel_len
= max((i
>> 3) + 1, 3)
402 pcrsel
= [0] * pcrsel_len
403 pcrsel
[i
>> 3] = 1 << (i
& 7)
404 pcrsel
= ''.join(map(chr, pcrsel
))
406 fmt
= '>HII IHB%us' % (pcrsel_len
)
407 cmd
= struct
.pack(fmt
,
409 struct
.calcsize(fmt
),
415 rsp
= self
.send_cmd(cmd
)
417 pcr_update_cnt
, pcr_select_cnt
= struct
.unpack('>II', rsp
[10:18])
418 assert pcr_select_cnt
== 1
421 alg2
, pcrsel_len2
= struct
.unpack('>HB', rsp
[:3])
422 assert bank_alg
== alg2
and pcrsel_len
== pcrsel_len2
423 rsp
= rsp
[3 + pcrsel_len
:]
425 digest_cnt
= struct
.unpack('>I', rsp
[:4])[0]
432 def extend_pcr(self
, i
, dig
, bank_alg
= TPM2_ALG_SHA1
):
433 ds
= get_digest_size(bank_alg
)
434 assert(ds
== len(dig
))
436 auth_cmd
= AuthCommand()
438 fmt
= '>HII I I%us IH%us' % (len(auth_cmd
), ds
)
442 struct
.calcsize(fmt
),
451 def start_auth_session(self
, session_type
, name_alg
= TPM2_ALG_SHA1
):
452 fmt
= '>HII IIH16sHBHH'
453 cmd
= struct
.pack(fmt
,
455 struct
.calcsize(fmt
),
456 TPM2_CC_START_AUTH_SESSION
,
466 return struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
468 def __calc_pcr_digest(self
, pcrs
, bank_alg
= TPM2_ALG_SHA1
,
469 digest_alg
= TPM2_ALG_SHA1
):
471 f
= get_hash_function(digest_alg
)
474 pcr
= self
.read_pcr(i
, bank_alg
)
479 return f(bytearray(x
)).digest()
481 def policy_pcr(self
, handle
, pcrs
, bank_alg
= TPM2_ALG_SHA1
,
482 name_alg
= TPM2_ALG_SHA1
):
483 ds
= get_digest_size(name_alg
)
484 dig
= self
.__calc
_pcr
_digest
(pcrs
, bank_alg
, name_alg
)
486 raise UnknownPCRBankError(bank_alg
)
488 pcrsel_len
= max((max(pcrs
) >> 3) + 1, 3)
489 pcrsel
= [0] * pcrsel_len
491 pcrsel
[i
>> 3] |
= 1 << (i
& 7)
492 pcrsel
= ''.join(map(chr, pcrsel
))
494 fmt
= '>HII IH%usIHB3s' % ds
495 cmd
= struct
.pack(fmt
,
497 struct
.calcsize(fmt
),
507 def policy_password(self
, handle
):
509 cmd
= struct
.pack(fmt
,
511 struct
.calcsize(fmt
),
512 TPM2_CC_POLICY_PASSWORD
,
517 def get_policy_digest(self
, handle
):
519 cmd
= struct
.pack(fmt
,
521 struct
.calcsize(fmt
),
522 TPM2_CC_POLICY_GET_DIGEST
,
525 return self
.send_cmd(cmd
)[12:]
527 def flush_context(self
, handle
):
529 cmd
= struct
.pack(fmt
,
531 struct
.calcsize(fmt
),
532 TPM2_CC_FLUSH_CONTEXT
,
537 def create_root_key(self
, auth_value
= ''):
540 Public
.FIXED_PARENT | \
541 Public
.SENSITIVE_DATA_ORIGIN | \
542 Public
.USER_WITH_AUTH | \
543 Public
.RESTRICTED | \
546 auth_cmd
= AuthCommand()
547 sensitive
= SensitiveCreate(user_auth
=auth_value
)
549 public_parms
= struct
.pack(
559 object_type
=TPM2_ALG_RSA
,
560 name_alg
=TPM2_ALG_SHA1
,
561 object_attributes
=attributes
,
562 parameters
=public_parms
)
564 fmt
= '>HIII I%us H%us H%us HI' % \
565 (len(auth_cmd
), len(sensitive
), len(public
))
569 struct
.calcsize(fmt
),
570 TPM2_CC_CREATE_PRIMARY
,
580 return struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
582 def seal(self
, parent_key
, data
, auth_value
, policy_dig
,
583 name_alg
= TPM2_ALG_SHA1
):
584 ds
= get_digest_size(name_alg
)
585 assert(not policy_dig
or ds
== len(policy_dig
))
589 attributes |
= Public
.USER_WITH_AUTH
592 auth_cmd
= AuthCommand()
593 sensitive
= SensitiveCreate(user_auth
=auth_value
, data
=data
)
596 object_type
=TPM2_ALG_KEYEDHASH
,
598 object_attributes
=attributes
,
599 auth_policy
=policy_dig
,
600 parameters
=struct
.pack('>H', TPM2_ALG_NULL
))
602 fmt
= '>HIII I%us H%us H%us HI' % \
603 (len(auth_cmd
), len(sensitive
), len(public
))
607 struct
.calcsize(fmt
),
618 rsp
= self
.send_cmd(cmd
)
622 def unseal(self
, parent_key
, blob
, auth_value
, policy_handle
):
623 private_len
= struct
.unpack('>H', blob
[0:2])[0]
624 public_start
= private_len
+ 2
625 public_len
= struct
.unpack('>H', blob
[public_start
:public_start
+ 2])[0]
626 blob
= blob
[:private_len
+ public_len
+ 4]
628 auth_cmd
= AuthCommand()
630 fmt
= '>HII I I%us %us' % (len(auth_cmd
), len(blob
))
634 struct
.calcsize(fmt
),
641 data_handle
= struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
644 auth_cmd
= AuthCommand(session_handle
=policy_handle
, hmac
=auth_value
)
646 auth_cmd
= AuthCommand(hmac
=auth_value
)
648 fmt
= '>HII I I%us' % (len(auth_cmd
))
652 struct
.calcsize(fmt
),
659 rsp
= self
.send_cmd(cmd
)
661 self
.flush_context(data_handle
)
663 data_len
= struct
.unpack('>I', rsp
[10:14])[0] - 2
665 return rsp
[16:16 + data_len
]
667 def reset_da_lock(self
):
668 auth_cmd
= AuthCommand()
670 fmt
= '>HII I I%us' % (len(auth_cmd
))
674 struct
.calcsize(fmt
),
675 TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET
,
682 def __get_cap_cnt(self
, cap
, pt
, cnt
):
686 cmd
= struct
.pack(fmt
,
688 struct
.calcsize(fmt
),
689 TPM2_CC_GET_CAPABILITY
,
692 rsp
= self
.send_cmd(cmd
)[10:]
693 more_data
, cap
, cnt
= struct
.unpack('>BII', rsp
[:9])
696 for i
in xrange(0, cnt
):
697 handle
= struct
.unpack('>I', rsp
[:4])[0]
698 handles
.append(handle
)
701 return handles
, more_data
703 def get_cap(self
, cap
, pt
):
708 next_handles
, more_data
= self
.__get
_cap
_cnt
(cap
, pt
, 1)
709 handles
+= next_handles