LoadExternal() private method

private LoadExternal ( Sensitive inPrivate, TpmPublic inPublic, TpmHandle hierarchy ) : TpmHandle
inPrivate Sensitive
inPublic TpmPublic
hierarchy TpmHandle
return TpmHandle
Esempio n. 1
0
        internal override TpmRc Execute(Tpm2 tpm, AuthSession sess, PolicyTree policy)
        {
            byte[] nonceTpm = UseNonceTpm ? Globs.CopyData(sess.NonceTpm) : new byte[0];

            TpmHandle sigKey;

            // If we have both the authorizing signature and the corresponding
            // signing key handle, we are good to go.
            if (AuthSig == null)
            {
                var dataToSign = new Marshaller();
                dataToSign.Put(nonceTpm, "");

                // If we have a signing key we can build the challenge here
                // (else we need to call out)
                if (SwSigningKey != null)
                {
                    dataToSign.Put(ExpirationTime, "");
                    dataToSign.Put(CpHash, "");
                    dataToSign.Put(PolicyRef, "");
                    // Just ask the key to sign the challenge
                    AuthSig = SwSigningKey.Sign(dataToSign.GetBytes());
                    sigKey  = tpm.LoadExternal(null, SigningKeyPub, TpmRh.Owner);
                }
                else
                {
                    TpmPublic verifier;
                    AuthSig = AssociatedPolicy.ExecuteSignerCallback(this, nonceTpm,
                                                                     out verifier);
                    sigKey = tpm.LoadExternal(null, verifier, TpmRh.Owner);
                }
            }
            else
            {
                sigKey = tpm.LoadExternal(null, SigningKeyPub, TpmRh.Owner);
            }
            Timeout = tpm.PolicySigned(sigKey, sess, nonceTpm,
                                       CpHash, PolicyRef, ExpirationTime,
                                       AuthSig, out Ticket);

            TpmRc responseCode = tpm._GetLastResponseCode();

            tpm.FlushContext(sigKey);
            if (!KeepAuth)
            {
                AuthSig = null;
            }
            return(responseCode);
        }
