Closed Dvergatal closed 2 years ago
@whooo OK I have done one more test, which was to confirm my reasoning, meaning I have created EK with the usage of this command:
tpm2_createek -c 0x81010001 -G rsa -u ek.pub
than I have used
tpm_device_provision
just to generate SRK - it will not regenerate EK because it has been already generated by thetpm2_createek
and I have confirmed that in my earlier posts, besidestpm_device_provision
returns this new value. With this additional step of SRK creation, I was now able to establish a connection with Azure cloud :) So I am wondering now how I can do this (make EK persistent, generate SRK and make it also persistent) with pytss?* Make EK Persistent - use ESAPI.EvictControl * You can also create it with ESAPI.CreatePrimary with the proper template or use the helper create_ek_template. * If you use create_ex_template from utils, I think the proper template is "EK-RSA2048" and you can set the Callable to class NVReadEK or even your own class that on call just returns NoSuchIndex exception but it will be less portable on the off chance the TPM defines a template at an NV index.
OK, whit this I have succeeded, the EK is persistent.
* Generate SRK - Use ESAPI.CreatePrimary with proper template * I Wonder if we should add a bunch of constants available for users here. * The SRK spec is here in section https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf section 7.5.1 which references the EK Spec https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_Credential_Profile_EK_V2.1_R13.pdf. TL;DR the SRK is the EK with the policy zeroed out and a slightly different attribute set. **NOTE** Their is some lore here, the TCG specification for the EK sets the unique field to keysize bytes of 0. So for an RSA 2048 key, the TCG SRK has a unique of 256 bytes of 0.
For this one, I already have given here a template which is written in C, the problem is that I dunno how can I rewrite this template into python.
You have the SRK template in GetSrkTemplate and just have to check the correct parameters as well, so create a TPM2B_PUBLIC instance and use that with create_primary
You have the SRK template in GetSrkTemplate and just have to check the correct parameters as well, so create a TPM2B_PUBLIC instance and use that with create_primary
@whooo that is what I have written:P but GetSrkTemplate() is in C code and I dunno how it should be rewritten in python code.
Look at https://github.com/tpm2-software/tpm2-pytss/blob/8ebc054af8e4e6c5fdadfbe5fbfd7876a98483fa/test/test_esapi.py#L28 for an example, it's the same field names as the C code from azure
@whooo thx
@whooo one more thing, from what I see in this example it slightly differs due to usage of ecc and in azure they are using rsa. So there are also this parameters an in case of example it looks like that:
inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDSA
inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = (
TPM2_ALG.SHA256
)
inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG.NULL
inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL
inPublic.publicArea.parameters.eccDetail.curveID = TPM2_ECC.NIST_P256
and in case of Azure:
static TPMS_RSA_PARMS RsaStorageParams = {
{ TPM_ALG_AES, 128, TPM_ALG_CFB }, // TPMT_SYM_DEF_OBJECT symmetric
{ TPM_ALG_NULL }, // TPMT_RSA_SCHEME scheme
2048, // TPMI_RSA_KEY_BITS keyBits
0 // UINT32 exponent
};
How should it inPublic.publicArea.parameters.eccDetail
be changed? Meaning eccDetail
.
Look at TPMT_PUBLIC in tss2_tpm2_types.h to get a picture of the structure
Look at TPMT_PUBLIC in tss2_tpm2_types.h to get a picture of the structure
I have just found it and it is all written down there:D thx
@whooo I'm not an expert in python rather C/C++, but I wonder if it is possible to write it like in here the assignments instead of passing all these:
inPublic = TPM2B_PUBLIC()
inPublic.publicArea.type = TPM2_ALG.ECC
inPublic.publicArea.nameAlg = TPM2_ALG.SHA1
inPublic.publicArea.objectAttributes = (
TPMA_OBJECT.USERWITHAUTH
| TPMA_OBJECT.SIGN_ENCRYPT
| TPMA_OBJECT.RESTRICTED
| TPMA_OBJECT.FIXEDTPM
| TPMA_OBJECT.FIXEDPARENT
| TPMA_OBJECT.SENSITIVEDATAORIGIN
)
inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG.ECDSA
inPublic.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = (
TPM2_ALG.SHA256
)
inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG.NULL
inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG.NULL
inPublic.publicArea.parameters.eccDetail.curveID = TPM2_ECC.NIST_P256
just to write it like that:
rsa_template = TPMT_PUBLIC(
type=TPM2_ALG.RSA,
nameAlg=TPM2_ALG.SHA256,
objectAttributes=TPMA_OBJECT.USERWITHAUTH
| TPMA_OBJECT.RESTRICTED
| TPMA_OBJECT.DECRYPT
| TPMA_OBJECT.NODA
| TPMA_OBJECT.FIXEDTPM
| TPMA_OBJECT.FIXEDPARENT
| TPMA_OBJECT.SENSITIVEDATAORIGIN,
authPolicy=b"",
parameters=TPMU_PUBLIC_PARMS(
rsaDetail=TPMS_RSA_PARMS(
symmetric=TPMT_SYM_DEF_OBJECT(
algorithm=TPM2_ALG.AES,
keyBits=TPMU_SYM_KEY_BITS(aes=128),
mode=TPMU_SYM_MODE(aes=TPM2_ALG.CFB),
),
scheme=TPMT_RSA_SCHEME(scheme=TPM2_ALG.NULL),
keyBits=2048,
exponent=0,
),
),
)
I'm just curious if TPM2B_PUBLIC() is being returned by TPMT_PUBLIC().
P.S. Do not care about the difference in case of type of asymmetric encryption, I've just copied the code to show my point of view.
It should work, but you won't know until you try. To get a TPM2B_PUBLIC from rsa_template just do TPM2B_PUBLIC(publicArea=rsa_template)
Ok and what about these parameters TPM2B_DIGEST
and TPMU_PUBLIC_ID
which are set in template as:
{ 0 }, // TPMA_OBJECT objectAttributes (set below)
{ 0 }, // TPM2B_DIGEST authPolicy
{ 0 }, // TPMU_PUBLIC_PARMS parameters (set before use)
{ 0 } // TPMU_PUBLIC_ID unique
Does authPolicy=b""
is equivalent with { 0 }, // TPM2B_DIGEST authPolicy
?
I do not see any TPMU_PUBLIC_ID
field in the documentation.
yes, authPolicy=b"" means an empty policy (zero size), you don't need to set it as it's empty by default (cffi zeroes all allocations by default). The fields are to the right, so the field name is unique, not TPMU_PUBLIC_ID and I see it in tss2_tpm2_types.h You shouldn't need to set the unique field unless you want to add some nonce to the key generation
yes, authPolicy=b"" means an empty policy (zero size), you don't need to set it as it's empty by default (cffi zeroes all allocations by default).
Ah ok so i can remove this field in my code.
The fields are to the right, so the field name is unique, not TPMU_PUBLIC_ID and I see it in tss2_tpm2_types.h You shouldn't need to set the unique field unless you want to add some nonce to the key generation
Hmmm, ok so the EK may differ between Azure and tpm2-tools only due to this nonce given to the key generation, but as you could see, the template for EK doesn't give any unique id to it. What should I look for?
The nonce part was mostly a guess/assumption from my side as the cause, but if it's not set by the azure stuff I was wrong
Nope it's not, I'm reading this Azure code and even all variables like TPML_PCR_SELECTION are the same. This is their function for creating primary:
TPM_RC TSS_CreatePrimary(TSS_DEVICE *tpm, TSS_SESSION *sess,
TPM_HANDLE hierarchy, TPM2B_PUBLIC *inPub,
TPM_HANDLE *outHandle, TPM2B_PUBLIC *outPub)
{
TPM2B_SENSITIVE_CREATE sensCreate = { 0 };
TPM2B_DATA outsideInfo = { {0} };
TPML_PCR_SELECTION creationPCR = { 0 };
return TPM2_CreatePrimary(tpm, sess, hierarchy, &sensCreate,
inPub, &outsideInfo, &creationPCR,
outHandle, outPub, NULL, NULL, NULL);
}
Arrr, this Azure code is really ugly. I think I need to ping them, because as you can see this sensCreate
is equal {0}
and I see further that it is being marshaled with some stupid define TSS_MARSHAL(TPM2B_SENSITIVE_CREATE, inSensitive);
which looks like that:
#define TSS_MARSHAL(Type, pValue) \
{ \
TSS_CHECK_PTR(pValue) \
cmdCtx->ParamSize += Type##_Marshal(pValue, ¶mBuf, &sizeParamBuf); \
}
and cmdCtx
is a structure, but it's rather not important. Than this Type##_Marshal
is TPM2B_SENSITIVE_CREATE_Marshal
and it starts to be really unreadable...
@whooo @williamcroberts First of all I'm sorry for bothering you with problem, which is not of your concerns. Together with guys which are still working there we are trying to solve this issue here.
I have also a question to you guys, because this method:
TPM_RC
TPM2_CreatePrimary(
TSS_DEVICE *tpm,
TSS_SESSION *session,
TPMI_DH_OBJECT primaryHandle,
TPM2B_SENSITIVE_CREATE *inSensitive,
TPM2B_PUBLIC *inPublic,
TPM2B_DATA *outsideInfo,
TPML_PCR_SELECTION *creationPCR,
TPM_HANDLE *objectHandle,
TPM2B_PUBLIC *outPublic,
TPM2B_CREATION_DATA *creationData,
TPM2B_DIGEST *creationHash,
TPMT_TK_CREATION *creationTicket
)
{
TSS_CMD_CONTEXT CmdCtx;
TPM_RC cmdResult = (TPM_RC)(0x000);
TSS_CMD_CONTEXT *cmdCtx = &CmdCtx;
INT32 sizeParamBuf = sizeof(cmdCtx->ParamBuffer);
BYTE *paramBuf = cmdCtx->ParamBuffer;
(void)sizeParamBuf;
(void)paramBuf;
cmdCtx->ParamSize = 0;
{
void* p = inSensitive;
(void)p;
}
cmdCtx->ParamSize += TPM2B_SENSITIVE_CREATE_Marshal(inSensitive, ¶mBuf, &sizeParamBuf);
{
void* p = inPublic;
(void)p;
}
cmdCtx->ParamSize += TPM2B_PUBLIC_Marshal(inPublic, ¶mBuf, &sizeParamBuf);
{
void* p = outsideInfo;
(void)p;
}
cmdCtx->ParamSize += TPM2B_DATA_Marshal(outsideInfo, ¶mBuf, &sizeParamBuf);
{
void* p = creationPCR;
(void)p;
}
cmdCtx->ParamSize += TPML_PCR_SELECTION_Marshal(creationPCR, ¶mBuf, &sizeParamBuf);
cmdResult = TSS_DispatchCmd(tpm, (TPM_CC)(0x00000131), &primaryHandle, 1, &session, 1, cmdCtx);
if (cmdResult != (TPM_RC)(0x000)) return cmdResult;;
*objectHandle = cmdCtx->RetHandle;
{
if ( TPM2B_PUBLIC_Unmarshal(outPublic, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft, 1) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
if (!(creationData)) {
TPM2B_CREATION_DATA val;
{
if ( TPM2B_CREATION_DATA_Unmarshal(&val, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
}
else {
if ( TPM2B_CREATION_DATA_Unmarshal(creationData, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
if (!(creationHash)) {
TPM2B_DIGEST val;
{
if ( TPM2B_DIGEST_Unmarshal(&val, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
}
else {
if ( TPM2B_DIGEST_Unmarshal(creationHash, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
if (!(creationTicket)) {
TPMT_TK_CREATION val;
{
if ( TPMT_TK_CREATION_Unmarshal(&val, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
}
else {
if ( TPMT_TK_CREATION_Unmarshal(creationTicket, &cmdCtx->RespBufPtr, (INT32*)&cmdCtx->RespBytesLeft) != (TPM_RC)(0x000)) return (TPM_RC)((TPM_RC)(0x080)+0x01A);
};
return cmdResult;
}
as the name suggests creates the primary and now I have feeling that PCR used in it is wrong. Can you look at it and maybe you may have some thoughts?
@Dvergatal i'll try and look at this, I am recovering from surgery so please be patient. Perhaps @idesai can look at it and spot why their is a delta?
@Dvergatal i'll try and look at this, I am recovering from surgery so please be patient. Perhaps @idesai can look at it and spot why their is a delta?
@williamcroberts it's OK. I fully understand you, as I am supposed to have surgery myself soon. I was also thinking about this delta and I do not fully understand what is this delta in the code. I suppose, as mentioned, that we would really need help from @idesai.
@williamcroberts and others I have pasted you in my previous post the link to issue on Azure github. Please join there, so that we can solve this problem together with the people from Microsoft.
After we (I mean by that, you @williamcroberts :P) have finally solved this issue, I think it can be closed. Thx a lot to all involved.
Hi all, just like in the subject I wanted to ask you guys is it possible to read/retrieve the endorsement key - public part - from the TPM with this API?
Moreover, if we are in the subject of endorsement key I have another question to you, because I am currently struggling with Microsoft Azure and its tpm_device_provision binary which is used for DPS provisioning (it retrieves Registration id and Endorsement Key). On Microsoft Azure documentation sites it is written, that this binary retrieves public part of this RSA TPM key, but when i wanted to decode this base64 with the usage of openssl, it says, that this is not a public key.
In our tests we are using SWTPM software TPM implementation on qemu machine and according to the SWTPM documentation it creates it's own ek_key during TPM creation. Question is, if this can be rubbish or does it have some completely different format? I can also paste you here this TPM ek_pub:
Moreover I have observed, that it starts completely differently, than any other RSA public key created by openssl.