/// <summary> /// This sample shows the use of HMAC sessions to authorize TPM actions. /// HMAC sessions may be bound/unbound and seeded/unseeded. This sample /// illustrates an unseeded and unbound session. /// </summary> /// <param name="tpm">Reference to the TPM object.</param> static void HmacUnboundUnseeded(Tpm2 tpm) { // // Create a hash-sequence with a random authorization value // AuthValue authVal = AuthValue.FromRandom(8); TpmHandle hashHandle = tpm.HashSequenceStart(authVal, TpmAlgId.Sha256); // // Commands with the Ex modifier are library-provided wrappers // around TPM functions to make programming easier. This version // of StartAuthSessionEx calls StartAuthSession configured to // create an unbound and unseeded auth session with the auth-value // provided here. // AuthSession s0 = tpm.StartAuthSessionEx(TpmSe.Hmac, TpmAlgId.Sha256); // // The following calls show the use of the HMAC session in authorization. // The session to use is communicated as a parameter in the [] overloaded // function and the auth-value is that set during HMAC session creation. // TkHashcheck validate; tpm[s0].SequenceUpdate(hashHandle, new byte[] { 0, 2, 1 }); byte[] hashedData = tpm[s0].SequenceComplete(hashHandle, new byte[] { 2, 3, 4 }, TpmHandle.RhOwner, out validate); Console.WriteLine("Hashed data (HMAC authorized sequence): " + BitConverter.ToString(hashedData)); tpm.FlushContext(s0.Handle); }
/// <summary> /// This sample illustrates the creation and use of an RSA signing key to /// "quote" PCR state /// </summary> /// <param name="tpm">Reference to the TPM object.</param> static void QuotePcrs(Tpm2 tpm) { // // First use a library routine to create an RSA/AES primary storage key // with null user-auth. // TpmPublic rsaPrimaryPublic; var primaryAuth = new byte[0]; TpmHandle primHandle = CreateRsaPrimaryStorageKey(tpm, primaryAuth, out rsaPrimaryPublic); // // Template for a signing key. We will make the key restricted so that we // can quote with it too. // var signKeyPubTemplate = new TpmPublic(TpmAlgId.Sha1, ObjectAttr.Sign | ObjectAttr.Restricted | // A "quoting" key ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicable ObjectAttr.UserWithAuth | // Authorize with auth-data ObjectAttr.SensitiveDataOrigin, // TPM will create a new key new byte[0], new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha1), 2048, 0), new Tpm2bPublicKeyRsa()); // // Auth-data for new key // var userAuth = new byte[] { 1, 2, 3, 4 }; var sensCreate = new SensitiveCreate(userAuth, new byte[0]); // // Creation data (not used in this sample) // CreationData childCreationData; TkCreation creationTicket; byte[] creationHash; // // Create the key // TpmPublic keyPub; TpmPrivate keyPriv = tpm[primaryAuth].Create(primHandle, // Child of primary key created above sensCreate, // Auth-data signKeyPubTemplate, // Template created above new byte[0], // Other parms are not used here new PcrSelection[0], out keyPub, out childCreationData, out creationHash, out creationTicket); Console.WriteLine("New public key\n" + keyPub.ToString()); // // Load the key as a child of the primary that it // was created under. // TpmHandle signHandle = tpm[primaryAuth].Load(primHandle, keyPriv, keyPub); // // Note that Load returns the "name" of the key and this is automatically // associated with the handle. // Console.WriteLine("Name of key:" + BitConverter.ToString(signHandle.Name)); // // Aome data to quote // TpmHash hashToSign = TpmHash.FromData(TpmAlgId.Sha1, new byte[] { 4, 3, 2, 1 }); // // PCRs to quote. SHA-1 bank, PCR-indices 1, 2, and 3 // var pcrsToQuote = new PcrSelection[] { new PcrSelection(TpmAlgId.Sha, new uint[] { 1, 2, 3 }) }; // // Ask the TPM to quote the PCR (and the nonce). The TPM // returns the quote-signature and the data that was signed // ISignatureUnion quoteSig; Attest quotedInfo = tpm[userAuth].Quote(signHandle, hashToSign.HashData, new SchemeRsassa(TpmAlgId.Sha1), pcrsToQuote, out quoteSig); // // Print out what was quoted // var info = (QuoteInfo)quotedInfo.attested; Console.WriteLine("PCRs that were quoted: " + info.pcrSelect[0].ToString() + "\nHash of PCR-array: " + BitConverter.ToString(info.pcrDigest)); // // Read the PCR to check the quoted value // PcrSelection[] outSelection; Tpm2bDigest[] outValues; tpm.PcrRead(new PcrSelection[] { new PcrSelection(TpmAlgId.Sha, new uint[] { 1, 2, 3 }) }, out outSelection, out outValues); // // Use the Tpm2Lib library to validate the quote against the // values just read. // bool quoteOk = keyPub.VerifyQuote(TpmAlgId.Sha1, outSelection, outValues, hashToSign.HashData, quotedInfo, quoteSig); if (!quoteOk) { throw new Exception("Quote did not validate"); } Console.WriteLine("Quote correctly validated."); // // Test other uses of the signing key. A restricted key can only // sign data that the TPM knows does not start with a magic // number (that identifies TPM internal data). So this does not // work // var nullProof = new TkHashcheck(TpmHandle.RhNull, new byte[0]); tpm[userAuth]._ExpectError(TpmRc.Ticket).Sign(signHandle, hashToSign.HashData, new SchemeRsassa(TpmAlgId.Sha1), nullProof); // // But if we ask the TPM to hash the same data and then sign it // then the TPM can be sure that the data is safe, so it will // sign it. // TkHashcheck safeHashTicket; TpmHandle hashHandle = tpm.HashSequenceStart(_nullAuth, TpmAlgId.Sha1); // // The ticket is only generated if the data is "safe." // tpm[_nullAuth].SequenceComplete(hashHandle, new byte[] { 4, 3, 2, 1 }, TpmHandle.RhOwner, out safeHashTicket); // // This will now work because the ticket proves to the // TPM that the data that it is about to sign does not // start with TPM_GENERATED // ISignatureUnion sig = tpm[userAuth].Sign(signHandle, hashToSign.HashData, new SchemeRsassa(TpmAlgId.Sha1), safeHashTicket); // // And we can verify the signature // bool sigOk = keyPub.VerifySignatureOverData(new byte[] { 4, 3, 2, 1 }, sig); if (!sigOk) { throw new Exception("Signature did not verify"); } Console.WriteLine("Signature verified."); // // Clean up // tpm.FlushContext(primHandle); tpm.FlushContext(signHandle); }
/// <summary> /// Use a hash sequence to concatenate and hash data that is bigger then /// the communication buffer to the TPM. /// </summary> /// <param name="tpm">Reference to the TPM object.</param> static void HashSequence(Tpm2 tpm) { // // Create an auth-value to control later access to the hash object. // The AuthValue class is a Tpm2Lib-provided helper object for managing // authorization data. Here we ask the library to create a 10-byte // random array. // AuthValue authVal = AuthValue.FromRandom(10); // // Create a hash sequence-object with the auth-value provided and // based on SHA-1. This command returns a uint identifier that we call a handle. // TpmHandle hashHandle = tpm.HashSequenceStart(authVal, TpmAlgId.Sha1); // // Hash some data using the hash sequence object just created. // It is normally the case that the use of TPM internal objects // must be "authorized" by proof-of-knowledge of the authorization // value that was set when the object was created. Authorization // is communicated using a TPM construct called a "session." // Every handle that requires authorization requires a session // that conveys knowledge of the auth-value (or other authorization). // // The specific style of session used here is a "password authorization // session, or PWAP session, where the password is communicated // in plain text. // // Three styles of session creation are demonstrated. // Style 1 (not preferred). The method _SetSessions() tells Tpm2Lib // to use the authorization value authVal in a PWAP session // tpm._SetSessions(authVal); tpm[authVal].SequenceUpdate(hashHandle, new byte[] { 0, 1 }); // // Style 2 (not preferred). The method _SetSessions() returns "this" // so the two lines above can be condensed. tpm._SetSessions(authVal); // tpm._SetSessions(authVal).SequenceUpdate(hashHandle, new byte[] { 2, 3 }); // // Style 3 - RECOMMENDED // In the command sequence below the [authValue] construct is // NOT an array-accessor. Instead it is shorthand to associate // a list of authorization sessions with the command (one session // in this case. // tpm[authVal].SequenceUpdate(hashHandle, new byte[] { 4, 5 }); tpm[authVal].SequenceUpdate(hashHandle, new byte[] { 6, 7 }); // // Add the final data block // TkHashcheck validation; byte[] hashedData = tpm[authVal].SequenceComplete(hashHandle, new byte[] { 4, 5 }, TpmHandle.RhOwner, out validation); Console.WriteLine("Hashed data (Sequence): " + BitConverter.ToString(hashedData)); }