Esempio n. 2
0
        /// <summary>
        /// This sample demonstrates a policy containing ALL policy commands.  
        /// It also demonstrates serialization of the policy, and the use
        /// of callbacks to satisfy the conditions in a policy (e.g. knowledge
        /// of a private key, or the NV-index associated with a name.
        /// </summary>
        /// <param name="tpm">Reference to the TPM used.</param>
        static void SamplePolicySerializationAndCallbacks(Tpm2 tpm)
        {
            Console.WriteLine("Policy sample that serializes all policy commands.");

            //
            // 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.PolicyPhysicalPresence,
                                       TpmCc.PolicySigned,
                                       TpmCc.PolicySecret,
                                       TpmCc.PolicyPCR,
                                       TpmCc.PolicyLocality,
                                       TpmCc.PolicyNV,
                                       TpmCc.PolicyCounterTimer,
                                       TpmCc.PolicyCommandCode,
                                       TpmCc.PolicyPassword,
                                       TpmCc.PolicyAuthorize,
                                       TpmCc.PolicyPhysicalPresence,
                                       TpmCc.PolicyCpHash,
                                       TpmCc.PolicyTicket,
                                       TpmCc.PolicyNameHash,
                                       TpmCc.PolicyCpHash,
                                       TpmCc.PolicyDuplicationSelect,
                                       TpmCc.PolicyAuthValue,
                                       TpmCc.PolicyNvWritten
            };
            foreach (var commandCode in usedCommands)
            {
                if (!tpm.Helpers.IsImplemented(commandCode))
                {
                    Console.WriteLine("Cancel Policy serialization and callback sample, because command {0} is not implemented by TPM.", commandCode);
                    return;
                }
            }

            //
            // AuthValue encapsulates an authorization value: essentially a byte-array.
            // OwnerAuth is the owner authorization value of the TPM-under-test. We
            // assume that it (and other) auths are set to the default (null) value.
            // If running on a real TPM, which has been provisioned by Windows, this
            // value will be different. An administrator can retrieve the owner
            // authorization value from the registry.
            //
            var ownerAuth = new AuthValue();

            var pInit = new PolicyTree(TpmAlgId.Sha256);
            var p = new PolicyTree(TpmAlgId.Sha256);

            //
            // In the first part of this sample we establish keys, NV-slots, 
            // etc. that will be used in the policy.
            // 

            //
            // create a new RSA software signing key. We will use this for both 
            // TpmPolicySigned AND TpmPolicyAuthorize.
            // 
            var signKeyPublicTemplate = new TpmPublic(TpmAlgId.Sha256,
                                                      ObjectAttr.Sign | ObjectAttr.Restricted | ObjectAttr.FixedTPM,
                                                      new byte[0],
                                                      new RsaParms(new SymDefObject(),
                                                                   new SchemeRsassa(TpmAlgId.Sha256), 
                                                                   2048, 0),
                                                      new Tpm2bPublicKeyRsa());
            _publicSigningKey = new AsymCryptoSystem(signKeyPublicTemplate);

            //
            // Get an authorization ticket for TpmPolicyAuthorize. We will authorize
            // a policy-digest consisting of policyPhysPresense.
            // 
            var tempPolicy = new PolicyTree(TpmAlgId.Sha256);
            tempPolicy.Create(
                new PolicyAce[]
                {
                    new TpmPolicyPhysicalPresence(), 
                    "leaf"
                });

            TpmHash initPolicyHash = tempPolicy.GetPolicyDigest();
            var policyAuthRef = new byte[0];
            byte[] dataToSign = Globs.Concatenate(initPolicyHash.HashData, policyAuthRef);
            byte[] aHash = CryptoLib.HashData(TpmAlgId.Sha256, 
                                              Globs.Concatenate(initPolicyHash.HashData, policyAuthRef));

            //
            // Sign the simple policy just containing PolicyPhysPres so that 
            // we can change it to a new value with PolicyAuthorize.
            // 
            ISignatureUnion policyAuthSig = _publicSigningKey.Sign(dataToSign);

            //
            // Get a ticket verifying the signature.
            // 
            TpmHandle verifierHandle = tpm.LoadExternal(null, _publicSigningKey.GetPublicParms(), TpmHandle.RhOwner);
            tpm.VerifySignature(verifierHandle, aHash, policyAuthSig);
            tpm.FlushContext(verifierHandle);

            //
            // Get the value of PCR[1]
            // 
            var pcrs = new uint[] { 1 };
            var sel = new PcrSelection(TpmAlgId.Sha, pcrs);
            PcrSelection[] selOut;
            Tpm2bDigest[] pcrValues;
            tpm.PcrRead(new[] { sel }, out selOut, out pcrValues);

            //
            // Save the current PCR values in a convenient data structure
            // 
            var expectedPcrVals = new PcrValueCollection(selOut, pcrValues);

            //
            // Set up an NV slot
            // 
            TpmHandle nvHandle = TpmHandle.NV(3001);

            //
            // Clean anything that might have been there before
            // 
            tpm[ownerAuth]._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle);

            AuthValue nvAuth = AuthValue.FromRandom(8);

            tpm[ownerAuth].NvDefineSpace(TpmHandle.RhOwner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1,
                                         NvAttr.TpmaNvAuthread | NvAttr.TpmaNvAuthwrite, new byte[0], 32));
            //
            // write some data
            // 
            var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
            tpm[nvAuth].NvWrite(nvHandle, nvHandle, nvData, 0);
            byte[] nvName;
            tpm.NvReadPublic(nvHandle, out nvName);

            //
            // Install evaluation callback
            // Note: generally the callback will check that the parameters are
            // actions that it is willing to authorize. Those checks are omitted here.
            // 
            p.SetNvCallback((PolicyTree policyTree,
                             TpmPolicyNV ace,
                             out SessionBase authorizingSession,
                             out TpmHandle authorizedEntityHandle,
                             out TpmHandle nvHandleIs) =>
            {
                authorizedEntityHandle = nvHandle;
                nvHandleIs = nvHandle;
                authorizingSession = nvAuth;
            });

            //
            // counter-timer:  The policy will check that the reset-count
            // is the current value.
            // 
            int start, end;
            TimeInfo now = tpm.ReadClock();            
            Marshaller.GetFragmentInfo(now, "resetCount", out start, out end);
            byte[] operandB = Marshaller.GetTpmRepresentation(now.clockInfo.resetCount);

            //
            // Get a cpHash for the command we want to execute
            // 
            var cpHash = new TpmHash(TpmAlgId.Sha256);
            tpm._GetCpHash(cpHash).HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth);

            p.SetSignerCallback(SignerCallback);

            //
            // PolicySecret tests knowledge of ownerAuth. Note that the callback 
            // will generally check that it is prepared to authorize what it is 
            // being asked to authorize. Those checks are omitted here (we just
            // provide a PWAP session containing ownerAuth.
            // 
            p.SetPolicySecretCallback((PolicyTree policyTree,
                                       TpmPolicySecret ace,
                                       out SessionBase authorizingSession,
                                       out TpmHandle authorizedEntityHandle,
                                       out bool flushAuthEntity) =>
            {
                authorizingSession = ownerAuth;
                authorizedEntityHandle = TpmHandle.RhOwner;
                flushAuthEntity = false;
            });

            //
            // If the policy contains a TpmPolicyAction then print out the 
            // action string on the console.  
            // 
            p.SetPolicyActionCallback((PolicyTree policy, TpmPolicyAction ace)
                                      => Console.WriteLine(ace.Action));

            var policyRef = new byte[] { 1, 2, 3, 4 };

            //
            // Ticket expiration times have to be negative.
            // Positive expiration times do not generate a ticket.
            // 
            _expectedExpirationTime = -60;

            //
            // A normalized policy is an array of policy-chains written as 
            // arrays. Here "most" of the policy-ACEs are in the first chain, but some 
            // ACEs cannot co-exist, and some need a ticket from a prior evaluation.
            // 
            pInit.CreateNormalizedPolicy(
                new[] 
                {
                    new PolicyAce[]
                    {
                        new TpmPolicySigned(_publicSigningKey.GetPublicParms().GetName(),
                                                                                // Newly created PubKey
                                            true,                               // Nonce in signed data
                                            _expectedExpirationTime,            // expirationTime
                                            new byte[0],                        // cpHash
                                            policyRef)                          // policyRef
                        {NodeId = "Signing Key 1"},                             // Distinguishing name

                        //
                        // Include owner-auth
                        // 
                        new TpmPolicySecret(TpmHandle.RhOwner.GetName(), true,
                                            new byte[0], new byte[] {1, 2, 3}, 0),

                        //
                        // Include PCR-values read earlier
                        // 
                        new TpmPolicyPcr(expectedPcrVals), 

                        //
                        // Command must be issued at locality two
                        // 
                        new TpmPolicyLocality(LocalityAttr.TpmLocTwo), 

                        //
                        // NV-data we set earlier must be present
                        // 
                        new TpmPolicyNV(nvName, nvData, 0, Eo.Eq), 

                        //
                        // This is a "dummy ACE" that is not executed on the TPM but
                        // a callback will be invoked at when the policy is executed.
                        // One use case for this is to increment a counter between two
                        // PolicyNV counter-checks.
                        // 
                        new TpmPolicyAction("Output of TpmPolicyAction when executed."),

                        //
                        // Boot-count must be what we read earlier
                        // 
                        new TpmPolicyCounterTimer(operandB, (ushort) start, Eo.Eq),

                        //
                        // Only authorize HierarchyChangeAuth
                        // 
                        new TpmPolicyCommand(TpmCc.HierarchyChangeAuth),

                        //
                        // Include password
                        // 
                        new TpmPolicyPassword(), 

                        //
                        // Authorize a change from PolicyPP (last ACE below)
                        // 
                        new TpmPolicyAuthorize(initPolicyHash.HashData, 
                                               policyAuthRef, 
                                               _publicSigningKey.GetPublicParms(), 
                                               TpmAlgId.Sha256, 
                                               policyAuthSig),
                        //
                        // Demand that the command be executed with PP asserted
                        // 
                        new TpmPolicyPhysicalPresence(), 

                        //
                        // Name for this branch
                        //
                        "branch_1"
                    },

                    new PolicyAce[]
                    {
                        //
                        // Bind to command/parameters
                        //
                        new TpmPolicyCpHash(cpHash),   

                        //
                        // Name for this branch
                        //
                        "branch_2"
                    },

                    new PolicyAce[]
                    {
                        new TpmPolicyTicket(_publicSigningKey.GetPublicParms(),
                                            policyRef,
                                            TpmSt.AuthSigned)
                        //
                        // Distinguishing name for this node
                        //
                        {NodeId = "PolicyTicket"},     

                        //
                        // Name for this branch
                        //
                        "branch_3"
                    },

                    //
                    // TODO: These ACEs are not evaluated yet in this sample
                    //
                    new PolicyAce[]
                    {
                        new TpmPolicyNameHash(),
                        new TpmPolicyCpHash(cpHash),
                        new TpmPolicyDuplicationSelect(new byte[0], new byte[0], true), 
                        new TpmPolicyAuthValue(), // Include entity authValue in HMAC
                        new TpmPolicyNvWritten(),
                        "branch_4"
                    }
                }
            );

            TpmHash policyHash = pInit.GetPolicyDigest();

            //
            // Check that we can serialize and deserialize the policy
            // 
            const string fileName = @".\test1.xml";
            pInit.SerializeToFile("Sample Policy",PolicySerializationFormat.Xml, fileName);
            p.DeserializeFromFile(PolicySerializationFormat.Xml, fileName);
            
            //
            // And check that the policy hash is the same
            // 
            TpmHash deserializedHash = p.GetPolicyDigest();
            if (policyHash != deserializedHash)
            {
                throw new Exception("Serialization error");
            }

            //
            // Execute the policy on the TPM. Start with "branch_1".
            // 
            AuthSession s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256);
            s0.RunPolicy(tpm, p, "branch_1");

            //
            // Check that the executed policy has the correct digest
            // 
            byte[] actualPolicyDigest = tpm.PolicyGetDigest(s0.Handle);
            if (policyHash != actualPolicyDigest)
            {
                throw new Exception("Policy Evaluation error");
            }

            //
            // Set a command to use the policy
            // 
            tpm[ownerAuth].SetPrimaryPolicy(TpmHandle.RhOwner, policyHash.HashData, TpmAlgId.Sha256);

            //
            // And then execute the command
            // 
            tpm._AssertPhysicalPresence(true);
            tpm._SetLocality(LocalityAttr.TpmLocTwo);
            tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth);
            tpm._SetLocality(LocalityAttr.TpmLocZero);
            tpm._AssertPhysicalPresence(false);
            tpm.FlushContext(s0.Handle);

            //
            // Next, "branch_2".
            // 
            s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256);
            s0.RunPolicy(tpm, p, "branch_2");
            tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth);
            tpm.FlushContext(s0.Handle);

            //
            // Now "branch_3" - ticket. Copy parms out of the ticket/ACE returned
            // from TpmPolicySinged above.
            // 
            var sigAce = p.GetAce<TpmPolicySigned>("Signing Key 1");
            TkAuth signedTicket = p.GetTicket("Signing Key 1");

            var tickAce = p.GetAce<TpmPolicyTicket>("PolicyTicket");
            tickAce.CpHash = sigAce.CpHash;
            tickAce.PolicyRef = sigAce.PolicyRef;
            tickAce.ExpirationTime = sigAce.GetTimeout();
            tickAce.SetTicket(signedTicket);

            s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256);
            s0.RunPolicy(tpm, p, "branch_3");
            tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth);
            tpm.FlushContext(s0.Handle);

            Console.WriteLine("Finished SamplePolicySerializationAndCallbacks.");
        }
