diff --git a/test/test_utils.py b/test/test_utils.py index e7da54ca..e4b8b4e8 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -5,6 +5,7 @@ from tpm2_pytss import * from tpm2_pytss.internal.crypto import _generate_seed, private_to_key, public_to_key from tpm2_pytss.utils import * +from tpm2_pytss.internal.templates import _ek from .TSS2_BaseTest import TSS2_EsapiTest from cryptography.hazmat.primitives import hashes @@ -101,6 +102,27 @@ -----END EC PRIVATE KEY----- """ +ek_test_template = TPMT_PUBLIC( + type=TPM2_ALG.KEYEDHASH, + nameAlg=TPM2_ALG.SHA256, + objectAttributes=TPMA_OBJECT.FIXEDTPM + | TPMA_OBJECT.FIXEDPARENT + | TPMA_OBJECT.SENSITIVEDATAORIGIN + | TPMA_OBJECT.ADMINWITHPOLICY + | TPMA_OBJECT.RESTRICTED + | TPMA_OBJECT.SIGN_ENCRYPT, + parameters=TPMU_PUBLIC_PARMS( + keyedHashDetail=TPMS_KEYEDHASH_PARMS( + scheme=TPMT_KEYEDHASH_SCHEME( + scheme=TPM2_ALG.HMAC, + details=TPMU_SCHEME_KEYEDHASH( + hmac=TPMS_SCHEME_HASH(hashAlg=TPM2_ALG.SHA256), + ), + ) + ), + ), +) + class TestUtils(TSS2_EsapiTest): def test_generate_seed_rsa(self): @@ -430,6 +452,207 @@ def test_tpm_export_rsa_child_rsa_parent_with_inner_key(self): hashes.SHA256(), ) + def test_create_ek_ecc(self): + nv_read = NVReadEK(self.ectx) + _, ecc_template = create_ek_template("EK-ECC256", nv_read) + _, ecc, _, _, _ = self.ectx.create_primary( + TPM2B_SENSITIVE_CREATE(), ecc_template, ESYS_TR.ENDORSEMENT + ) + + self.assertEqual(ecc.publicArea.type, TPM2_ALG.ECC) + + ecc_nv_nonce = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=0x1C0000B, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=15, + ) + ) + eh = self.ectx.nv_define_space(b"", ecc_nv_nonce, ESYS_TR.OWNER) + self.ectx.nv_write(eh, b"\xFF" * 15) + nv_read = NVReadEK(self.ectx) + _, ecc_nonce_template = create_ek_template("EK-ECC256", nv_read) + _, ecc_nonce, _, _, _ = self.ectx.create_primary( + TPM2B_SENSITIVE_CREATE(), ecc_nonce_template, ESYS_TR.ENDORSEMENT + ) + self.assertNotEqual( + ecc_nonce.publicArea.unique.ecc.x, ecc.publicArea.unique.ecc.x + ) + self.assertNotEqual( + ecc_nonce.publicArea.unique.ecc.y, ecc.publicArea.unique.ecc.y + ) + + def test_create_ek_rsa(self): + nv_read = NVReadEK(self.ectx) + _, rsa_template = create_ek_template("EK-RSA2048", nv_read) + _, rsa, _, _, _ = self.ectx.create_primary( + TPM2B_SENSITIVE_CREATE(), rsa_template, ESYS_TR.ENDORSEMENT + ) + self.assertEqual(rsa.publicArea.type, TPM2_ALG.RSA) + + rsa_nv_nonce = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=0x1C00003, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=127, + ) + ) + rh = self.ectx.nv_define_space(b"", rsa_nv_nonce, ESYS_TR.OWNER) + self.ectx.nv_write(rh, b"\xFF" * 127) + nv_read = NVReadEK(self.ectx) + _, rsa_nonce_template = create_ek_template("EK-RSA2048", nv_read) + _, rsa_nonce, _, _, _ = self.ectx.create_primary( + TPM2B_SENSITIVE_CREATE(), rsa_nonce_template, ESYS_TR.ENDORSEMENT + ) + self.assertNotEqual(rsa_nonce.publicArea.unique.rsa, rsa.publicArea.unique.rsa) + + def test_create_ek_template(self): + tb = ek_test_template.marshal() + nv_template = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=0x1C0000C, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(tb), + ) + ) + tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) + self.ectx.nv_write(tnh, tb) + nv_read = NVReadEK(self.ectx) + _, templpub = create_ek_template("EK-ECC256", nv_read) + _, templ, _, _, _ = self.ectx.create_primary( + TPM2B_SENSITIVE_CREATE(), templpub, ESYS_TR.ENDORSEMENT + ) + self.assertEqual(templ.publicArea.type, TPM2_ALG.KEYEDHASH) + + def test_create_ek_bad(self): + nv_read = NVReadEK(self.ectx) + with self.assertRaises(ValueError) as e: + create_ek_template("EK-DES", nv_read) + self.assertEqual(str(e.exception), "unknown EK type EK-DES") + + def test_create_ek_high_rsa2048(self): + nv_read = NVReadEK(self.ectx) + with self.assertRaises(ValueError) as e: + create_ek_template("EK-HIGH-RSA2048", nv_read) + self.assertEqual(str(e.exception), "no certificate found for EK-HIGH-RSA2048") + + cert_index, def_template = _ek.EK_HIGH_RSA2048 + nv_cert = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=cert_index, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(b"I am a certificate"), + ) + ) + cnh = self.ectx.nv_define_space(b"", nv_cert, ESYS_TR.OWNER) + self.ectx.nv_write(cnh, b"I am a certificate") + nv_read = NVReadEK(self.ectx) + cert, template = create_ek_template("EK-HIGH-RSA2048", nv_read) + self.assertEqual(cert, b"I am a certificate") + self.assertEqual(template.marshal(), def_template.marshal()) + + tb = ek_test_template.marshal() + nv_template = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=cert_index + 1, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(tb), + ) + ) + tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) + self.ectx.nv_write(tnh, tb) + nv_read = NVReadEK(self.ectx) + cert, template = create_ek_template("EK-HIGH-RSA2048", nv_read) + self.assertEqual(cert, b"I am a certificate") + self.assertEqual( + template.marshal(), TPM2B_PUBLIC(publicArea=ek_test_template).marshal() + ) + + def test_create_ek_high_ecc256(self): + nv_read = NVReadEK(self.ectx) + with self.assertRaises(ValueError) as e: + create_ek_template("EK-HIGH-ECC256", nv_read) + self.assertEqual(str(e.exception), "no certificate found for EK-HIGH-ECC256") + + cert_index, def_template = _ek.EK_HIGH_ECC256 + nv_cert = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=cert_index, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(b"I am a certificate"), + ) + ) + cnh = self.ectx.nv_define_space(b"", nv_cert, ESYS_TR.OWNER) + self.ectx.nv_write(cnh, b"I am a certificate") + nv_read = NVReadEK(self.ectx) + cert, template = create_ek_template("EK-HIGH-ECC256", nv_read) + self.assertEqual(cert, b"I am a certificate") + self.assertEqual(template.marshal(), def_template.marshal()) + + tb = ek_test_template.marshal() + nv_template = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=cert_index + 1, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(tb), + ) + ) + tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) + self.ectx.nv_write(tnh, tb) + nv_read = nv_read_ek(self.ectx) + cert, template = create_ek_template("EK-HIGH-ECC256", nv_read) + self.assertEqual(cert, b"I am a certificate") + self.assertEqual( + template.marshal(), TPM2B_PUBLIC(publicArea=ek_test_template).marshal() + ) + + def test_create_ek_high_ecc256(self): + nv_read = NVReadEK(self.ectx) + with self.assertRaises(ValueError) as e: + create_ek_template("EK-HIGH-ECC384", nv_read) + self.assertEqual(str(e.exception), "no certificate found for EK-HIGH-ECC384") + + cert_index, def_template = _ek.EK_HIGH_ECC384 + nv_cert = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=cert_index, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(b"I am a certificate"), + ) + ) + cnh = self.ectx.nv_define_space(b"", nv_cert, ESYS_TR.OWNER) + self.ectx.nv_write(cnh, b"I am a certificate") + nv_read = NVReadEK(self.ectx) + cert, template = create_ek_template("EK-HIGH-ECC384", nv_read) + self.assertEqual(cert, b"I am a certificate") + self.assertEqual(template.marshal(), def_template.marshal()) + + tb = ek_test_template.marshal() + nv_template = TPM2B_NV_PUBLIC( + nvPublic=TPMS_NV_PUBLIC( + nvIndex=cert_index + 1, + nameAlg=TPM2_ALG.SHA256, + attributes=TPMA_NV.AUTHWRITE | TPMA_NV.AUTHREAD, + dataSize=len(tb), + ) + ) + tnh = self.ectx.nv_define_space(b"", nv_template, ESYS_TR.OWNER) + self.ectx.nv_write(tnh, tb) + nv_read = NVReadEK(self.ectx) + cert, template = create_ek_template("EK-HIGH-ECC384", nv_read) + self.assertEqual(cert, b"I am a certificate") + self.assertEqual( + template.marshal(), TPM2B_PUBLIC(publicArea=ek_test_template).marshal() + ) + if __name__ == "__main__": unittest.main() diff --git a/tpm2_pytss/internal/templates.py b/tpm2_pytss/internal/templates.py new file mode 100644 index 00000000..44c0af23 --- /dev/null +++ b/tpm2_pytss/internal/templates.py @@ -0,0 +1,214 @@ +from collections import namedtuple +from ..types import ( + TPMT_SYM_DEF_OBJECT, + TPMU_SYM_KEY_BITS, + TPMU_SYM_MODE, + TPM2B_PUBLIC, + TPMT_PUBLIC, + TPMU_PUBLIC_PARMS, + TPMS_RSA_PARMS, + TPMT_RSA_SCHEME, + TPMU_PUBLIC_ID, + TPMS_ECC_PARMS, + TPMT_ECC_SCHEME, + TPMT_KDF_SCHEME, + TPMS_ECC_POINT, +) +from ..constants import ( + TPM2_ALG, + TPMA_OBJECT, + TPM2_ECC, +) + + +class _ek: + _ek_tuple = namedtuple("_ek_tuple", ["cert_index", "ek_template"]) + _low_symmetric = TPMT_SYM_DEF_OBJECT( + algorithm=TPM2_ALG.AES, + keyBits=TPMU_SYM_KEY_BITS(aes=128), + mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), + ) + _low_attrs = ( + TPMA_OBJECT.FIXEDTPM + | TPMA_OBJECT.FIXEDPARENT + | TPMA_OBJECT.SENSITIVEDATAORIGIN + | TPMA_OBJECT.ADMINWITHPOLICY + | TPMA_OBJECT.RESTRICTED + | TPMA_OBJECT.DECRYPT + ) + _low_policy = b"\x83q\x97gD\x84\xb3\xf8\x1a\x90\xcc\x8dF\xa5\xd7$\xfdR\xd7n\x06R\x0bd\xf2\xa1\xda\x1b3\x14i\xaa" + _ek_rsa2048_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.RSA, + nameAlg=TPM2_ALG.SHA256, + objectAttributes=_low_attrs, + authPolicy=_low_policy, + parameters=TPMU_PUBLIC_PARMS( + rsaDetail=TPMS_RSA_PARMS( + symmetric=_low_symmetric, + scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), + keyBits=2048, + ), + ), + unique=TPMU_PUBLIC_ID(rsa=b"\x00" * 256), + ) + ) + _ek_ecc256_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.ECC, + nameAlg=TPM2_ALG.SHA256, + objectAttributes=_low_attrs, + authPolicy=_low_policy, + parameters=TPMU_PUBLIC_PARMS( + eccDetail=TPMS_ECC_PARMS( + symmetric=_low_symmetric, + scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), + curveID=TPM2_ECC.NIST_P256, + kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), + ) + ), + unique=TPMU_PUBLIC_ID(ecc=TPMS_ECC_POINT(x=b"\x00" * 32, y=b"\x00" * 32)), + ) + ) + _high_attrs = ( + TPMA_OBJECT.FIXEDTPM + | TPMA_OBJECT.FIXEDPARENT + | TPMA_OBJECT.SENSITIVEDATAORIGIN + | TPMA_OBJECT.USERWITHAUTH + | TPMA_OBJECT.ADMINWITHPOLICY + | TPMA_OBJECT.RESTRICTED + | TPMA_OBJECT.DECRYPT + ) + _256_symmetric = TPMT_SYM_DEF_OBJECT( + algorithm=TPM2_ALG.AES, + keyBits=TPMU_SYM_KEY_BITS(aes=256), + mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), + ) + _sm4_symmetric = TPMT_SYM_DEF_OBJECT( + algorithm=TPM2_ALG.SM4, + keyBits=TPMU_SYM_KEY_BITS(sm4=128), + mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB), + ) + _sha256_policy = b"\xca=\n\x99\xa2\xb99\x06\xf7\xa34$\x14\xef\xcf\xb3\xa3\x85\xd4L\xd1\xfdE\x90\x89\xd1\x9bPq\xc0\xb7\xa0" + _sha384_policy = b"\xb2n}(\xd1\x1aP\xbcS\xd8\x82\xbc\xf5\xfd:\x1a\x07AH\xbb5\xd3\xb4\xe4\xcb\x1c\n\xd9\xbd\xe4\x19\xca\xcbG\xba\ti\x96F\x15\x0f\x9f\xc0\x00\xf3\xf8\x0e\x12" + _sha512_policy = b'\xb8"\x1c\xa6\x9e\x85P\xa4\x91M\xe3\xfa\xa6\xa1\x8c\x07,\xc0\x12\x08\x07:\x92\x8d]f\xd5\x9e\xf7\x9eI\xa4)\xc4\x1ak&\x95q\xd5~\xdb%\xfb\xdb\x188BV\x08\xb4\x13\xcdaj_m\xb5\xb6\x07\x1a\xf9\x9b\xea' + _sm3_256_policy = b"\x16x`\xa3_,\\5g\xf9\xc9'\xacV\xc02\xf3\xb3\xa6F/\x8d\x03y\x98\xe7\xa1\x0fw\xfaEJ" + _ek_high_rsa2048_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.RSA, + nameAlg=TPM2_ALG.SHA256, + objectAttributes=_high_attrs, + authPolicy=_sha256_policy, + parameters=TPMU_PUBLIC_PARMS( + rsaDetail=TPMS_RSA_PARMS( + symmetric=_low_symmetric, + scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), + keyBits=2048, + ), + ), + ) + ) + _ek_high_ecc256_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.ECC, + nameAlg=TPM2_ALG.SHA256, + objectAttributes=_high_attrs, + authPolicy=_sha256_policy, + parameters=TPMU_PUBLIC_PARMS( + eccDetail=TPMS_ECC_PARMS( + symmetric=_low_symmetric, + scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), + curveID=TPM2_ECC.NIST_P256, + kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), + ), + ), + ), + ) + _ek_high_ecc384_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.ECC, + nameAlg=TPM2_ALG.SHA384, + objectAttributes=_high_attrs, + authPolicy=_sha384_policy, + parameters=TPMU_PUBLIC_PARMS( + eccDetail=TPMS_ECC_PARMS( + symmetric=_256_symmetric, + scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), + curveID=TPM2_ECC.NIST_P384, + kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), + ), + ), + ), + ) + _ek_high_ecc521_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.ECC, + nameAlg=TPM2_ALG.SHA512, + objectAttributes=_high_attrs, + authPolicy=_sha512_policy, + parameters=TPMU_PUBLIC_PARMS( + eccDetail=TPMS_ECC_PARMS( + symmetric=_256_symmetric, + scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), + curveID=TPM2_ECC.NIST_P521, + kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), + ), + ), + ), + ) + _ek_high_eccsm2p521_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.ECC, + nameAlg=TPM2_ALG.SM3_256, + objectAttributes=_high_attrs, + authPolicy=_sm3_256_policy, + parameters=TPMU_PUBLIC_PARMS( + eccDetail=TPMS_ECC_PARMS( + symmetric=_sm4_symmetric, + scheme=TPMT_ECC_SCHEME(scheme=TPM2_ALG.NULL), + curveID=TPM2_ECC.SM2_P256, + kdf=TPMT_KDF_SCHEME(scheme=TPM2_ALG.NULL), + ), + ), + ), + ) + _ek_high_rsa3072_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.RSA, + nameAlg=TPM2_ALG.SHA384, + objectAttributes=_high_attrs, + authPolicy=_sha384_policy, + parameters=TPMU_PUBLIC_PARMS( + rsaDetail=TPMS_RSA_PARMS( + symmetric=_256_symmetric, + scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), + keyBits=3072, + ), + ), + ) + ) + _ek_high_rsa4096_template = TPM2B_PUBLIC( + publicArea=TPMT_PUBLIC( + type=TPM2_ALG.RSA, + nameAlg=TPM2_ALG.SHA384, + objectAttributes=_high_attrs, + authPolicy=_sha384_policy, + parameters=TPMU_PUBLIC_PARMS( + rsaDetail=TPMS_RSA_PARMS( + symmetric=_256_symmetric, + scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL), + keyBits=3072, + ), + ), + ) + ) + + EK_RSA2048 = _ek_tuple(0x01C00002, _ek_rsa2048_template) + EK_ECC256 = _ek_tuple(0x01C0000A, _ek_ecc256_template) + EK_HIGH_RSA2048 = _ek_tuple(0x01C00012, _ek_high_rsa2048_template) + EK_HIGH_ECC256 = _ek_tuple(0x01C00014, _ek_high_ecc256_template) + EK_HIGH_ECC384 = _ek_tuple(0x01C00016, _ek_high_ecc384_template) + EK_HIGH_ECC521 = _ek_tuple(0x01C00018, _ek_high_ecc521_template) + EK_HIGH_ECCSM2P521 = _ek_tuple(0x01C0001A, _ek_high_eccsm2p521_template) + EK_HIGH_RSA3072 = _ek_tuple(0x01C0001C, _ek_high_rsa3072_template) + EK_HIGH_RSA4096 = _ek_tuple(0x01C0001E, _ek_high_rsa4096_template) diff --git a/tpm2_pytss/utils.py b/tpm2_pytss/utils.py index 1c6fc2d3..631888d5 100644 --- a/tpm2_pytss/utils.py +++ b/tpm2_pytss/utils.py @@ -10,10 +10,21 @@ _hmac, ) from .types import * +from .ESAPI import ESAPI +from .constants import ( + ESYS_TR, + TPM2_CAP, + TPM2_PT_NV, + TPM2_ECC, + TPM2_PT, + TPM2_RH, +) +from .internal.templates import _ek +from .TSS2_Exception import TSS2_Exception from cryptography.hazmat.primitives import constant_time as ct from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend -from typing import Optional, Tuple +from typing import Optional, Tuple, Callable import secrets @@ -226,3 +237,160 @@ def unwrap( ) return s + + +class NoSuchIndex(Exception): + """NV index is not defined exception + + Args: + index (int): The NV index requested + """ + + def __init__(self, index): + self.index = index + + def __str__(self): + return f"NV index 0x{index:08x} does not exist" + + +class NVReadEK: + """NV read callback to be used with create_ek_template + + Args: + ectx (ESAPI): The ESAPI context for reading from NV areas + auth_handle (ESYS_TR): Handle indicating the source of the authorization. Defaults to the index being read. + session1 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.PASSWORD. + session2 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. + session3 (ESYS_TR): A session for securing the TPM command (optional). Defaults to ESYS_TR.NONE. + """ + + def __init__( + self, + ectx: ESAPI, + auth_handle: ESYS_TR = None, + session1: ESYS_TR = ESYS_TR.PASSWORD, + session2: ESYS_TR = ESYS_TR.NONE, + session3: ESYS_TR = ESYS_TR.NONE, + ): + self._ectx = ectx + self._auth_handle = auth_handle + self._session1 = session1 + self._session2 = session2 + self._session3 = session3 + self._buffer_max = 512 + + more = True + while more: + more, data = self._ectx.get_capability( + TPM2_CAP.TPM_PROPERTIES, + TPM2_PT.FIXED, + 4096, + session1=session2, + session2=session3, + ) + props = data.data.tpmProperties + for p in props: + if p.property == TPM2_PT_NV.BUFFER_MAX: + self._buffer_max = p.value + more = False + break + + def __call__(self, index: Union[int, TPM2_RH]) -> bytes: + try: + nvh = self._ectx.tr_from_tpmpublic( + index, session1=self._session2, session2=self._session3 + ) + except TSS2_Exception as e: + if e.rc == 0x18B: + raise NoSuchIndex(index) + else: + raise e + nvpub, _ = self._ectx.nv_read_public( + nvh, session1=self._session2, session2=self._session3 + ) + nvdata = b"" + left = nvpub.nvPublic.dataSize + while left > 0: + off = nvpub.nvPublic.dataSize - left + size = self._buffer_max if left > self._buffer_max else left + data = self._ectx.nv_read( + nvh, + size, + off, + auth_handle=self._auth_handle, + session1=self._session1, + session2=self._session2, + session3=self._session3, + ) + nvdata = nvdata + bytes(data) + left = left - len(data) + + return nvdata + + +def create_ek_template( + ektype: str, nv_read_cb: Callable[[Union[int, TPM2_RH]], bytes] +) -> Tuple[bytes, TPM2B_PUBLIC]: + """Creates an Endorsenment Key template which when created matches the EK certificate + + The template is created according to TCG EK Credential Profile For TPM Family 2.0: + - https://trustedcomputinggroup.org/resource/tcg-ek-credential-profile-for-tpm-family-2-0/ + + Args: + ektype (str): The endoresment key type. + nv_read_cb (Callable[Union[int, TPM2_RH]]): The callback to use for reading NV areas. + + None: + nv_read_cb MUST raise a NoSuchIndex exception if the NV index isn't defined. + + Returns: + A tuple of the certificate (can be None) and the template as a TPM2B_PUBLIC instance + + Raises: + ValueError: If ektype is unknown or if a high range certificate is requested but not found. + """ + + en = ektype.replace("-", "_") + if not hasattr(_ek, en): + raise ValueError(f"unknown EK type {ektype}") + (cert_index, template) = getattr(_ek, en) + + nonce_index = None + if ektype in ("EK-RSA2048", "EK-ECC256"): + nonce_index = cert_index + 1 + template_index = cert_index + 2 + else: + template_index = cert_index + 1 + + cert = None + try: + cert = nv_read_cb(cert_index) + except NoSuchIndex: + if ektype not in ("EK-RSA2048", "EK-ECC256"): + raise ValueError(f"no certificate found for {ektype}") + + try: + templb = nv_read_cb(template_index) + tt, _ = TPMT_PUBLIC.unmarshal(templb) + template = TPM2B_PUBLIC(publicArea=tt) + except NoSuchIndex: + pass + + nonce = None + if nonce_index: + try: + nonce = nv_read_cb(nonce_index) + except NoSuchIndex: + pass + + if nonce and template.publicArea.type == TPM2_ALG.RSA: + template.publicArea.unique.rsa = nonce + ((256 - len(nonce)) * b"\x00") + elif ( + nonce + and template.publicArea.type == TPM2_ALG.ECC + and template.publicArea.parameters.eccDetail.curveID == TPM2_ECC.NIST_P256 + ): + template.publicArea.unique.ecc.x = nonce + ((32 - len(nonce)) * b"\x00") + template.publicArea.unique.ecc.y = b"\x00" * 32 + + return cert, template