blob: 343fe9da34df91dd8173236d158c42f5b494cc0b [file] [log] [blame] [edit]
# Copyright 2025 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module for testing TPM2 commands."""
import struct
import cbor
import subcmd
import x509keymint
TPM_SU_CLEAR = 0x0000
TPM_SU_STATE = 0x0001
SB_DeviceGetHardwareInfo = 0x11
SB_DeviceAddRngEntropy = 0x12
SB_DeviceGenerateKey = 0x13
SB_DeviceImportKey = 0x14
SB_DeviceImportWrappedKey = 0x15
SB_DeviceUpgradeKey = 0x16
SB_DeviceDeleteKey = 0x17
SB_DeviceDeleteAllKeys = 0x18
SB_DeviceDestroyAttestationIds = 0x19
SB_DeviceBegin = 0x1A
SB_DeviceEarlyBootEnded = 0x1C
SB_DeviceConvertStorageKeyToEphemeral = 0x1D
SB_DeviceGetKeyCharacteristics = 0x1E
SB_OperationUpdateAad = 0x31
SB_OperationUpdate = 0x32
SB_OperationFinish = 0x33
SB_OperationAbort = 0x34
SB_RpcGetHardwareInfo = 0x41
SB_RpcGenerateEcdsaP256KeyPair = 0x42
SB_RpcGenerateCertificateRequest = 0x43
SB_RpcGenerateCertificateV2Request = 0x44
SB_SharedSecretGetSharedSecretParameters = 0x51
SB_SharedSecretComputeSharedSecret = 0x52
SB_SecureClockGenerateTimeStamp = 0x61
SB_GetRootOfTrustChallenge = 0x71
SB_GetRootOfTrust = 0x72
SB_SendRootOfTrust = 0x73
SB_SetHalInfo = 0x81
SB_SetBootInfo = 0x82
SB_SetAttestationIds = 0x83
SB_SetHalVersion = 0x84
SB_SetAdditionalAttestationInfo = 0x91
SB_GetDiceChain = 0xA0
SB_SetHalBootInfo = 0xA1
SB_SetStrongboxState = 0xA2
# Keymint tag types
KM_TAG_TYPE_INVALID = 0
KM_TAG_TYPE_ENUM = 1
KM_TAG_TYPE_ENUM_REP = 2
KM_TAG_TYPE_UINT = 3
KM_TAG_TYPE_UINT_REP = 4
KM_TAG_TYPE_ULONG = 5
KM_TAG_TYPE_DATE = 6
KM_TAG_TYPE_BOOL = 7
KM_TAG_TYPE_BIGNUM = 8
KM_TAG_TYPE_BYTES = 9
KM_TAG_TYPE_ULONG_REP = 10
KM_TAG_TYPE_SHIFT = 28
KM_TYPE_INVALID = KM_TAG_TYPE_INVALID << KM_TAG_TYPE_SHIFT
KM_TYPE_ENUM = KM_TAG_TYPE_ENUM << KM_TAG_TYPE_SHIFT
KM_TYPE_ENUM_REP = KM_TAG_TYPE_ENUM_REP << KM_TAG_TYPE_SHIFT
KM_TYPE_UINT = KM_TAG_TYPE_UINT << KM_TAG_TYPE_SHIFT
KM_TYPE_UINT_REP = KM_TAG_TYPE_UINT_REP << KM_TAG_TYPE_SHIFT
KM_TYPE_ULONG = KM_TAG_TYPE_ULONG << KM_TAG_TYPE_SHIFT
KM_TYPE_DATE = KM_TAG_TYPE_DATE << KM_TAG_TYPE_SHIFT
KM_TYPE_BOOL = KM_TAG_TYPE_BOOL << KM_TAG_TYPE_SHIFT
KM_TYPE_BIGNUM = KM_TAG_TYPE_BIGNUM << KM_TAG_TYPE_SHIFT
KM_TYPE_BYTES = KM_TAG_TYPE_BYTES << KM_TAG_TYPE_SHIFT
KM_TYPE_ULONG_REP = KM_TAG_TYPE_ULONG_REP << KM_TAG_TYPE_SHIFT
KM_TAG_TYPE_MASK = 0xF << KM_TAG_TYPE_SHIFT
# Hardware-enforced tags
KM_TAG_PURPOSE = KM_TYPE_ENUM_REP | 1
KM_TAG_ALGORITHM = KM_TYPE_ENUM | 2
KM_TAG_KEY_SIZE = KM_TYPE_UINT | 3
KM_TAG_BLOCK_MODE = KM_TYPE_ENUM_REP | 4
KM_TAG_DIGEST = KM_TYPE_ENUM_REP | 5
KM_TAG_PADDING = KM_TYPE_ENUM_REP | 6
KM_TAG_CALLER_NONCE = KM_TYPE_BOOL | 7
KM_TAG_MIN_MAC_LENGTH = KM_TYPE_UINT | 8
KM_TAG_EC_CURVE = KM_TYPE_ENUM | 10
KM_TAG_RSA_PUBLIC_EXPONENT = KM_TYPE_ULONG | 200
KM_TAG_INCLUDE_UNIQUE_ID = KM_TYPE_BOOL | 202
KM_TAG_RSA_OAEP_MGF_DIGEST = KM_TYPE_ENUM_REP | 203
KM_TAG_BOOTLOADER_ONLY = KM_TYPE_BOOL | 302
KM_TAG_ROLLBACK_RESISTANCE = KM_TYPE_BOOL | 303
KM_TAG_HARDWARE_TYPE = KM_TYPE_ENUM | 304
KM_TAG_EARLY_BOOT_ONLY = KM_TYPE_BOOL | 305
KM_TAG_MAX_USES_PER_BOOT = KM_TYPE_UINT | 404
KM_TAG_USAGE_COUNT_LIMIT = KM_TYPE_UINT | 405
KM_TAG_USER_SECURE_ID = KM_TYPE_ULONG_REP | 502
KM_TAG_NO_AUTH_REQUIRED = KM_TYPE_BOOL | 503
KM_TAG_USER_AUTH_TYPE = KM_TYPE_ENUM | 504
KM_TAG_AUTH_TIMEOUT = KM_TYPE_UINT | 505
KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_TYPE_BOOL | 507
KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_TYPE_BOOL | 508
KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_TYPE_BOOL | 509
KM_TAG_ORIGIN = KM_TYPE_ENUM | 702
KM_TAG_OS_VERSION = KM_TYPE_UINT | 705
KM_TAG_OS_PATCHLEVEL = KM_TYPE_UINT | 706
KM_TAG_UNIQUE_ID = KM_TYPE_BYTES | 707
KM_TAG_VENDOR_PATCHLEVEL = KM_TYPE_UINT | 718
KM_TAG_BOOT_PATCHLEVEL = KM_TYPE_UINT | 719
KM_TAG_DEVICE_UNIQUE_ATTESTATION = KM_TYPE_BOOL | 720
KM_TAG_IDENTITY_CREDENTIAL_KEY = KM_TYPE_BOOL | 721
KM_TAG_STORAGE_KEY = KM_TYPE_BOOL | 722
KM_TAG_MAC_LENGTH = KM_TYPE_UINT | 1003
KM_TAG_MAX_BOOT_LEVEL = KM_TYPE_UINT | 1010
# Software-enforced tags
KM_TAG_ACTIVE_DATETIME = KM_TYPE_DATE | 400
KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_TYPE_DATE | 401
KM_TAG_USAGE_EXPIRE_DATETIME = KM_TYPE_DATE | 402
KM_TAG_USER_ID = KM_TYPE_UINT | 501
KM_TAG_ALLOW_WHILE_ON_BODY = KM_TYPE_BOOL | 506
KM_TAG_CREATION_DATETIME = KM_TYPE_DATE | 701
KM_TAG_ATTESTATION_APPLICATION_ID = KM_TYPE_BYTES | 709
# Input-only / special tags
KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_TYPE_UINT | 403
KM_TAG_APPLICATION_ID = KM_TYPE_BYTES | 601
KM_TAG_APPLICATION_DATA = KM_TYPE_BYTES | 700
KM_TAG_ROOT_OF_TRUST = KM_TYPE_BYTES | 704
KM_TAG_ATTESTATION_CHALLENGE = KM_TYPE_BYTES | 708
KM_TAG_ATTESTATION_ID_BRAND = KM_TYPE_BYTES | 710
KM_TAG_ATTESTATION_ID_DEVICE = KM_TYPE_BYTES | 711
KM_TAG_ATTESTATION_ID_PRODUCT = KM_TYPE_BYTES | 712
KM_TAG_ATTESTATION_ID_SERIAL = KM_TYPE_BYTES | 713
KM_TAG_ATTESTATION_ID_IMEI = KM_TYPE_BYTES | 714
KM_TAG_ATTESTATION_ID_MEID = KM_TYPE_BYTES | 715
KM_TAG_ATTESTATION_ID_MANUFACTURER = KM_TYPE_BYTES | 716
KM_TAG_ATTESTATION_ID_MODEL = KM_TYPE_BYTES | 717
KM_TAG_ATTESTATION_ID_SECOND_IMEI = KM_TYPE_BYTES | 723
KM_TAG_MODULE_HASH = KM_TYPE_BYTES | 724
KM_TAG_ASSOCIATED_DATA = KM_TYPE_BYTES | 1000
KM_TAG_NONCE = KM_TYPE_BYTES | 1001
KM_TAG_RESET_SINCE_ID_ROTATION = KM_TYPE_BOOL | 1004
KM_TAG_CONFIRMATION_TOKEN = KM_TYPE_BYTES | 1005
KM_TAG_CERTIFICATE_SERIAL = KM_TYPE_BIGNUM | 1006
KM_TAG_CERTIFICATE_SUBJECT = KM_TYPE_BYTES | 1007
KM_TAG_CERTIFICATE_NOT_BEFORE = KM_TYPE_DATE | 1008
KM_TAG_CERTIFICATE_NOT_AFTER = KM_TYPE_DATE | 1009
KM_ALG_NONE = 0
KM_ALG_RSA = 1
KM_ALG_EC = 3
KM_ALG_AES = 32
KM_ALG_TDES = 33
KM_ALG_HMAC = 128
KM_PURPOSE_ENCRYPT = 0
KM_PURPOSE_DECRYPT = 1
KM_PURPOSE_SIGN = 2
KM_PURPOSE_VERIFY = 3
KM_PURPOSE_WRAP_KEY = 5
KM_PURPOSE_AGREE_KEY = 6
KM_PURPOSE_ATTEST_KEY = 7
KM_SECURITY_SOFTWARE = 0
KM_SECURITY_TRUSTED_ENVIRONMENT = 1
KM_SECURITY_STRONGBOX = 2
KM_SECURITY_KEYSTORE = 100
KM_ORIGIN_GENERATED = 0
KM_ORIGIN_DERIVED = 1
KM_ORIGIN_IMPORTED = 2
KM_ORIGIN_RESERVED = 3
KM_ORIGIN_SECURELY_IMPORTED = 4
KM_DIGEST_NONE = 0
KM_DIGEST_MD5 = 1
KM_DIGEST_SHA1 = 2
KM_DIGEST_SHA_2_224 = 3
KM_DIGEST_SHA_2_256 = 4
KM_DIGEST_SHA_2_384 = 5
KM_DIGEST_SHA_2_512 = 6
def U32(val: int):
return val.to_bytes(4, byteorder="little")
def U64(val: int):
return val.to_bytes(8, byteorder="little")
def Tag(tag: int, value):
tag_type = tag & KM_TAG_TYPE_MASK
tag_val = tag & ~KM_TAG_TYPE_MASK
if tag_type in [
KM_TYPE_ENUM,
KM_TYPE_ENUM_REP,
KM_TYPE_UINT,
KM_TYPE_UINT_REP,
]:
if not isinstance(value, int):
print(f"Tag {tag_val} Expected int got {type(value)}, {value}")
return U32(tag) + U32(value)
if tag_type in [KM_TYPE_BIGNUM, KM_TYPE_BYTES]:
if not isinstance(value, bytes):
print(f"Tag {tag_val} Expected bytes got {type(value)}, {value}")
# Encode length into tag and pad value to 32-bit
return (
U32(tag | (len(value) << 16))
+ value
+ bytes((4 - len(value) % 4) % 4)
)
if tag_type in [KM_TYPE_DATE, KM_TYPE_ULONG, KM_TYPE_ULONG_REP]:
if not isinstance(value, int):
print(f"Tag {tag_val} Expected int got {type(value)}, {value}")
return U32(tag) + U64(value)
if tag_type == KM_TYPE_BOOL:
return U32(tag)
print(f"Invalid tag type: {tag_type}")
return None
def tpm2_startup(tpm, state):
"""Send TPM2_Startup command
Args:
tpm: a tpm object used to communicate with the device
state: TPM_SU_CLEAR / TPM_SU_STATE
Raises:
subcmd.TpmTestError: on unexpected target responses
"""
startup = [
0x80,
0x01, # TPM_ST_NO_SESSIONS
0x00,
0x00,
0x00,
0x0C, # commandSize = 12
0x00,
0x00,
0x01,
0x44, # TPM_CC_Startup
0x00,
0x00, # TPM_SU_CLEAR / TPM_SU_STATE
]
startup[10:12] = state.to_bytes(2, byteorder="big")
cmd = bytes(startup)
response = tpm.command(cmd)
return response
def tpm2_shutdown(tpm, state):
"""Send TPM2_Shutdown command
Args:
tpm: a tpm object used to communicate with the device
state: TPM_SU_CLEAR / TPM_SU_STATE
Raises:
subcmd.TpmTestError: on unexpected target responses
"""
shutdown = [
0x80,
0x01, # tag: TPM_ST_NO_SESSIONS
0x00,
0x00,
0x00,
0x0C, # size:
0x00,
0x00,
0x01,
0x45, # command: TPM_CC_Shutdown
# ======
0x00,
0x00, # shutdown type: TPM_SU_STATE
]
shutdown[10:12] = state.to_bytes(2, byteorder="big")
cmd = bytes(shutdown)
response = tpm.command(cmd)
return response
def wrap_sb_command(subcmd_code, cmd_body):
"""Wrap TPM command into extension command header"""
return (
struct.pack(
">H2IH",
0x8001,
len(cmd_body) + struct.calcsize(">H2IH"),
0x20000001,
subcmd_code,
)
+ cmd_body
)
def unwrap_ext_response(self, expected_subcmd, response):
"""Verify basic validity and strip off TPM extended command header.
Get the response generated by the device, as it came off the wire,
verify that header fields match expectations, then strip off the
extension command header and return the payload to the caller.
Args:
expected_subcmd: an int, up to 16 bits in size, the extension
command this response is supposed to be for.
response: a binary string, the actual response received
over the wire.
Returns:
the binary string of the response payload,
if validation succeeded.
Raises:
subcmd.TpmTestError: in case there are any validation problems,
the error message describes the problem.
"""
header_size = struct.calcsize(">H2IH")
tag, size, cmd, sub = struct.unpack(">H2IH", response[:header_size])
if tag != 0x8001:
raise subcmd.TpmTestError("Wrong response tag: %4.4x" % tag)
if cmd:
raise subcmd.TpmTestError(
"Unexpected response command" " field: %8.8x" % cmd
)
if sub != expected_subcmd:
raise subcmd.TpmTestError(
"Unexpected response subcommand" " field: %2.2x" % sub
)
if size != len(response):
raise subcmd.TpmTestError(
"Size mismatch: header %d, actual %d" % (size, len(response))
)
return response[header_size:]
def sb_GetDiceChain(tpm):
print("Calling GetDiceChain")
w_rsp = tpm.command(wrap_sb_command(SB_GetDiceChain, b""))
return tpm.unwrap_ext_response(SB_GetDiceChain, w_rsp)
def sb_GenerateEcdsaP256KeyPair(tpm):
print("Calling GenerateEcdsaP256KeyPair")
w_rsp = tpm.command(wrap_sb_command(SB_RpcGenerateEcdsaP256KeyPair, b""))
rsp = tpm.unwrap_ext_response(SB_RpcGenerateEcdsaP256KeyPair, w_rsp)
# key blob's first word is number of the following words for the blob
key_blob_words = int.from_bytes(rsp[:4], "little")
key_blob = rsp[: key_blob_words * 4 + 4]
# next the word with byte size of MAC'ed key comes
maced_key_len = int.from_bytes(
rsp[key_blob_words * 4 + 4 : key_blob_words * 4 + 8], "little"
)
# and the MAC'ed key itself
maced_key = rsp[
key_blob_words * 4 + 8 : key_blob_words * 4 + 8 + maced_key_len
]
return key_blob, maced_key
def vc_SetStrongboxState(tpm, state: int):
cmd = state.to_bytes(1, "little")
print("vc_SetStrongboxState: ", cmd.hex())
rsp = tpm.command(tpm.wrap_ext_command(subcmd.SET_STRONGBOX_STATE, cmd))
return tpm.unwrap_ext_response(subcmd.SET_STRONGBOX_STATE, rsp)
def sb_SetHalBootInfo(
tpm, os_version, os_patchlevel, vendor_patchlevel, boot_patchlevel
):
cmd = (
U32(os_version)
+ U32(os_patchlevel)
+ U32(vendor_patchlevel)
+ U32(boot_patchlevel)
)
print("sb_SetHalBootInfo:", cmd.hex())
w_rsp = tpm.command(wrap_sb_command(SB_SetHalBootInfo, cmd))
return tpm.unwrap_ext_response(SB_SetHalBootInfo, w_rsp)
# Adding size prefix for the byte string and pad to 32-bit aligned
def wrap_bytes(data):
size = len(data)
return U32(len(data)) + data + bytes((4 - size % 4) % 4)
def sb_GenerateCertificateV2Request(
tpm, maced_keys: list, challenge, device_info
):
cmd = (
U32(len(maced_keys))
+ b"".join(wrap_bytes(key) for key in maced_keys)
+ wrap_bytes(challenge)
+ wrap_bytes(device_info)
)
print("GenerateCertificateV2Request:", cmd.hex())
w_rsp = tpm.command(
wrap_sb_command(SB_RpcGenerateCertificateV2Request, cmd)
)
csr = tpm.unwrap_ext_response(SB_RpcGenerateCertificateV2Request, w_rsp)
return csr
# Set the default subject:
# SEQUENCE
# 0x30 <size = 0x1b>
# OBJECT :commonName
# 0x06 <size = 0x03> 0x55 0x04 0x03
# PRINTABLESTRING :Android Keystore Key
# 0x13 <size = 0x14> ...
DEFAULT_ISSUER = bytes.fromhex(
"301B" + "0603550403" + "1314416E64726F6964204B657973746F7265204B6579"
)
def sb_GenerateKey(tpm, key_params, attest_key, issuer_asn1=None):
print("Calling GenerateKey")
if not isinstance(key_params, list) or len(key_params) == 0:
print("Expected list of key parameters")
return None
params = b"".join(key_params)
issuer = DEFAULT_ISSUER if not issuer_asn1 else issuer_asn1
g = U32(len(params) // 4) + params + attest_key + wrap_bytes(issuer)
# attest key is currently ignored
w_rsp = tpm.command(wrap_sb_command(SB_DeviceGenerateKey, g))
rsp = tpm.unwrap_ext_response(SB_DeviceGenerateKey, w_rsp)
key_blob_words = int.from_bytes(rsp[:4], "little")
key_blob = rsp[: key_blob_words * 4 + 4]
# Separating KeyCharacteristics from the blob.
# word 0: total length of key blob in words
# word 1: KM_SECURITY_STRONGBOX
# word 2: length of hw params in words
# .. hw enforced tags
# word n: KM_SECURITY_KEYSTORE
# word n+1: length of sw params in words
# .. sw enforced tags
hw_size = int.from_bytes(rsp[8:12], "little")
sw_size = int.from_bytes(rsp[16 + hw_size * 4 : 20 + hw_size * 4], "little")
if sw_size * 4 > len(key_blob):
print("Incorrect size in blob:", sw_size, hex(sw_size))
key_tags = key_blob[4 : 20 + (hw_size + sw_size) * 4]
cert_size = int.from_bytes(
rsp[key_blob_words * 4 + 4 : key_blob_words * 4 + 8], "little"
)
cert = rsp[key_blob_words * 4 + 8 : key_blob_words * 4 + 8 + cert_size]
return key_blob, key_tags, cert
def sb_test(tpm):
"""Run TPM2 startup/shutdown in a loop tests"""
tpm2_startup(tpm, TPM_SU_CLEAR)
vc_SetStrongboxState(tpm, 1)
w_rsp = tpm.command(wrap_sb_command(SB_DeviceGetHardwareInfo, b""))
rsp = tpm.unwrap_ext_response(SB_DeviceGetHardwareInfo, w_rsp)
print("Get Hardware Info:", rsp.hex())
sb_SetHalBootInfo(tpm, 0x027100, 0x031710, 0x01350245, 0x013502450)
dice_chain = sb_GetDiceChain(tpm)
print("Received DICE chain:", dice_chain.hex())
with open("dice_chain.cbor", "wb") as f:
f.write(dice_chain)
rkp_blob1, maced_key1 = sb_GenerateEcdsaP256KeyPair(tpm)
print(f"RKP key blob[{len(rkp_blob1)}]={rkp_blob1.hex()}")
# save without length prefix and alignment
with open("maced_key.cbor", "wb") as f:
f.write(maced_key1)
cbor.verify_maced_key(maced_key1)
rkp_blob2, maced_key2 = sb_GenerateEcdsaP256KeyPair(tpm)
print(f"RKP key blob[{len(rkp_blob2)}]={rkp_blob2.hex()}")
# save without length prefix and alignment
with open("maced_key2.cbor", "wb") as f:
f.write(maced_key2)
cbor.verify_maced_key(maced_key2)
# {"brand": "Google", "fused": 1, "model": "model", "device": "device",
# "product": "Brya", "os_version": "17", "manufacturer": "Google",
# "vbmeta_digest": h'112233445566778899AABBCCDDEEFF', "boot_patch_level": 20251026,
# "system_patch_level": 20251025, "vendor_patch_level": 20251027,
# "security_level": "strongbox", "vb_state": "green", "bootloader_state": "locked" }
device_info = bytes.fromhex(
"AE656272616E6466476F6F676C6565667573656401656D6F64656C656D6F64656C"
"66646576696365666465766963656770726F647563746442727961"
"6A6F735F76657273696F6E6231376C6D616E756661637475726572"
"66476F6F676C656D76626D6574615F6469676573744F112233445566778899AABBCC"
"DDEEFF70626F6F745F70617463685F6C6576656C1A013501927273797374656D5F70"
"617463685F6C6576656C1A013501917276656E646F725F70617463685F6C6576656C"
"1A01350193"
"6E73656375726974795F6C6576656C697374726F6E67626F78" # "security_level" : "strongbox"
"6876625F737461746565677265656E" # "vb_state":"green"
"70626F6F746C6F616465725F7374617465666C6F636B6564" # "bootloader_state":"locked"
)
csr = sb_GenerateCertificateV2Request(
tpm, [], b"1234567890abcdefghijklmnopqrstuv", device_info
)
with open("csr0.cbor", "wb") as f:
f.write(csr)
cbor.verify_signed_data(csr)
csr = sb_GenerateCertificateV2Request(
tpm, [maced_key1], b"1234567890abcdefghijklmnopqrstuv", device_info
)
with open("csr1.cbor", "wb") as f:
f.write(csr)
cbor.verify_signed_data(csr)
csr = sb_GenerateCertificateV2Request(
tpm,
[maced_key1, maced_key2],
b"1234567890abcdefghijklmnopqrstuv",
device_info,
)
with open("csr2.cbor", "wb") as f:
f.write(csr)
cbor.verify_signed_data(csr)
# Test without attestation key
key_blob, key_tags, cert = sb_GenerateKey(
tpm,
[
Tag(KM_TAG_ALGORITHM, KM_ALG_EC),
Tag(KM_TAG_KEY_SIZE, 256),
Tag(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_256),
Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_512),
Tag(KM_TAG_ALLOW_WHILE_ON_BODY, 0),
Tag(KM_TAG_USER_ID, 0xF00),
Tag(KM_TAG_APPLICATION_ID, b"\xaa\xaa\xaa\xaa"),
Tag(KM_TAG_APPLICATION_DATA, b"\xbb\xbb\xbb\xbb"),
],
b"\x00\x00\x00\x00",
)
print(f"Key blob[{len(key_blob)}]={key_blob.hex()}")
print(f"Key cert[{len(cert)}]={cert.hex()}")
with open("cert_self.der", "wb") as f:
f.write(cert)
x509keymint.verify_certificate(cert)
# Test with attestation key
key_blob, key_tags, cert = sb_GenerateKey(
tpm,
[
Tag(KM_TAG_ALGORITHM, KM_ALG_EC),
Tag(KM_TAG_KEY_SIZE, 256),
Tag(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_256),
Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_512),
Tag(KM_TAG_ALLOW_WHILE_ON_BODY, 0),
Tag(KM_TAG_USER_ID, 0xF00),
Tag(KM_TAG_CERTIFICATE_SUBJECT, DEFAULT_ISSUER),
Tag(
KM_TAG_CERTIFICATE_SERIAL,
b"\x01\x23\x45\x67\x89\xab\xcd\xef01234567",
),
Tag(KM_TAG_APPLICATION_ID, b"\xaa\xaa\xaa\xaa"),
Tag(KM_TAG_APPLICATION_DATA, b"\xbb\xbb\xbb\xbb"),
Tag(KM_TAG_NO_AUTH_REQUIRED, 0),
Tag(KM_TAG_ATTESTATION_CHALLENGE, b"2025-11-05T19:57:14.294Z"),
Tag(KM_TAG_ATTESTATION_APPLICATION_ID, b"com.google.android.gms"),
Tag(KM_TAG_ATTESTATION_ID_BRAND, b"google"),
Tag(KM_TAG_ATTESTATION_ID_DEVICE, b"brya"),
Tag(KM_TAG_ATTESTATION_ID_PRODUCT, b"brya"),
Tag(KM_TAG_ATTESTATION_ID_SERIAL, b"5CD5231RQK"),
Tag(KM_TAG_ATTESTATION_ID_MANUFACTURER, b"Google"),
Tag(KM_TAG_ATTESTATION_ID_MODEL, b"Brya"),
],
rkp_blob1,
)
print(f"Key blob[{len(key_blob)}]={key_blob.hex()}")
print(f"Key cert[{len(cert)}]={cert.hex()}")
with open("cert.der", "wb") as f:
f.write(cert)
x509keymint.verify_certificate(cert)
# expected blob header
expected_tags = (
# KeyCharacteristics
U32(KM_SECURITY_STRONGBOX)
+ U32(21)
+ Tag(KM_TAG_ORIGIN, KM_ORIGIN_GENERATED)
+ Tag(KM_TAG_OS_VERSION, 0x027100)
+ Tag(KM_TAG_OS_PATCHLEVEL, 0x031710)
+ Tag(KM_TAG_VENDOR_PATCHLEVEL, 0x013502450)
+ Tag(KM_TAG_BOOT_PATCHLEVEL, 0x01350245)
+ Tag(KM_TAG_ALGORITHM, KM_ALG_EC)
+ Tag(KM_TAG_KEY_SIZE, 256)
+ Tag(KM_TAG_PURPOSE, KM_PURPOSE_SIGN)
+ Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_256)
+ Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_512)
+ Tag(KM_TAG_NO_AUTH_REQUIRED, 0)
+ U32(KM_SECURITY_KEYSTORE)
+ U32(3)
+ Tag(KM_TAG_ALLOW_WHILE_ON_BODY, 0)
+ Tag(KM_TAG_USER_ID, 0xF00)
)
if key_tags != expected_tags:
print(
f"KeyCharacteristics doesn't match:\nexpected: {expected_tags.hex()}, {len(expected_tags)} bytes\nreceived: {key_tags.hex()} {len(key_tags)} bytes"
)
print("Begin signing")
# Additional parameters for blob authentication for begin()
key_params = U32(8) + (
Tag(KM_TAG_APPLICATION_ID, b"\xaa\xaa\xaa\xaa")
+ Tag(KM_TAG_APPLICATION_DATA, b"\xbb\xbb\xbb\xbb")
+ Tag(KM_TAG_DIGEST, KM_DIGEST_SHA_2_256)
+ Tag(KM_TAG_ALGORITHM, KM_ALG_EC)
)
begin_cmd = U32(KM_PURPOSE_SIGN) + key_blob + key_params
w_rsp = tpm.command(wrap_sb_command(SB_DeviceBegin, begin_cmd))
rsp = tpm.unwrap_ext_response(SB_DeviceBegin, w_rsp)
print("r=", rsp.hex())
operation_id = rsp[-4:]
w_rsp = tpm.command(
wrap_sb_command(
SB_OperationUpdate,
operation_id + U32(32) + b"0123456789ABCDEF0123456789ABCDEF",
)
)
rsp = tpm.unwrap_ext_response(SB_OperationUpdate, w_rsp)
print("r=", rsp.hex())
w_rsp = tpm.command(
wrap_sb_command(SB_OperationFinish, operation_id + U32(0))
)
rsp = tpm.unwrap_ext_response(SB_OperationFinish, w_rsp)
print("r=", rsp.hex())
vc_SetStrongboxState(tpm, 0)
exception_detected = False
try:
vc_SetStrongboxState(tpm, 1)
except subcmd.TpmTestError as tpm_exc:
exception_detected = True
if not exception_detected:
print("Unexpected success in sb_SetStrongboxState")
tpm2_shutdown(tpm, TPM_SU_STATE)