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
=bytes(),
251 session_attributes
=0, hmac
=bytes()):
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
=bytes(), data
=bytes()):
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
,
300 auth_policy
=bytes(), parameters
=bytes(),
302 self
.object_type
= object_type
303 self
.name_alg
= name_alg
304 self
.object_attributes
= object_attributes
305 self
.auth_policy
= auth_policy
306 self
.parameters
= parameters
310 return struct
.pack(self
.__fmt
(),
313 self
.object_attributes
,
314 len(self
.auth_policy
),
321 return struct
.calcsize(self
.__fmt
())
324 def get_digest_size(alg
):
325 ds
= ALG_DIGEST_SIZE_MAP
.get(alg
)
327 raise UnknownAlgorithmIdError(alg
)
331 def get_hash_function(alg
):
332 f
= ALG_HASH_FUNCTION_MAP
.get(alg
)
334 raise UnknownAlgorithmIdError(alg
)
338 def get_algorithm(name
):
339 alg
= NAME_ALG_MAP
.get(name
)
341 raise UnknownAlgorithmNameError(name
)
346 d
= [format(ord(x
), '02x') for x
in d
]
347 d
= [d
[i
: i
+ 16] for i
in range(0, len(d
), 16)]
348 d
= [' '.join(x
) for x
in d
]
349 d
= os
.linesep
.join(d
)
357 TPM_IOC_NEW_SPACE
= 0xa200
359 def __init__(self
, flags
= 0):
362 if (self
.flags
& Client
.FLAG_SPACE
) == 0:
363 self
.tpm
= open('/dev/tpm0', 'r+b', buffering
=0)
365 self
.tpm
= open('/dev/tpmrm0', 'r+b', buffering
=0)
367 if (self
.flags
& Client
.FLAG_NONBLOCK
):
368 flags
= fcntl
.fcntl(self
.tpm
, fcntl
.F_GETFL
)
369 flags |
= os
.O_NONBLOCK
370 fcntl
.fcntl(self
.tpm
, fcntl
.F_SETFL
, flags
)
371 self
.tpm_poll
= select
.poll()
376 def send_cmd(self
, cmd
):
379 if (self
.flags
& Client
.FLAG_NONBLOCK
):
380 self
.tpm_poll
.register(self
.tpm
, select
.POLLIN
)
381 self
.tpm_poll
.poll(10000)
383 rsp
= self
.tpm
.read()
385 if (self
.flags
& Client
.FLAG_NONBLOCK
):
386 self
.tpm_poll
.unregister(self
.tpm
)
388 if (self
.flags
& Client
.FLAG_DEBUG
) != 0:
389 sys
.stderr
.write('cmd' + os
.linesep
)
390 sys
.stderr
.write(hex_dump(cmd
) + os
.linesep
)
391 sys
.stderr
.write('rsp' + os
.linesep
)
392 sys
.stderr
.write(hex_dump(rsp
) + os
.linesep
)
394 rc
= struct
.unpack('>I', rsp
[6:10])[0]
396 cc
= struct
.unpack('>I', cmd
[6:10])[0]
397 raise ProtocolError(cc
, rc
)
401 def read_pcr(self
, i
, bank_alg
= TPM2_ALG_SHA1
):
402 pcrsel_len
= max((i
>> 3) + 1, 3)
403 pcrsel
= [0] * pcrsel_len
404 pcrsel
[i
>> 3] = 1 << (i
& 7)
405 pcrsel
= ''.join(map(chr, pcrsel
)).encode()
407 fmt
= '>HII IHB%us' % (pcrsel_len
)
408 cmd
= struct
.pack(fmt
,
410 struct
.calcsize(fmt
),
416 rsp
= self
.send_cmd(cmd
)
418 pcr_update_cnt
, pcr_select_cnt
= struct
.unpack('>II', rsp
[10:18])
419 assert pcr_select_cnt
== 1
422 alg2
, pcrsel_len2
= struct
.unpack('>HB', rsp
[:3])
423 assert bank_alg
== alg2
and pcrsel_len
== pcrsel_len2
424 rsp
= rsp
[3 + pcrsel_len
:]
426 digest_cnt
= struct
.unpack('>I', rsp
[:4])[0]
433 def extend_pcr(self
, i
, dig
, bank_alg
= TPM2_ALG_SHA1
):
434 ds
= get_digest_size(bank_alg
)
435 assert(ds
== len(dig
))
437 auth_cmd
= AuthCommand()
439 fmt
= '>HII I I%us IH%us' % (len(auth_cmd
), ds
)
443 struct
.calcsize(fmt
),
452 def start_auth_session(self
, session_type
, name_alg
= TPM2_ALG_SHA1
):
453 fmt
= '>HII IIH16sHBHH'
454 cmd
= struct
.pack(fmt
,
456 struct
.calcsize(fmt
),
457 TPM2_CC_START_AUTH_SESSION
,
461 ('\0' * 16).encode(),
467 return struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
469 def __calc_pcr_digest(self
, pcrs
, bank_alg
= TPM2_ALG_SHA1
,
470 digest_alg
= TPM2_ALG_SHA1
):
472 f
= get_hash_function(digest_alg
)
475 pcr
= self
.read_pcr(i
, bank_alg
)
480 return f(bytearray(x
)).digest()
482 def policy_pcr(self
, handle
, pcrs
, bank_alg
= TPM2_ALG_SHA1
,
483 name_alg
= TPM2_ALG_SHA1
):
484 ds
= get_digest_size(name_alg
)
485 dig
= self
.__calc
_pcr
_digest
(pcrs
, bank_alg
, name_alg
)
487 raise UnknownPCRBankError(bank_alg
)
489 pcrsel_len
= max((max(pcrs
) >> 3) + 1, 3)
490 pcrsel
= [0] * pcrsel_len
492 pcrsel
[i
>> 3] |
= 1 << (i
& 7)
493 pcrsel
= ''.join(map(chr, pcrsel
)).encode()
495 fmt
= '>HII IH%usIHB3s' % ds
496 cmd
= struct
.pack(fmt
,
498 struct
.calcsize(fmt
),
509 def policy_password(self
, handle
):
511 cmd
= struct
.pack(fmt
,
513 struct
.calcsize(fmt
),
514 TPM2_CC_POLICY_PASSWORD
,
519 def get_policy_digest(self
, handle
):
521 cmd
= struct
.pack(fmt
,
523 struct
.calcsize(fmt
),
524 TPM2_CC_POLICY_GET_DIGEST
,
527 return self
.send_cmd(cmd
)[12:]
529 def flush_context(self
, handle
):
531 cmd
= struct
.pack(fmt
,
533 struct
.calcsize(fmt
),
534 TPM2_CC_FLUSH_CONTEXT
,
539 def create_root_key(self
, auth_value
= bytes()):
542 Public
.FIXED_PARENT | \
543 Public
.SENSITIVE_DATA_ORIGIN | \
544 Public
.USER_WITH_AUTH | \
545 Public
.RESTRICTED | \
548 auth_cmd
= AuthCommand()
549 sensitive
= SensitiveCreate(user_auth
=auth_value
)
551 public_parms
= struct
.pack(
561 object_type
=TPM2_ALG_RSA
,
562 name_alg
=TPM2_ALG_SHA1
,
563 object_attributes
=attributes
,
564 parameters
=public_parms
)
566 fmt
= '>HIII I%us H%us H%us HI' % \
567 (len(auth_cmd
), len(sensitive
), len(public
))
571 struct
.calcsize(fmt
),
572 TPM2_CC_CREATE_PRIMARY
,
582 return struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
584 def seal(self
, parent_key
, data
, auth_value
, policy_dig
,
585 name_alg
= TPM2_ALG_SHA1
):
586 ds
= get_digest_size(name_alg
)
587 assert(not policy_dig
or ds
== len(policy_dig
))
591 attributes |
= Public
.USER_WITH_AUTH
594 auth_cmd
= AuthCommand()
595 sensitive
= SensitiveCreate(user_auth
=auth_value
, data
=data
)
598 object_type
=TPM2_ALG_KEYEDHASH
,
600 object_attributes
=attributes
,
601 auth_policy
=policy_dig
,
602 parameters
=struct
.pack('>H', TPM2_ALG_NULL
))
604 fmt
= '>HIII I%us H%us H%us HI' % \
605 (len(auth_cmd
), len(sensitive
), len(public
))
609 struct
.calcsize(fmt
),
620 rsp
= self
.send_cmd(cmd
)
624 def unseal(self
, parent_key
, blob
, auth_value
, policy_handle
):
625 private_len
= struct
.unpack('>H', blob
[0:2])[0]
626 public_start
= private_len
+ 2
627 public_len
= struct
.unpack('>H', blob
[public_start
:public_start
+ 2])[0]
628 blob
= blob
[:private_len
+ public_len
+ 4]
630 auth_cmd
= AuthCommand()
632 fmt
= '>HII I I%us %us' % (len(auth_cmd
), len(blob
))
636 struct
.calcsize(fmt
),
643 data_handle
= struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
646 auth_cmd
= AuthCommand(session_handle
=policy_handle
, hmac
=auth_value
)
648 auth_cmd
= AuthCommand(hmac
=auth_value
)
650 fmt
= '>HII I I%us' % (len(auth_cmd
))
654 struct
.calcsize(fmt
),
661 rsp
= self
.send_cmd(cmd
)
663 self
.flush_context(data_handle
)
665 data_len
= struct
.unpack('>I', rsp
[10:14])[0] - 2
667 return rsp
[16:16 + data_len
]
669 def reset_da_lock(self
):
670 auth_cmd
= AuthCommand()
672 fmt
= '>HII I I%us' % (len(auth_cmd
))
676 struct
.calcsize(fmt
),
677 TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET
,
684 def __get_cap_cnt(self
, cap
, pt
, cnt
):
688 cmd
= struct
.pack(fmt
,
690 struct
.calcsize(fmt
),
691 TPM2_CC_GET_CAPABILITY
,
694 rsp
= self
.send_cmd(cmd
)[10:]
695 more_data
, cap
, cnt
= struct
.unpack('>BII', rsp
[:9])
698 for i
in range(0, cnt
):
699 handle
= struct
.unpack('>I', rsp
[:4])[0]
700 handles
.append(handle
)
703 return handles
, more_data
705 def get_cap(self
, cap
, pt
):
710 next_handles
, more_data
= self
.__get
_cap
_cnt
(cap
, pt
, 1)
711 handles
+= next_handles