1 # SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
9 from fcntl
import ioctl
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
)
355 TPM_IOC_NEW_SPACE
= 0xa200
357 def __init__(self
, flags
= 0):
360 if (self
.flags
& Client
.FLAG_SPACE
) == 0:
361 self
.tpm
= open('/dev/tpm0', 'r+b', buffering
=0)
363 self
.tpm
= open('/dev/tpmrm0', 'r+b', buffering
=0)
368 def send_cmd(self
, cmd
):
370 rsp
= self
.tpm
.read()
372 if (self
.flags
& Client
.FLAG_DEBUG
) != 0:
373 sys
.stderr
.write('cmd' + os
.linesep
)
374 sys
.stderr
.write(hex_dump(cmd
) + os
.linesep
)
375 sys
.stderr
.write('rsp' + os
.linesep
)
376 sys
.stderr
.write(hex_dump(rsp
) + os
.linesep
)
378 rc
= struct
.unpack('>I', rsp
[6:10])[0]
380 cc
= struct
.unpack('>I', cmd
[6:10])[0]
381 raise ProtocolError(cc
, rc
)
385 def read_pcr(self
, i
, bank_alg
= TPM2_ALG_SHA1
):
386 pcrsel_len
= max((i
>> 3) + 1, 3)
387 pcrsel
= [0] * pcrsel_len
388 pcrsel
[i
>> 3] = 1 << (i
& 7)
389 pcrsel
= ''.join(map(chr, pcrsel
))
391 fmt
= '>HII IHB%us' % (pcrsel_len
)
392 cmd
= struct
.pack(fmt
,
394 struct
.calcsize(fmt
),
400 rsp
= self
.send_cmd(cmd
)
402 pcr_update_cnt
, pcr_select_cnt
= struct
.unpack('>II', rsp
[10:18])
403 assert pcr_select_cnt
== 1
406 alg2
, pcrsel_len2
= struct
.unpack('>HB', rsp
[:3])
407 assert bank_alg
== alg2
and pcrsel_len
== pcrsel_len2
408 rsp
= rsp
[3 + pcrsel_len
:]
410 digest_cnt
= struct
.unpack('>I', rsp
[:4])[0]
417 def extend_pcr(self
, i
, dig
, bank_alg
= TPM2_ALG_SHA1
):
418 ds
= get_digest_size(bank_alg
)
419 assert(ds
== len(dig
))
421 auth_cmd
= AuthCommand()
423 fmt
= '>HII I I%us IH%us' % (len(auth_cmd
), ds
)
427 struct
.calcsize(fmt
),
436 def start_auth_session(self
, session_type
, name_alg
= TPM2_ALG_SHA1
):
437 fmt
= '>HII IIH16sHBHH'
438 cmd
= struct
.pack(fmt
,
440 struct
.calcsize(fmt
),
441 TPM2_CC_START_AUTH_SESSION
,
451 return struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
453 def __calc_pcr_digest(self
, pcrs
, bank_alg
= TPM2_ALG_SHA1
,
454 digest_alg
= TPM2_ALG_SHA1
):
456 f
= get_hash_function(digest_alg
)
459 pcr
= self
.read_pcr(i
, bank_alg
)
464 return f(bytearray(x
)).digest()
466 def policy_pcr(self
, handle
, pcrs
, bank_alg
= TPM2_ALG_SHA1
,
467 name_alg
= TPM2_ALG_SHA1
):
468 ds
= get_digest_size(name_alg
)
469 dig
= self
.__calc
_pcr
_digest
(pcrs
, bank_alg
, name_alg
)
471 raise UnknownPCRBankError(bank_alg
)
473 pcrsel_len
= max((max(pcrs
) >> 3) + 1, 3)
474 pcrsel
= [0] * pcrsel_len
476 pcrsel
[i
>> 3] |
= 1 << (i
& 7)
477 pcrsel
= ''.join(map(chr, pcrsel
))
479 fmt
= '>HII IH%usIHB3s' % ds
480 cmd
= struct
.pack(fmt
,
482 struct
.calcsize(fmt
),
492 def policy_password(self
, handle
):
494 cmd
= struct
.pack(fmt
,
496 struct
.calcsize(fmt
),
497 TPM2_CC_POLICY_PASSWORD
,
502 def get_policy_digest(self
, handle
):
504 cmd
= struct
.pack(fmt
,
506 struct
.calcsize(fmt
),
507 TPM2_CC_POLICY_GET_DIGEST
,
510 return self
.send_cmd(cmd
)[12:]
512 def flush_context(self
, handle
):
514 cmd
= struct
.pack(fmt
,
516 struct
.calcsize(fmt
),
517 TPM2_CC_FLUSH_CONTEXT
,
522 def create_root_key(self
, auth_value
= ''):
525 Public
.FIXED_PARENT | \
526 Public
.SENSITIVE_DATA_ORIGIN | \
527 Public
.USER_WITH_AUTH | \
528 Public
.RESTRICTED | \
531 auth_cmd
= AuthCommand()
532 sensitive
= SensitiveCreate(user_auth
=auth_value
)
534 public_parms
= struct
.pack(
544 object_type
=TPM2_ALG_RSA
,
545 name_alg
=TPM2_ALG_SHA1
,
546 object_attributes
=attributes
,
547 parameters
=public_parms
)
549 fmt
= '>HIII I%us H%us H%us HI' % \
550 (len(auth_cmd
), len(sensitive
), len(public
))
554 struct
.calcsize(fmt
),
555 TPM2_CC_CREATE_PRIMARY
,
565 return struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
567 def seal(self
, parent_key
, data
, auth_value
, policy_dig
,
568 name_alg
= TPM2_ALG_SHA1
):
569 ds
= get_digest_size(name_alg
)
570 assert(not policy_dig
or ds
== len(policy_dig
))
574 attributes |
= Public
.USER_WITH_AUTH
577 auth_cmd
= AuthCommand()
578 sensitive
= SensitiveCreate(user_auth
=auth_value
, data
=data
)
581 object_type
=TPM2_ALG_KEYEDHASH
,
583 object_attributes
=attributes
,
584 auth_policy
=policy_dig
,
585 parameters
=struct
.pack('>H', TPM2_ALG_NULL
))
587 fmt
= '>HIII I%us H%us H%us HI' % \
588 (len(auth_cmd
), len(sensitive
), len(public
))
592 struct
.calcsize(fmt
),
603 rsp
= self
.send_cmd(cmd
)
607 def unseal(self
, parent_key
, blob
, auth_value
, policy_handle
):
608 private_len
= struct
.unpack('>H', blob
[0:2])[0]
609 public_start
= private_len
+ 2
610 public_len
= struct
.unpack('>H', blob
[public_start
:public_start
+ 2])[0]
611 blob
= blob
[:private_len
+ public_len
+ 4]
613 auth_cmd
= AuthCommand()
615 fmt
= '>HII I I%us %us' % (len(auth_cmd
), len(blob
))
619 struct
.calcsize(fmt
),
626 data_handle
= struct
.unpack('>I', self
.send_cmd(cmd
)[10:14])[0]
629 auth_cmd
= AuthCommand(session_handle
=policy_handle
, hmac
=auth_value
)
631 auth_cmd
= AuthCommand(hmac
=auth_value
)
633 fmt
= '>HII I I%us' % (len(auth_cmd
))
637 struct
.calcsize(fmt
),
644 rsp
= self
.send_cmd(cmd
)
646 self
.flush_context(data_handle
)
648 data_len
= struct
.unpack('>I', rsp
[10:14])[0] - 2
650 return rsp
[16:16 + data_len
]
652 def reset_da_lock(self
):
653 auth_cmd
= AuthCommand()
655 fmt
= '>HII I I%us' % (len(auth_cmd
))
659 struct
.calcsize(fmt
),
660 TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET
,
667 def __get_cap_cnt(self
, cap
, pt
, cnt
):
671 cmd
= struct
.pack(fmt
,
673 struct
.calcsize(fmt
),
674 TPM2_CC_GET_CAPABILITY
,
677 rsp
= self
.send_cmd(cmd
)[10:]
678 more_data
, cap
, cnt
= struct
.unpack('>BII', rsp
[:9])
681 for i
in xrange(0, cnt
):
682 handle
= struct
.unpack('>I', rsp
[:4])[0]
683 handles
.append(handle
)
686 return handles
, more_data
688 def get_cap(self
, cap
, pt
):
693 next_handles
, more_data
= self
.__get
_cap
_cnt
(cap
, pt
, 1)
694 handles
+= next_handles