David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame^] | 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 | from fcntl import ioctl |
| 10 | |
| 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_TPM_PROPERTIES = 0x00000006 |
| 60 | |
| 61 | TPM2_PT_FIXED = 0x100 |
| 62 | TPM2_PT_TOTAL_COMMANDS = TPM2_PT_FIXED + 41 |
| 63 | |
| 64 | HR_SHIFT = 24 |
| 65 | HR_LOADED_SESSION = 0x02000000 |
| 66 | HR_TRANSIENT = 0x80000000 |
| 67 | |
| 68 | SHA1_DIGEST_SIZE = 20 |
| 69 | SHA256_DIGEST_SIZE = 32 |
| 70 | |
| 71 | TPM2_VER0_ERRORS = { |
| 72 | 0x000: "TPM_RC_SUCCESS", |
| 73 | 0x030: "TPM_RC_BAD_TAG", |
| 74 | } |
| 75 | |
| 76 | TPM2_VER1_ERRORS = { |
| 77 | 0x000: "TPM_RC_FAILURE", |
| 78 | 0x001: "TPM_RC_FAILURE", |
| 79 | 0x003: "TPM_RC_SEQUENCE", |
| 80 | 0x00B: "TPM_RC_PRIVATE", |
| 81 | 0x019: "TPM_RC_HMAC", |
| 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", |
| 87 | 0x027: "TPM_RC_PCR", |
| 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", |
| 111 | 0x07F: "RC_MAX_FM0", |
| 112 | } |
| 113 | |
| 114 | TPM2_FMT1_ERRORS = { |
| 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", |
| 121 | 0x008: "TPM_RC_MGF", |
| 122 | 0x009: "TPM_RC_MODE", |
| 123 | 0x00A: "TPM_RC_TYPE", |
| 124 | 0x00B: "TPM_RC_HANDLE", |
| 125 | 0x00C: "TPM_RC_KDF", |
| 126 | 0x00D: "TPM_RC_RANGE", |
| 127 | 0x00E: "TPM_RC_AUTH_FAIL", |
| 128 | 0x00F: "TPM_RC_NONCE", |
| 129 | 0x010: "TPM_RC_PP", |
| 130 | 0x012: "TPM_RC_SCHEME", |
| 131 | 0x015: "TPM_RC_SIZE", |
| 132 | 0x016: "TPM_RC_SYMMETRIC", |
| 133 | 0x017: "TPM_RC_TAG", |
| 134 | 0x018: "TPM_RC_SELECTOR", |
| 135 | 0x01A: "TPM_RC_INSUFFICIENT", |
| 136 | 0x01B: "TPM_RC_SIGNATURE", |
| 137 | 0x01C: "TPM_RC_KEY", |
| 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", |
| 148 | } |
| 149 | |
| 150 | TPM2_WARN_ERRORS = { |
| 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", |
| 180 | } |
| 181 | |
| 182 | RC_VER1 = 0x100 |
| 183 | RC_FMT1 = 0x080 |
| 184 | RC_WARN = 0x900 |
| 185 | |
| 186 | ALG_DIGEST_SIZE_MAP = { |
| 187 | TPM2_ALG_SHA1: SHA1_DIGEST_SIZE, |
| 188 | TPM2_ALG_SHA256: SHA256_DIGEST_SIZE, |
| 189 | } |
| 190 | |
| 191 | ALG_HASH_FUNCTION_MAP = { |
| 192 | TPM2_ALG_SHA1: hashlib.sha1, |
| 193 | TPM2_ALG_SHA256: hashlib.sha256 |
| 194 | } |
| 195 | |
| 196 | NAME_ALG_MAP = { |
| 197 | "sha1": TPM2_ALG_SHA1, |
| 198 | "sha256": TPM2_ALG_SHA256, |
| 199 | } |
| 200 | |
| 201 | |
| 202 | class UnknownAlgorithmIdError(Exception): |
| 203 | def __init__(self, alg): |
| 204 | self.alg = alg |
| 205 | |
| 206 | def __str__(self): |
| 207 | return '0x%0x' % (alg) |
| 208 | |
| 209 | |
| 210 | class UnknownAlgorithmNameError(Exception): |
| 211 | def __init__(self, name): |
| 212 | self.name = name |
| 213 | |
| 214 | def __str__(self): |
| 215 | return name |
| 216 | |
| 217 | |
| 218 | class UnknownPCRBankError(Exception): |
| 219 | def __init__(self, alg): |
| 220 | self.alg = alg |
| 221 | |
| 222 | def __str__(self): |
| 223 | return '0x%0x' % (alg) |
| 224 | |
| 225 | |
| 226 | class ProtocolError(Exception): |
| 227 | def __init__(self, cc, rc): |
| 228 | self.cc = cc |
| 229 | self.rc = rc |
| 230 | |
| 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") |
| 237 | else: |
| 238 | self.name = TPM2_VER0_ERRORS.get(rc & 0x7f, "TPM_RC_UNKNOWN") |
| 239 | |
| 240 | def __str__(self): |
| 241 | if self.cc: |
| 242 | return '%s: cc=0x%08x, rc=0x%08x' % (self.name, self.cc, self.rc) |
| 243 | else: |
| 244 | return '%s: rc=0x%08x' % (self.name, self.rc) |
| 245 | |
| 246 | |
| 247 | class AuthCommand(object): |
| 248 | """TPMS_AUTH_COMMAND""" |
| 249 | |
| 250 | def __init__(self, session_handle=TPM2_RS_PW, nonce='', session_attributes=0, |
| 251 | hmac=''): |
| 252 | self.session_handle = session_handle |
| 253 | self.nonce = nonce |
| 254 | self.session_attributes = session_attributes |
| 255 | self.hmac = hmac |
| 256 | |
| 257 | def __str__(self): |
| 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), |
| 261 | self.hmac) |
| 262 | |
| 263 | def __len__(self): |
| 264 | fmt = '>I H%us B H%us' % (len(self.nonce), len(self.hmac)) |
| 265 | return struct.calcsize(fmt) |
| 266 | |
| 267 | |
| 268 | class SensitiveCreate(object): |
| 269 | """TPMS_SENSITIVE_CREATE""" |
| 270 | |
| 271 | def __init__(self, user_auth='', data=''): |
| 272 | self.user_auth = user_auth |
| 273 | self.data = data |
| 274 | |
| 275 | def __str__(self): |
| 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) |
| 279 | |
| 280 | def __len__(self): |
| 281 | fmt = '>H%us H%us' % (len(self.user_auth), len(self.data)) |
| 282 | return struct.calcsize(fmt) |
| 283 | |
| 284 | |
| 285 | class Public(object): |
| 286 | """TPMT_PUBLIC""" |
| 287 | |
| 288 | FIXED_TPM = (1 << 1) |
| 289 | FIXED_PARENT = (1 << 4) |
| 290 | SENSITIVE_DATA_ORIGIN = (1 << 5) |
| 291 | USER_WITH_AUTH = (1 << 6) |
| 292 | RESTRICTED = (1 << 16) |
| 293 | DECRYPT = (1 << 17) |
| 294 | |
| 295 | def __fmt(self): |
| 296 | return '>HHIH%us%usH%us' % \ |
| 297 | (len(self.auth_policy), len(self.parameters), len(self.unique)) |
| 298 | |
| 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 |
| 306 | self.unique = unique |
| 307 | |
| 308 | def __str__(self): |
| 309 | return struct.pack(self.__fmt(), |
| 310 | self.object_type, |
| 311 | self.name_alg, |
| 312 | self.object_attributes, |
| 313 | len(self.auth_policy), |
| 314 | self.auth_policy, |
| 315 | self.parameters, |
| 316 | len(self.unique), |
| 317 | self.unique) |
| 318 | |
| 319 | def __len__(self): |
| 320 | return struct.calcsize(self.__fmt()) |
| 321 | |
| 322 | |
| 323 | def get_digest_size(alg): |
| 324 | ds = ALG_DIGEST_SIZE_MAP.get(alg) |
| 325 | if not ds: |
| 326 | raise UnknownAlgorithmIdError(alg) |
| 327 | return ds |
| 328 | |
| 329 | |
| 330 | def get_hash_function(alg): |
| 331 | f = ALG_HASH_FUNCTION_MAP.get(alg) |
| 332 | if not f: |
| 333 | raise UnknownAlgorithmIdError(alg) |
| 334 | return f |
| 335 | |
| 336 | |
| 337 | def get_algorithm(name): |
| 338 | alg = NAME_ALG_MAP.get(name) |
| 339 | if not alg: |
| 340 | raise UnknownAlgorithmNameError(name) |
| 341 | return alg |
| 342 | |
| 343 | |
| 344 | def hex_dump(d): |
| 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) |
| 349 | |
| 350 | return d |
| 351 | |
| 352 | class Client: |
| 353 | FLAG_DEBUG = 0x01 |
| 354 | FLAG_SPACE = 0x02 |
| 355 | TPM_IOC_NEW_SPACE = 0xa200 |
| 356 | |
| 357 | def __init__(self, flags = 0): |
| 358 | self.flags = flags |
| 359 | |
| 360 | if (self.flags & Client.FLAG_SPACE) == 0: |
| 361 | self.tpm = open('/dev/tpm0', 'r+b', buffering=0) |
| 362 | else: |
| 363 | self.tpm = open('/dev/tpmrm0', 'r+b', buffering=0) |
| 364 | |
| 365 | def close(self): |
| 366 | self.tpm.close() |
| 367 | |
| 368 | def send_cmd(self, cmd): |
| 369 | self.tpm.write(cmd) |
| 370 | rsp = self.tpm.read() |
| 371 | |
| 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) |
| 377 | |
| 378 | rc = struct.unpack('>I', rsp[6:10])[0] |
| 379 | if rc != 0: |
| 380 | cc = struct.unpack('>I', cmd[6:10])[0] |
| 381 | raise ProtocolError(cc, rc) |
| 382 | |
| 383 | return rsp |
| 384 | |
| 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)) |
| 390 | |
| 391 | fmt = '>HII IHB%us' % (pcrsel_len) |
| 392 | cmd = struct.pack(fmt, |
| 393 | TPM2_ST_NO_SESSIONS, |
| 394 | struct.calcsize(fmt), |
| 395 | TPM2_CC_PCR_READ, |
| 396 | 1, |
| 397 | bank_alg, |
| 398 | pcrsel_len, pcrsel) |
| 399 | |
| 400 | rsp = self.send_cmd(cmd) |
| 401 | |
| 402 | pcr_update_cnt, pcr_select_cnt = struct.unpack('>II', rsp[10:18]) |
| 403 | assert pcr_select_cnt == 1 |
| 404 | rsp = rsp[18:] |
| 405 | |
| 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:] |
| 409 | |
| 410 | digest_cnt = struct.unpack('>I', rsp[:4])[0] |
| 411 | if digest_cnt == 0: |
| 412 | return None |
| 413 | rsp = rsp[6:] |
| 414 | |
| 415 | return rsp |
| 416 | |
| 417 | def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1): |
| 418 | ds = get_digest_size(bank_alg) |
| 419 | assert(ds == len(dig)) |
| 420 | |
| 421 | auth_cmd = AuthCommand() |
| 422 | |
| 423 | fmt = '>HII I I%us IH%us' % (len(auth_cmd), ds) |
| 424 | cmd = struct.pack( |
| 425 | fmt, |
| 426 | TPM2_ST_SESSIONS, |
| 427 | struct.calcsize(fmt), |
| 428 | TPM2_CC_PCR_EXTEND, |
| 429 | i, |
| 430 | len(auth_cmd), |
| 431 | str(auth_cmd), |
| 432 | 1, bank_alg, dig) |
| 433 | |
| 434 | self.send_cmd(cmd) |
| 435 | |
| 436 | def start_auth_session(self, session_type, name_alg = TPM2_ALG_SHA1): |
| 437 | fmt = '>HII IIH16sHBHH' |
| 438 | cmd = struct.pack(fmt, |
| 439 | TPM2_ST_NO_SESSIONS, |
| 440 | struct.calcsize(fmt), |
| 441 | TPM2_CC_START_AUTH_SESSION, |
| 442 | TPM2_RH_NULL, |
| 443 | TPM2_RH_NULL, |
| 444 | 16, |
| 445 | '\0' * 16, |
| 446 | 0, |
| 447 | session_type, |
| 448 | TPM2_ALG_NULL, |
| 449 | name_alg) |
| 450 | |
| 451 | return struct.unpack('>I', self.send_cmd(cmd)[10:14])[0] |
| 452 | |
| 453 | def __calc_pcr_digest(self, pcrs, bank_alg = TPM2_ALG_SHA1, |
| 454 | digest_alg = TPM2_ALG_SHA1): |
| 455 | x = [] |
| 456 | f = get_hash_function(digest_alg) |
| 457 | |
| 458 | for i in pcrs: |
| 459 | pcr = self.read_pcr(i, bank_alg) |
| 460 | if pcr == None: |
| 461 | return None |
| 462 | x += pcr |
| 463 | |
| 464 | return f(bytearray(x)).digest() |
| 465 | |
| 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) |
| 470 | if not dig: |
| 471 | raise UnknownPCRBankError(bank_alg) |
| 472 | |
| 473 | pcrsel_len = max((max(pcrs) >> 3) + 1, 3) |
| 474 | pcrsel = [0] * pcrsel_len |
| 475 | for i in pcrs: |
| 476 | pcrsel[i >> 3] |= 1 << (i & 7) |
| 477 | pcrsel = ''.join(map(chr, pcrsel)) |
| 478 | |
| 479 | fmt = '>HII IH%usIHB3s' % ds |
| 480 | cmd = struct.pack(fmt, |
| 481 | TPM2_ST_NO_SESSIONS, |
| 482 | struct.calcsize(fmt), |
| 483 | TPM2_CC_POLICY_PCR, |
| 484 | handle, |
| 485 | len(dig), str(dig), |
| 486 | 1, |
| 487 | bank_alg, |
| 488 | pcrsel_len, pcrsel) |
| 489 | |
| 490 | self.send_cmd(cmd) |
| 491 | |
| 492 | def policy_password(self, handle): |
| 493 | fmt = '>HII I' |
| 494 | cmd = struct.pack(fmt, |
| 495 | TPM2_ST_NO_SESSIONS, |
| 496 | struct.calcsize(fmt), |
| 497 | TPM2_CC_POLICY_PASSWORD, |
| 498 | handle) |
| 499 | |
| 500 | self.send_cmd(cmd) |
| 501 | |
| 502 | def get_policy_digest(self, handle): |
| 503 | fmt = '>HII I' |
| 504 | cmd = struct.pack(fmt, |
| 505 | TPM2_ST_NO_SESSIONS, |
| 506 | struct.calcsize(fmt), |
| 507 | TPM2_CC_POLICY_GET_DIGEST, |
| 508 | handle) |
| 509 | |
| 510 | return self.send_cmd(cmd)[12:] |
| 511 | |
| 512 | def flush_context(self, handle): |
| 513 | fmt = '>HIII' |
| 514 | cmd = struct.pack(fmt, |
| 515 | TPM2_ST_NO_SESSIONS, |
| 516 | struct.calcsize(fmt), |
| 517 | TPM2_CC_FLUSH_CONTEXT, |
| 518 | handle) |
| 519 | |
| 520 | self.send_cmd(cmd) |
| 521 | |
| 522 | def create_root_key(self, auth_value = ''): |
| 523 | attributes = \ |
| 524 | Public.FIXED_TPM | \ |
| 525 | Public.FIXED_PARENT | \ |
| 526 | Public.SENSITIVE_DATA_ORIGIN | \ |
| 527 | Public.USER_WITH_AUTH | \ |
| 528 | Public.RESTRICTED | \ |
| 529 | Public.DECRYPT |
| 530 | |
| 531 | auth_cmd = AuthCommand() |
| 532 | sensitive = SensitiveCreate(user_auth=auth_value) |
| 533 | |
| 534 | public_parms = struct.pack( |
| 535 | '>HHHHHI', |
| 536 | TPM2_ALG_AES, |
| 537 | 128, |
| 538 | TPM2_ALG_CFB, |
| 539 | TPM2_ALG_NULL, |
| 540 | 2048, |
| 541 | 0) |
| 542 | |
| 543 | public = Public( |
| 544 | object_type=TPM2_ALG_RSA, |
| 545 | name_alg=TPM2_ALG_SHA1, |
| 546 | object_attributes=attributes, |
| 547 | parameters=public_parms) |
| 548 | |
| 549 | fmt = '>HIII I%us H%us H%us HI' % \ |
| 550 | (len(auth_cmd), len(sensitive), len(public)) |
| 551 | cmd = struct.pack( |
| 552 | fmt, |
| 553 | TPM2_ST_SESSIONS, |
| 554 | struct.calcsize(fmt), |
| 555 | TPM2_CC_CREATE_PRIMARY, |
| 556 | TPM2_RH_OWNER, |
| 557 | len(auth_cmd), |
| 558 | str(auth_cmd), |
| 559 | len(sensitive), |
| 560 | str(sensitive), |
| 561 | len(public), |
| 562 | str(public), |
| 563 | 0, 0) |
| 564 | |
| 565 | return struct.unpack('>I', self.send_cmd(cmd)[10:14])[0] |
| 566 | |
| 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)) |
| 571 | |
| 572 | attributes = 0 |
| 573 | if not policy_dig: |
| 574 | attributes |= Public.USER_WITH_AUTH |
| 575 | policy_dig = '' |
| 576 | |
| 577 | auth_cmd = AuthCommand() |
| 578 | sensitive = SensitiveCreate(user_auth=auth_value, data=data) |
| 579 | |
| 580 | public = Public( |
| 581 | object_type=TPM2_ALG_KEYEDHASH, |
| 582 | name_alg=name_alg, |
| 583 | object_attributes=attributes, |
| 584 | auth_policy=policy_dig, |
| 585 | parameters=struct.pack('>H', TPM2_ALG_NULL)) |
| 586 | |
| 587 | fmt = '>HIII I%us H%us H%us HI' % \ |
| 588 | (len(auth_cmd), len(sensitive), len(public)) |
| 589 | cmd = struct.pack( |
| 590 | fmt, |
| 591 | TPM2_ST_SESSIONS, |
| 592 | struct.calcsize(fmt), |
| 593 | TPM2_CC_CREATE, |
| 594 | parent_key, |
| 595 | len(auth_cmd), |
| 596 | str(auth_cmd), |
| 597 | len(sensitive), |
| 598 | str(sensitive), |
| 599 | len(public), |
| 600 | str(public), |
| 601 | 0, 0) |
| 602 | |
| 603 | rsp = self.send_cmd(cmd) |
| 604 | |
| 605 | return rsp[14:] |
| 606 | |
| 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] |
| 612 | |
| 613 | auth_cmd = AuthCommand() |
| 614 | |
| 615 | fmt = '>HII I I%us %us' % (len(auth_cmd), len(blob)) |
| 616 | cmd = struct.pack( |
| 617 | fmt, |
| 618 | TPM2_ST_SESSIONS, |
| 619 | struct.calcsize(fmt), |
| 620 | TPM2_CC_LOAD, |
| 621 | parent_key, |
| 622 | len(auth_cmd), |
| 623 | str(auth_cmd), |
| 624 | blob) |
| 625 | |
| 626 | data_handle = struct.unpack('>I', self.send_cmd(cmd)[10:14])[0] |
| 627 | |
| 628 | if policy_handle: |
| 629 | auth_cmd = AuthCommand(session_handle=policy_handle, hmac=auth_value) |
| 630 | else: |
| 631 | auth_cmd = AuthCommand(hmac=auth_value) |
| 632 | |
| 633 | fmt = '>HII I I%us' % (len(auth_cmd)) |
| 634 | cmd = struct.pack( |
| 635 | fmt, |
| 636 | TPM2_ST_SESSIONS, |
| 637 | struct.calcsize(fmt), |
| 638 | TPM2_CC_UNSEAL, |
| 639 | data_handle, |
| 640 | len(auth_cmd), |
| 641 | str(auth_cmd)) |
| 642 | |
| 643 | try: |
| 644 | rsp = self.send_cmd(cmd) |
| 645 | finally: |
| 646 | self.flush_context(data_handle) |
| 647 | |
| 648 | data_len = struct.unpack('>I', rsp[10:14])[0] - 2 |
| 649 | |
| 650 | return rsp[16:16 + data_len] |
| 651 | |
| 652 | def reset_da_lock(self): |
| 653 | auth_cmd = AuthCommand() |
| 654 | |
| 655 | fmt = '>HII I I%us' % (len(auth_cmd)) |
| 656 | cmd = struct.pack( |
| 657 | fmt, |
| 658 | TPM2_ST_SESSIONS, |
| 659 | struct.calcsize(fmt), |
| 660 | TPM2_CC_DICTIONARY_ATTACK_LOCK_RESET, |
| 661 | TPM2_RH_LOCKOUT, |
| 662 | len(auth_cmd), |
| 663 | str(auth_cmd)) |
| 664 | |
| 665 | self.send_cmd(cmd) |
| 666 | |
| 667 | def __get_cap_cnt(self, cap, pt, cnt): |
| 668 | handles = [] |
| 669 | fmt = '>HII III' |
| 670 | |
| 671 | cmd = struct.pack(fmt, |
| 672 | TPM2_ST_NO_SESSIONS, |
| 673 | struct.calcsize(fmt), |
| 674 | TPM2_CC_GET_CAPABILITY, |
| 675 | cap, pt, cnt) |
| 676 | |
| 677 | rsp = self.send_cmd(cmd)[10:] |
| 678 | more_data, cap, cnt = struct.unpack('>BII', rsp[:9]) |
| 679 | rsp = rsp[9:] |
| 680 | |
| 681 | for i in xrange(0, cnt): |
| 682 | handle = struct.unpack('>I', rsp[:4])[0] |
| 683 | handles.append(handle) |
| 684 | rsp = rsp[4:] |
| 685 | |
| 686 | return handles, more_data |
| 687 | |
| 688 | def get_cap(self, cap, pt): |
| 689 | handles = [] |
| 690 | |
| 691 | more_data = True |
| 692 | while more_data: |
| 693 | next_handles, more_data = self.__get_cap_cnt(cap, pt, 1) |
| 694 | handles += next_handles |
| 695 | pt += 1 |
| 696 | |
| 697 | return handles |