Esempio n. 3
0
        // ReSharper disable once InconsistentNaming
        internal override TpmRc Execute(Tpm2 tpm, AuthSession authSession, PolicyTree policy)
        {
            byte[] dataToSign = Globs.Concatenate(PolicyToReplace, PolicyRef);
            byte[] aHash = CryptoLib.HashData(SigningHash, dataToSign);

            TpmHandle verifierHandle = tpm.LoadExternal(null, SigningKey, TpmRh.Owner);
            if (policy.AllowErrorsInPolicyEval)
            {
                tpm._AllowErrors();
            }

            // todo - fix the serialization so that we can persist the interface
            ISignatureUnion theSig = null;
            if(null!= (Object) Sig1)
            {
                theSig = Sig1;
            }
            if (null != (Object)Sig2)
            {
                theSig = Sig2;
            }

            if (theSig != null)
            {
                Ticket = tpm.VerifySignature(verifierHandle, aHash, theSig);
                TpmRc intermediateError = tpm._GetLastResponseCode();
                if (intermediateError != TpmRc.Success)
                {
                    tpm.FlushContext(verifierHandle);
                    return intermediateError;
                }
            }
            else
            {
                // create a dummy ticket = e.g. for a trial session
                Ticket = new TkVerified(TpmRh.Owner, new byte[0]);
            }
            tpm.FlushContext(verifierHandle);


            byte[] keySign = SigningKey.GetName();
            TpmHandle policySession = authSession;
            if (TheParamsCallback != null)
            {
                TheParamsCallback(tpm, ref policySession, ref PolicyToReplace, ref PolicyRef, keySign, ref Ticket);
            }
            if (policy.AllowErrorsInPolicyEval)
            {
                tpm._AllowErrors();
            }
            tpm.PolicyAuthorize(policySession, PolicyToReplace, PolicyRef, keySign, Ticket);

            return tpm._GetLastResponseCode();
        }
