Hi Bill, Thanks for the response.
I have written a native trousers test case (removing all our classes so not to muddy the water) to see if I could reproduce the issue on our device. It still happens, even with the keys being generated for each test and not registered with the persistent store. I have attached my test code: it is a GTest test program ( https://code.google.com/p/googletest/downloads/list), using the QCA library to generate the ca key for the AIK. there are two tests: one without PCR locking which works on the emulator and on two different devices with real tpms one with pcr locking of the bind key which works on the emulator but fails on both tpm devices. If anyone can take a look, and let me know if there are any obvious mistakes? and may be compile it and run it against a tpm device? I would be very greatful. Many thanks Simon On 26 January 2015 at 17:26, Bill Martin <[email protected]> wrote: > You are running into similar problems I am having. > > I think I know where my errors are. See if this helps. > > Take care that you are managing your persistent storage for your keys you > load or register by UUID. It makes sense that you need a unique UUID for > each user-generated key. At least to me it does. All the examples I used > were for a single demonstration and had the UUID {0, 0, 0, 0, 0, {0, 0, 0, > 0, 2, 0}. > > The inner array is the rgbNode array of six bytes. The element 5 (0-based > array) has reserved values. And there is a special OWNEREVICT set of values > too. See tss_defines.h > > In my case I also compiled trouSerS with --enable_debug, and it made a lot > of sense the area was in a call to unblob a header. > > You are not using the tcai_aik.c file. But a lot of your errors involve > loading by UUID, presumably from the storage. > > let me know how it goes > > Bill > ________________________________________ > From: Simon Gould [[email protected]] > Sent: Monday, January 26, 2015 7:58 AM > To: [email protected] > Subject: Re: [TrouSerS-users] CertifyKey failing when bind key locked to > PCRs > > Hi all, > > I appear to have made a schoolboy error in my last post ;-). Apologies, my > previous mail included the log where I had attempted to put the localities > in. The log where certify fails is attached here. line 1176 is where the > certify error occurs. > > Many thanks > > Simon > > On 26 January 2015 at 10:13, Simon Gould <[email protected] > <mailto:[email protected]>> wrote: > Hi all, > > I have progressed my TPM project thanks to the really useful input from > this list and I am hoping someone can help as I have hit another block. > > I have seen some similar issues to this on the mailing list before, but my > issue appears to be slightly different to those. > > We are using a TPM on an embedded device: > TPM 1.2 Version Info: > Chip version 1.2.13.10 > Spec Level 2 > Errata Revision 3 > TPM Vendor ID STM > Vendor Specific data 4b. > > we have an internal process that sets up keys on the device. those being > the Storage Root Key, Attestation Identity Key & a communications signing > key (used to sign SSL comms from the device). > > there is a second stage to that process happens on the first boot of the > device (so we have the correct PCR values). We create a licence encryption > key for the device. this is a bind key locked to some of the PCRs that are > extended on boot (to ensure that the device is not tampered with). > > This key is a child of the SRK, locked to 2 PCRs and we want to certify it > using the AIK and send that information to the service licencing the device. > > However the CertifyKey call fails with a Bad Parameter error. I have run > the same code against the IBM emulator (which has been very useful) and it > passes without issue. If I do not lock the key to the PCRs it passes > without issue. The locked key can bind and unbind data without issue. > > The PCRs haven't changed. I have tried setting localities in the PCR > composite object used when we create the key and it complains that the > object is in an inconsistent state (I was trying anything I could think of > at this point). > > I have isolated this as a test case and I see the same issue as with the > production code when it is run on the device. I am now at a loss as to what > may be causing this issue. I have attached the trousers debug log from the > test case. if anyone has any insight into the cause or what I can try next > that would be great. > > The log has 3 test cases within it. > 1) create a bind key locked to a pcr, bind some data. register the key, > clear the key. load the key by UUid and unbind the data. > 2) create a bind key locked to a pcr. bind some data. register the key. > clear the key. extend the pcr it is locked to. load the key by UUid. try to > unbind data which fails. > 3) create a bind key locked to a pcr, use the AIK to certify this key > (which fails unexpectedly) > > I have noticed I get some errors in the set up where it appears to be > failing to load keys, but I get these in the cases where it works as well, > so they maybe red herrings. > > Many thanks > > Simon > > > ------------------------------------------------------------------------------ > Dive into the World of Parallel Programming. The Go Parallel Website, > sponsored by Intel and developed in partnership with Slashdot Media, is > your > hub for all things parallel software development, from weekly thought > leadership blogs to news, videos, case studies, tutorials and more. Take a > look and join the conversation now. http://goparallel.sourceforge.net/ > _______________________________________________ > TrouSerS-users mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/trousers-users >
#include <gtest/gtest.h>
#include <tss/tspi.h>
#include <tss/tddli.h>
#include <tss/tss_defines.h>
#include <tss/tcs_error.h>
#include <tss/tss_error.h>
#include <trousers/trousers.h>
#include <qca.h>
class CertifyKeyTests: public ::testing::Test
{
public:
TSS_HCONTEXT tspi;
TSS_HTPM tpmHandle;
TSS_HKEY srkKey;
TSS_HKEY identKey;
QCA::Initializer init;
CertifyKeyTests():tspi(0),tpmHandle(0),srkKey(0),identKey(0){}
// Test interface
protected:
void AssertOnError(TSS_RESULT result)
{
ASSERT_EQ(TSS_SUCCESS,result) << Trspi_Error_String(result);
}
bool isOwned()
{
UINT32 sub_cap = TSS_TPMCAP_PROP_OWNER;
UINT32 cap_length = 0;
BYTE* cap = NULL;
bool owned = false;
AssertOnError(Tspi_TPM_GetCapability(tpmHandle, TSS_TPMCAP_PROPERTY,
sizeof(sub_cap),
reinterpret_cast<BYTE*>(&sub_cap),
&cap_length, &cap));
if (cap_length >= (sizeof(TSS_BOOL))) {
owned = ((*(reinterpret_cast<TSS_BOOL*>(cap))) != 0);
}
return owned;
}
void takeOwnership()
{
TSS_RESULT result;
AssertOnError(Tspi_Context_CreateObject(tspi,TSS_OBJECT_TYPE_RSAKEY,TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION,&srkKey));
TSS_HPOLICY srkUsagePolicy;
AssertOnError(Tspi_GetPolicyObject(srkKey, TSS_POLICY_USAGE,&srkUsagePolicy));
AssertOnError(Tspi_Policy_SetSecret(srkUsagePolicy,
TSS_SECRET_MODE_PLAIN,
20, (BYTE*) "00000000000000000000"));
int retryCount = 0;
do {
result = Tspi_TPM_TakeOwnership(tpmHandle, srkKey, 0);
retryCount++;
} while(((result == TDDL_E_TIMEOUT) ||
(result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) ||
(result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) &&
(retryCount < 10));
AssertOnError(result);
}
void loadSrk()
{
AssertOnError(Tspi_Context_LoadKeyByUUID(tspi,TSS_PS_TYPE_SYSTEM,TSS_UUID_SRK,&srkKey));
TSS_HPOLICY srkUsagePolicy;
AssertOnError(Tspi_GetPolicyObject(srkKey, TSS_POLICY_USAGE,&srkUsagePolicy));
AssertOnError(Tspi_Policy_SetSecret(srkUsagePolicy,
TSS_SECRET_MODE_PLAIN,
20, (BYTE*) "00000000000000000000"));
}
void setPublicModulus(TSS_HKEY key, const QCA::SecureArray &pubN)
{
BYTE* blob;
UINT32 blobSize;
UINT64 offset = 0;
TCPA_PUBKEY pubKey;
QCA::SecureArray pubBlob(1024);
// Get the TCPA_PUBKEY blob from the key object.
AssertOnError(Tspi_GetAttribData(key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,&blobSize, &blob));
AssertOnError(Trspi_UnloadBlob_PUBKEY(&offset, blob, &pubKey));
pubKey.pubKey.keyLength = pubN.size();
pubKey.pubKey.key = reinterpret_cast<BYTE*>(const_cast<char*>(pubN.data()));
offset = 0;
Trspi_LoadBlob_PUBKEY(&offset, reinterpret_cast<BYTE*>(const_cast<char*>(pubBlob.data())), &pubKey);
//set the public key data in the TSS object
AssertOnError(Tspi_SetAttribData(key, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,(UINT32)offset, reinterpret_cast<BYTE*>(const_cast<char*>(pubBlob.data())) ));
}
void createAIK()
{
TSS_HKEY caKey =0;
AssertOnError( Tspi_Context_CreateObject(
tspi,
TSS_OBJECT_TYPE_RSAKEY,
TSS_KEY_SIZE_2048 |
TSS_KEY_TYPE_LEGACY |
TSS_KEY_NOT_MIGRATABLE |
TSS_KEY_NO_AUTHORIZATION |
TSS_KEY_VOLATILE, &caKey) );
QCA::RSAPublicKey pubKey = QCA::KeyGenerator().createRSA(2048).toPublicKey().toRSA();
setPublicModulus(caKey,pubKey.n().toArray());
// set the CA key's algorithm
AssertOnError(Tspi_SetAttribUint32(caKey, TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_ALGORITHM,
TSS_ALG_RSA));
// set the CA key's number of primes
AssertOnError(Tspi_SetAttribUint32(caKey, TSS_TSPATTRIB_RSAKEY_INFO,
TSS_TSPATTRIB_KEYINFO_RSA_PRIMES,
2));
AssertOnError(Tspi_SetAttribUint32(caKey,
TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
TSS_ES_RSAESPKCSV15));
AssertOnError(Tspi_SetAttribUint32(caKey,
TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
TSS_SS_RSASSAPKCS1V15_SHA1));
AssertOnError( Tspi_Context_CreateObject(
tspi,
TSS_OBJECT_TYPE_RSAKEY,
TSS_KEY_SIZE_2048 |
TSS_KEY_TYPE_IDENTITY |
TSS_KEY_NOT_MIGRATABLE |
TSS_KEY_NO_AUTHORIZATION |
TSS_KEY_VOLATILE, &identKey) );
AssertOnError(Tspi_SetAttribUint32(identKey,
TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
TSS_SS_RSASSAPKCS1V15_SHA1));
UINT32 ulTCPAIdentityReqLength;
BYTE *rgbTCPAIdentityReq = NULL;
AssertOnError(Tspi_TPM_CollateIdentityRequest(
tpmHandle,
srkKey ,
caKey,
15,
(BYTE *)"CertifyKeyTests",
identKey,
TSS_ALG_AES,
&ulTCPAIdentityReqLength,
&rgbTCPAIdentityReq));
AssertOnError(Tspi_Key_LoadKey(identKey,srkKey));
}
void SetUp()
{
//initialize QCA
init = QCA::Initializer();
AssertOnError(Tspi_Context_Create(&tspi));
AssertOnError(Tspi_Context_Connect(tspi,nullptr));
AssertOnError(Tspi_Context_GetTpmObject(tspi,&tpmHandle));
TSS_HPOLICY usagePolicy;
AssertOnError(Tspi_GetPolicyObject(tpmHandle, TSS_POLICY_USAGE,&usagePolicy));
AssertOnError(Tspi_Policy_SetSecret(usagePolicy,
TSS_SECRET_MODE_PLAIN,
20, (BYTE*) "00000000000000000000"));
//if not owned
if (!isOwned())
{
//take ownership
takeOwnership();
}
//Load SRK
loadSrk();
createAIK();
}
void TearDown()
{
if(tspi != 0){
//Free's all memory related to this context
Tspi_Context_FreeMemory(tspi,nullptr);
//Close the actual context itself
Tspi_Context_Close(tspi);
tspi = 0;
}
}
};
TEST_F(CertifyKeyTests,CertifyKeyBasicBindKey)
{
TSS_HKEY bindKey = 0;
AssertOnError( Tspi_Context_CreateObject(tspi,
TSS_OBJECT_TYPE_RSAKEY,
TSS_KEY_SIZE_2048 |
TSS_KEY_TYPE_BIND |
TSS_KEY_NOT_MIGRATABLE |
TSS_KEY_NO_AUTHORIZATION |
TSS_KEY_VOLATILE,
&bindKey) );
AssertOnError(Tspi_Key_CreateKey(
bindKey,
srkKey,
0));
AssertOnError(Tspi_Key_LoadKey(bindKey,srkKey));
//Generate a random nonce to prevent replay attacks
TSS_VALIDATION validation;
validation.ulExternalDataLength = sizeof(TCPA_NONCE);
AssertOnError(Tspi_TPM_GetRandom(
tpmHandle,
validation.ulExternalDataLength,
&validation.rgbExternalData));
AssertOnError(Tspi_Key_CertifyKey(bindKey, identKey, &validation));
}
TEST_F(CertifyKeyTests,CertifyPCRLockedBindKey)
{
UINT32 pcrOutLen = 20;
BYTE* pcrOut;
AssertOnError(Tspi_TPM_PcrRead(tpmHandle,3,&pcrOutLen,&pcrOut));
TSS_HPCRS hPcrs = 0;
AssertOnError(Tspi_Context_CreateObject(tspi, TSS_OBJECT_TYPE_PCRS, 0, &hPcrs));
AssertOnError(Tspi_PcrComposite_SetPcrValue(hPcrs,3,pcrOutLen,pcrOut));
TSS_HKEY bindKey = 0;
AssertOnError( Tspi_Context_CreateObject(tspi,
TSS_OBJECT_TYPE_RSAKEY,
TSS_KEY_SIZE_2048 |
TSS_KEY_TYPE_BIND |
TSS_KEY_NOT_MIGRATABLE |
TSS_KEY_NO_AUTHORIZATION |
TSS_KEY_VOLATILE,
&bindKey) );
AssertOnError(Tspi_Key_CreateKey(
bindKey,
srkKey,
hPcrs));
AssertOnError(Tspi_Key_LoadKey(bindKey,srkKey));
//Generate a random nonce to prevent replay attacks
TSS_VALIDATION validation;
validation.ulExternalDataLength = sizeof(TCPA_NONCE);
AssertOnError(Tspi_TPM_GetRandom(
tpmHandle,
validation.ulExternalDataLength,
&validation.rgbExternalData));
AssertOnError(Tspi_Key_CertifyKey(bindKey, identKey, &validation));
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
tcsd_certify.log
Description: Binary data
------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________ TrouSerS-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/trousers-users
