/// <summary> /// Some policies can be evaluated solely from public parts of the policy. /// Others need a private keyholder to sign some data. Tpm2Lib provides a /// callback facility for these cases. In this sample the callback /// signs some data using a software key. But the callback might also /// ask for a smartcard to sign a challenge, etc. /// </summary> /// <param name="tpm">reference to the TPM2 object to use.</param> static void PolicyEvaluationWithCallback(Tpm2 tpm) { Console.WriteLine("Policy evaluation with callback sample."); // // Check if policy commands are implemented by TPM. This list // could include all the other used commands as well. // This check here makes sense for policy commands, because // usually a policy has to be executed in full. If a command // out of the chain of policy commands is not implemented in the // TPM, the policy cannot be satisfied. // var usedCommands = new[] { TpmCc.PolicySigned, TpmCc.PolicyGetDigest }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Policy evaluation callback sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // Template for a software signing key // var signKeyPublicTemplate = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Sign | ObjectAttr.Restricted, new byte[0], new RsaParms(SymDefObject.NullObject(), new SchemeRsassa(TpmAlgId.Sha1), 2048, 0), new Tpm2bPublicKeyRsa()); // // Create a new random key // _publicSigningKey = new AsymCryptoSystem(signKeyPublicTemplate); // // Create a policy containing a TpmPolicySigned referring to the new // software signing key. // _expectedExpirationTime = 60; var policy = new PolicyTree(TpmAlgId.Sha256); policy.Create( new PolicyAce[] { new TpmPolicySigned(_publicSigningKey.GetPublicParms().GetName(), // Newly created PubKey true, // nonceTpm required, expiration time is given _expectedExpirationTime, // expirationTime for policy new byte[0], // cpHash new byte[] { 1, 2, 3, 4 }) // policyRef { NodeId = "Signing Key 1" }, // Distinguishing name new TpmPolicyChainId("leaf") // Signed data }); // // Compute the expected hash for the policy session. This hash would be // used in the object associated with the policy to confirm that the // policy is actually fulfilled. // TpmHash expectedHash = policy.GetPolicyDigest(); // // The use of the object associated with the policy has to evaluate the // policy. In order to process TpmPolicySigned the caller will have to // sign a data structure challenge from the TPM. Here we install a // callback that will sign the challenge from the TPM. // policy.SetSignerCallback(SignerCallback); // // Evaluate the policy. Tpm2Lib will traverse the policy tree from leaf to // root (in this case just TpmPolicySigned) and will call the signer callback // to get a properly-formed challenge signed. // AuthSession authSession = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); authSession.RunPolicy(tpm, policy, "leaf"); // // And check that the TPM policy hash is what we expect // byte[] actualHash = tpm.PolicyGetDigest(authSession.Handle); if (expectedHash != actualHash) { throw new Exception("Policy evaluation error"); } Console.WriteLine("TpmPolicySignature evaluated."); // // Clean up // tpm.FlushContext(authSession.Handle); }
/// <summary> /// Some policies can be evaluated solely from public parts of the policy. /// Others needs a private keyholder to sign some data. Tpm2Lib provides /// a callback facility for these cases. /// /// This second sample illustrates the use of callbacks to provide authData. /// </summary> /// <param name="tpm">Reference to the TPM object to use.</param> static void PolicyEvaluationWithCallback2(Tpm2 tpm) { Console.WriteLine("Policy evaluation with callback sample 2."); // // Check if policy commands are implemented by TPM. This list // could include all the other used commands as well. // This check here makes sense for policy commands, because // usually a policy has to be executed in full. If a command // out of the chain of policy commands is not implemented in the // TPM, the policy cannot be satisfied. // var usedCommands = new[] { TpmCc.PolicySecret, TpmCc.PolicyGetDigest, TpmCc.PolicyRestart }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Policy evaluation callback 2 sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // Create an object with an AuthValue. The type of object is immaterial // (it can even be the owner). In order to construct the policy we will // need the name and to prove that we know the AuthVal. // _publicAuthorizationValue = AuthValue.FromRandom(10); var dataToSeal = new byte[] { 1, 2, 3, 4 }; _publicSealedObjectHandle = CreateSealedPrimaryObject(tpm, dataToSeal, _publicAuthorizationValue, null); byte[] objectName = _publicSealedObjectHandle.Name; var policy = new PolicyTree(TpmAlgId.Sha256); policy.Create( new PolicyAce[] { new TpmPolicySecret(objectName, // Name of the obj that we will prove authData true, // Include nonceTpm new byte[0], // Not bound to a cpHash new byte[0], // Null policyRef 0), // Never expires (in this session) "leaf" // Name for this ACE }); TpmHash expectedHash = policy.GetPolicyDigest(); // // We are about to ask for the session to be evaluated, but in order // to process TpmPolicySecret the caller will have to prove knowledge of // the authValue associated with objectName. In this first version we // do this with PWAP. // policy.SetPolicySecretCallback(PolicySecretCallback); AuthSession authSession = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); authSession.RunPolicy(tpm, policy, "leaf"); // // The policy evaluated. But is the digest what we expect? // byte[] digestIs = tpm.PolicyGetDigest(authSession.Handle); if (expectedHash != digestIs) { throw new Exception("Incorrect PolicyDigest"); } // // And now do the same thing but with an HMAC session. // _sharedTpm = tpm; tpm.PolicyRestart(authSession.Handle); policy.SetPolicySecretCallback(PolicySecretCallback2); authSession.RunPolicy(tpm, policy, "leaf"); _sharedTpm = null; // // The policy evaluated. But is the digest what we expect? // digestIs = tpm.PolicyGetDigest(authSession.Handle); if (expectedHash != digestIs) { throw new Exception("Incorrect PolicyDigest"); } Console.WriteLine("TpmPolicySignature evaluated."); tpm.FlushContext(authSession.Handle); }
/// <summary> /// This sample illustrates the use of a simple TPM policy session. The policy demands /// PCR 1, 2, 3 set to current values, and the command be issued at locality zero. /// </summary> static void SimplePolicy(Tpm2 tpm) { Console.WriteLine("Simple Policy sample:"); // // Check if policy commands are implemented by TPM. This list // could include all the other used commands as well. // This check here makes sense for policy commands, because // usually a policy has to be executed in full. If a command // out of the chain of policy commands is not implemented in the // TPM, the policy cannot be satisfied. // var usedCommands = new[] { TpmCc.PolicyPCR }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Simple Policy sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // First read the PCR values // var pcrs = new uint[] { 1, 2, 3 }; var sel = new PcrSelection(TpmAlgId.Sha, pcrs); PcrSelection[] selOut; Tpm2bDigest[] pcrValues; tpm.PcrRead(new[] { sel }, out selOut, out pcrValues); Console.WriteLine("PCR Selections:\n"); foreach (PcrSelection s in selOut) { Console.WriteLine(s.ToString()); } Console.WriteLine("PCR Values:\n"); foreach (var v in pcrValues) { Console.WriteLine(v.ToString()); } // // Save the current PCR values in a convenient data structure // var expectedPcrVals = new PcrValueCollection(selOut, pcrValues); // // Tpm2Lib encapsulates a set of policy assertions as the PolicyTree class. // var policy = new PolicyTree(TpmAlgId.Sha256); // // Set the policy: Locality AND PolicyPcr. This form of CreatePOlicy // only creates a single chain. Note that all well-formed policy chains // must have leaf identifiers. Leaf identifiers are just strings that // are unique in a policy so that the framework can be told what // chain to evaluate. // policy.Create( new PolicyAce[] { new TpmPolicyPcr(expectedPcrVals), "leaf" } ); // // Ask Tpm2Lib for the expected policy-hash for this policy // TpmHash expectedPolicyHash = policy.GetPolicyDigest(); // // Create a sealed primary object with the policy-hash we just calculated // var dataToSeal = new byte[] { 1, 2, 3, 4, 5, 4, 3, 2, 1 }; TpmHandle primHandle = CreateSealedPrimaryObject(tpm, dataToSeal, null, expectedPolicyHash.HashData); // // Create an actual TPM policy session to evaluate the policy // AuthSession session = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); // // Run the policy on the TPM // session.RunPolicy(tpm, policy, "leaf"); // // Unseal the object // byte[] unsealedData = tpm[session].Unseal(primHandle); Console.WriteLine("Unsealed data: " + BitConverter.ToString(unsealedData)); // // Change a PCR and make sure that the policy no longer works // var nullAuth = new AuthValue(); tpm[nullAuth].PcrEvent(TpmHandle.Pcr(3), new byte[] { 1, 2, 3 }); tpm.PolicyRestart(session.Handle); // // Run the policy again - an error will be returned // TpmRc policyError = session.RunPolicy(tpm, policy, null, true); // // And the session will be unusable // unsealedData = tpm[session]._ExpectError(TpmRc.PolicyFail).Unseal(primHandle); // // Clean up // tpm.FlushContext(session.Handle); tpm.FlushContext(primHandle); }