Esempio n. 4
0
        // ReSharper disable once InconsistentNaming
        internal override TpmRc Execute(Tpm2 tpm, AuthSession authSession, PolicyTree policy)
        {
            byte[] nonceTpm = UseNonceTpm ? Globs.CopyData(authSession.NonceTpm) : new byte[0];

            var dataToSign = new Marshaller();
            dataToSign.Put(nonceTpm, "");
            ISignatureUnion signature;
            // If the library has been given a signing key we can do the challenge here (else we need to call out)
            TpmHandle verificationKey;
            if (SigningKey != null)
            {
                dataToSign.Put(ExpirationTime, "");
                dataToSign.Put(CpHash, "");
                dataToSign.Put(PolicyRef, "");
                // Just ask the key to sign the challenge
                signature = SigningKey.Sign(dataToSign.GetBytes());
                verificationKey = tpm.LoadExternal(null, SigningKeyPub, TpmRh.Owner);
            }
            else
            {
                TpmPublic verifier;
                signature = AssociatedPolicy.ExecuteSignerCallback(this, nonceTpm, out verifier);
                verificationKey = tpm.LoadExternal(null, verifier, TpmRh.Owner);
            }
            TkAuth policyTicket;

            Timeout = tpm.PolicySigned(verificationKey,
                                       authSession,
                                       nonceTpm,
                                       CpHash,
                                       PolicyRef,
                                       ExpirationTime,
                                       signature,
                                       out policyTicket);

            TpmRc responseCode = tpm._GetLastResponseCode();
            // Save the policyTicket in case it is needed later
            PolicyTicket = policyTicket;
            tpm.FlushContext(verificationKey);
            return responseCode;
        }
