Skip to content

Commit

Permalink
utils: add function to generate an EK
Browse files Browse the repository at this point in the history
Signed-off-by: Erik Larsson <who+github@cnackers.org>
  • Loading branch information
whooo committed Dec 19, 2021
1 parent ba2dd5c commit 7ec6d51
Show file tree
Hide file tree
Showing 3 changed files with 327 additions and 0 deletions.
99 changes: 99 additions & 0 deletions test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,105 @@ def test_tpm_export_rsa_child_rsa_parent_with_inner_key(self):
hashes.SHA256(),
)

def test_create_ek_ecc(self):
nv_read = nv_read_full(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)
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 = nv_read_full(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)
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):
return
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),
),
)
),
),
)
tb = 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)
templpub = create_ek_template(self.ectx)
_, 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 = nv_read_full(self.ectx)
with self.assertRaises(ValueError) as e:
create_ek_template("EK-DES", nv_read)
self.assertEqual(str(e.exception), "unsupported EK type EK-DES")


if __name__ == "__main__":
unittest.main()
111 changes: 111 additions & 0 deletions tpm2_pytss/templates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
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:
_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
)
_sha256_policy = "ca3d0a99a2b93906f7a3342414efcfb3a385d44cd1fd459089d19b5071c0b7a0"
_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 = None
_ek_high_ecc384_template = None
_ek_high_ecc521_template = None
_ek_high_eccsm2p521_template = None
_ek_high_rsa3072_template = None
_ek_high_rsa4096_template = None
# values are (cert nv index, default template)
EK_RSA2048 = (0x01C00002, _ek_rsa2048_template)
EK_ECC256 = (0x01C0000A, _ek_ecc256_template)
EK_HIGH_RSA2048 = (0x01C00012, _ek_high_rsa2048_template)
EK_HIGH_ECC256 = (0x01C00014, _ek_high_ecc256_template)
EK_HIGH_ECC384 = (0x01C00016, _ek_high_ecc384_template)
EK_HIGH_ECC521 = (0x01C00018, _ek_high_ecc521_template)
EK_HIGH_ECCSM2P521 = (0x01C0001A, _ek_high_eccsm2p521_template)
EK_HIGH_RSA3072 = (0x01C0001C, _ek_high_rsa3072_template)
EK_HIGH_RSA4096 = (0x01C0001E, _ek_high_rsa4096_template)
117 changes: 117 additions & 0 deletions tpm2_pytss/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
_hmac,
)
from .types import *
from .ESAPI import ESAPI
from .constants import ESYS_TR, TPM2_CAP, TPM2_PT_NV, TPM2_ECC, TPM2_PT
from .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
Expand Down Expand Up @@ -226,3 +230,116 @@ def unwrap(
)

return s


class nv_read_full:
def __init__(
self,
ectx: ESAPI,
auth_handle: ESYS_TR = 0,
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: int) -> bytes:
nvh = self._ectx.tr_from_tpmpublic(
index, session1=self._session2, session2=self._session3
)
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) -> 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:
FIXME
Returns:
The template as a TPM2B_PUBLIC instance
"""

en = ektype.replace("-", "_")
if not hasattr(ek, en):
raise ValueError(f"unsupported EK type {ektype}")
(nvbase, template) = getattr(ek, en)

nvnonce = None
if ektype in ("EK-RSA2048", "EK-ECC256"):
nvnonce = nvbase + 1
nvtemplate = nvbase + 2
else:
nvtemplate = nvbase + 1

try:
templb = nv_read_cb(nvtemplate)
tt, _ = TPMT_PUBLIC.unmarshal(templb)
template = TPM2B_PUBLIC(publicArea=tt)
except TSS2_Exception as e:
if e.rc != 0x18B:
raise e

nonce = b""
if nvnonce:
try:
nonce = nv_read_cb(nvnonce)
except TSS2_Exception as e:
if e.rc != 0x18B:
raise e

if len(nonce) > 0 and template.publicArea.type == TPM2_ALG.RSA:
template.publicArea.unique.rsa = nonce + ((256 - len(nonce)) * b"\x00")
elif (
len(nonce) > 0
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 template

0 comments on commit 7ec6d51

Please sign in to comment.