Esempio n. 5
0
        /// <summary>
        /// This sample demonstrates the creation of a signing "primary" key and use of this
        /// key to sign data, and use of the TPM and Tpm2Lib to validate the signature.
        /// </summary>
        /// <param name="args">Arguments to this program.</param>
        static void Main(string[] args)
        {
            //
            // Parse the program arguments. If the wrong arguments are given or
            // are malformed, then instructions for usage are displayed and 
            // the program terminates.
            // 
            string tpmDeviceName;
            if (!ParseArguments(args, out tpmDeviceName))
            {
                WriteUsage();
                return;
            }

            try
            {
                //
                // Create the device according to the selected connection.
                // 
                Tpm2Device tpmDevice;
                switch (tpmDeviceName)
                {
                    case DeviceSimulator:
                        tpmDevice = new TcpTpmDevice(DefaultSimulatorName, DefaultSimulatorPort);
                        break;

                    case DeviceWinTbs:
                        tpmDevice = new TbsDevice();
                        break;

                    default:
                        throw new Exception("Unknown device selected.");
                }
                //
                // Connect to the TPM device. This function actually establishes the
                // connection.
                // 
                tpmDevice.Connect();

                //
                // Pass the device object used for communication to the TPM 2.0 object
                // which provides the command interface.
                // 
                var tpm = new Tpm2(tpmDevice);
                if (tpmDevice is TcpTpmDevice)
                {
                    //
                    // If we are using the simulator, we have to do a few things the
                    // firmware would usually do. These actions have to occur after
                    // the connection has been established.
                    // 
                    tpmDevice.PowerCycle();
                    tpm.Startup(Su.Clear);
                }

                //
                // AuthValue encapsulates an authorization value: essentially a byte-array.
                // OwnerAuth is the owner authorization value of the TPM-under-test.  We
                // assume that it (and other) auths are set to the default (null) value.
                // If running on a real TPM, which has been provisioned by Windows, this
                // value will be different. An administrator can retrieve the owner
                // authorization value from the registry.
                //
                var ownerAuth = new AuthValue();

                // 
                // The TPM needs a template that describes the parameters of the key
                // or other object to be created.  The template below instructs the TPM 
                // to create a new 2048-bit non-migratable signing key.
                // 
                var keyTemplate = new TpmPublic(TpmAlgId.Sha1,                                  // Name algorithm
                                                ObjectAttr.UserWithAuth | ObjectAttr.Sign |     // Signing key
                                                ObjectAttr.FixedParent  | ObjectAttr.FixedTPM | // Non-migratable 
                                                ObjectAttr.SensitiveDataOrigin,
                                                new byte[0],                                    // No policy
                                                new RsaParms(new SymDefObject(), 
                                                             new SchemeRsassa(TpmAlgId.Sha1), 2048, 0),
                                                new Tpm2bPublicKeyRsa());

                // 
                // Authorization for the key we are about to create.
                // 
                var keyAuth = new byte[] { 1, 2, 3 };

                TpmPublic keyPublic;
                CreationData creationData;
                TkCreation creationTicket;
                byte[] creationHash;

                // 
                // Ask the TPM to create a new primary RSA signing key.
                // 
                TpmHandle keyHandle = tpm[ownerAuth].CreatePrimary(
                    TpmHandle.RhOwner,                          // In the owner-hierarchy
                    new SensitiveCreate(keyAuth, new byte[0]),  // With this auth-value
                    keyTemplate,                                // Describes key
                    new byte[0],                                // For creation ticket
                    new PcrSelection[0],                        // For creation ticket
                    out keyPublic,                              // Out pubKey and attributes
                    out creationData, out creationHash,         // Not used here
                    out creationTicket);

                // 
                // Print out text-versions of the public key just created
                // 
                Console.WriteLine("New public key\n" + keyPublic.ToString());

                // 
                // Use the key to sign some data
                // 
                byte[] message = Encoding.Unicode.GetBytes("ABC");
                TpmHash dataToSign = TpmHash.FromData(TpmAlgId.Sha1, message);

                // 
                // A different structure is returned for each signing scheme, 
                // so cast the interface to our signature type (see third argument).
                // 
                // As an alternative, 'signature' can be of type ISignatureUnion and
                // cast to SignatureRssa whenever a signature specific type is needed.
                // 
                var signature = tpm[keyAuth].Sign(keyHandle,                       // Handle of signing key
                                                  dataToSign.HashData,             // Data to sign
                                                  new SchemeRsassa(TpmAlgId.Sha1), // Default scheme
                                                  TpmHashCheck.NullHashCheck()) as SignatureRsassa;
                // 
                // Print the signature.
                // 
                Console.WriteLine("Signature: " + BitConverter.ToString(signature.sig));

                // 
                // Use the TPM library to validate the signature
                // 
                bool sigOk = keyPublic.VerifySignatureOverData(message, signature);
                if (!sigOk)
                {
                    throw new Exception("Signature did not validate.");
                }

                Console.WriteLine("Verified signature with TPM2lib (software implementation).");

                // 
                // Load the public key into another slot in the TPM and then 
                // use the TPM to validate the signature
                // 
                TpmHandle pubHandle = tpm.LoadExternal(null, keyPublic, TpmHandle.RhOwner);
                tpm.VerifySignature(pubHandle, dataToSign.HashData, signature);
                Console.WriteLine("Verified signature with TPM.");

                // 
                // The default behavior of Tpm2Lib is to create an exception if the 
                // signature does not validate. If an error is expected the library can 
                // be notified of this, or the exception can be turned into a value that
                // can be later queried. The following are examples of this.
                // 
                signature.sig[0] ^= 1;
                tpm._ExpectError(TpmRc.Signature).VerifySignature(pubHandle, dataToSign.HashData, signature);

                tpm._AllowErrors().VerifySignature(pubHandle, dataToSign.HashData, signature);
                if (tpm._GetLastResponseCode() != TpmRc.Signature)
                {
                    throw new Exception("TPM returned unexpected return code.");
                }

                Console.WriteLine("Verified that invalid signature causes TPM_RC_SIGNATURE return code.");

                // 
                // Clean up of used handles.
                // 
                tpm.FlushContext(keyHandle);
                tpm.FlushContext(pubHandle);

                // 
                // (Note that serialization is not supported on WinRT)
                // 
                // Demonstrate the use of XML persistence by saving keyPublic to 
                // a file and making a copy by reading it back into a new object
                // 
                // NOTE: 12-JAN-2016: May be removing support for policy
                //       serialization. We'd like to get feedback on whether
                //       this is a desirable feature and should be retained.
                //
                // {
                //     const string fileName = "sample.xml";
                //     string xmlVersionOfObject = keyPublic.GetXml();
                //     keyPublic.XmlSerializeToFile(fileName);
                //     var copyOfPublic = TpmStructureBase.XmlDeserializeFromFile<TpmPublic>(fileName);
                //     
                //     // 
                //     // Demonstrate Tpm2Lib support of TPM-structure equality operators
                //     // 
                //     if (copyOfPublic != keyPublic)
                //     {
                //         Console.WriteLine("Library bug persisting data.");
                //     }
                // }
                //

                //
                // Clean up.
                // 
                tpm.Dispose();
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception occurred: {0}", e.Message);
            }

            Console.WriteLine("Press Any Key to continue.");
            Console.ReadLine();
        }