Пример #1
0
        void ExternalKeyImportSample(Tpm2 tpm, TestContext testCtx)
        {
            // Create a software key (external to any TPM).
            int keySize        = 2048;
            var externalRsaKey = new RawRsa(keySize);

            // When an external key comes from a cert, one would need to extract the key size and
            // byte buffers representing public and private parts of the key from the cert, an use
            // them directly in the call to ImportExternalRsaKey() below (i.e. no RawRsa object is
            // necessary).

            // Signing scheme to use (it may come from the key's cert)
            TpmAlgId sigHashAlg = Substrate.Random(TpmCfg.HashAlgs);
            var      sigScheme  = new SchemeRsassa(sigHashAlg);

            // An arbitrary external key would not have TPM key attributes associated with it.
            // Yet some of them may be inferred from the cert based on the declared key purpose
            // (ObjectAttr.Sign below). The others are defined by the intended TPM key usage
            // scenarios, e.g. ObjectAttr.UserWithAuth tells TPM to allow key usage authorization
            // using an auth value (random byte buffer) in a password or an HMAC session.
            ObjectAttr keyAttrs = ObjectAttr.Sign | ObjectAttr.UserWithAuth;

            // Generate an auth value for the imported matching in strength the signing scheme
            byte[] authVal = Substrate.RandomAuth(sigHashAlg);

            // We need a storage key to use as a parent of the imported key.
            // The following helper creates an RSA primary storage key.
            TpmHandle hParent = Substrate.CreateRsaPrimary(tpm);

            TssObject importedKey = ImportExternalRsaKey(tpm, hParent,
                                                         keySize, sigScheme,
                                                         externalRsaKey.Public, externalRsaKey.Private,
                                                         keyAttrs, authVal);

            // Now we can load the newly imported key into the TPM, ...
            TpmHandle hImportedKey = tpm.Load(hParent, importedKey.Private, importedKey.Public);

            // ... let the TSS know the auth value associated with this handle, ...
            hImportedKey.SetAuth(authVal);

            // ... and use it to sign something to check if import was OK
            TpmHash         toSign = TpmHash.FromRandom(sigHashAlg);
            ISignatureUnion sig    = tpm.Sign(hImportedKey, toSign, null, new TkHashcheck());

            // Verify that the signature is correct using the public part of the imported key
            bool sigOk = importedKey.Public.VerifySignatureOverHash(toSign, sig);

            testCtx.Assert("Signature.OK", sigOk);

            // Cleanup
            tpm.FlushContext(hImportedKey);
            // The parent key handle can be flushed immediately after it was used in the Load() command
            tpm.FlushContext(hParent);

            // Imported private/public key pair (in the TssObject) can be stored on disk, in the cloud,
            // etc. (no additional protection is necessary), and loaded into the TPM as above whenever
            // the key is needed.

            // Alternatively the key can be persisted in the TPM using the EvictControl() command
        } // ExternalKeyImportSample
Пример #2
0
        } //NVCounter

        internal static void CreateTwoPrimaries(Tpm2 tpm)
        {
            var data = Encoding.UTF8.GetBytes("hello world");

            var handle1 = KeyHelpers.CreatePrimaryRsaKey(tpm, null, null, null, out TpmPublic key);

            IAsymSchemeUnion decScheme = new SchemeOaep(TpmAlgId.Sha1);

            var cipher = tpm.RsaEncrypt(handle1, data, decScheme, null);

            byte[] decrypted1 = tpm.RsaDecrypt(handle1, cipher, decScheme, null);

            var decyyptedData = Encoding.UTF8.GetString(decrypted1);



            var pub = tpm.ReadPublic(handle1, out byte[] name, out byte[] qn);

            var enc = KeyHelpers.CreateEncryptionDecryptionKey(tpm, handle1);

            tpm._ExpectResponses(TpmRc.Success, TpmRc.TbsCommandBlocked);
            var cipher2 = tpm.EncryptDecrypt(enc, 1, TpmAlgId.None, data, data, out byte[] test2);

            tpm.FlushContext(handle1);

            var handle2 = KeyHelpers.CreatePrimary(tpm, out TpmPublic key3); //, seed: new byte[] { 22, 123, 22, 1, 33 });

            tpm.FlushContext(handle2);
        }
Пример #3
0
        void TestCertifyX509_1(Tpm2 tpm, TestContext testCtx)
        {
            testCtx.ReportParams("Test phase: TestCertifyX509_1");

            var policy = new PolicyTree(TpmAlgId.Sha256);

            policy.SetPolicyRoot(new TpmPolicyCommand(TpmCc.CertifyX509));

            var keyTemplate = new TpmPublic(
                TpmAlgId.Sha256,
                ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.UserWithAuth | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin,
                policy.GetPolicyDigest(),
                new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0),
                new Tpm2bPublicKeyRsa()
                );

            // Make two keys
            TpmPublic certifyingKeyPub, keyToBeCertifiedPub;
            TpmHandle hCertifyingKey    = Substrate.CreatePrimary(tpm, keyTemplate, out certifyingKeyPub);
            TpmHandle hKeyToBeCertified = Substrate.CreatePrimary(tpm, keyTemplate, out keyToBeCertifiedPub);

            var partialCert      = CertifyX509Support.MakeExemplarPartialCert();
            var partialCertBytes = partialCert.GetDerEncoded();

            // If you want to paste in your own hex put it here and s
            //var partialCertBytes = Globs.ByteArrayFromHex("01020304");

            AuthSession sess = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256);

            sess.RunPolicy(tpm, policy);

            // I used this to test that the auth is OK.  Of course you need to change the PolicyCommandCode above
            //var attestInfo = tpm[sess].Certify(hKeyToBeCertified, hCertifyingKey, new byte[0], new NullSigScheme(), out var legacySignature);

            byte[]          tbsHash;
            ISignatureUnion signature;

            byte[] addedTo     = tpm[sess].CertifyX509(hKeyToBeCertified, hCertifyingKey, new byte[0], new NullSigScheme(), partialCertBytes, out tbsHash, out signature);
            var    addedToCert = AddedToCertificate.FromDerEncoding(addedTo);

            var returnedCert = CertifyX509Support.AssembleCertificate(partialCert, addedToCert, ((SignatureRsa)signature).GetTpmRepresentation());

            // Does the expected hash match the returned hash?
            var tbsBytes        = returnedCert.GetTbsCertificate();
            var expectedTbsHash = TpmHash.FromData(TpmAlgId.Sha256, tbsBytes);

            Debug.Assert(Globs.ArraysAreEqual(expectedTbsHash.HashData, tbsHash));

            // If you get this far we can check the cert is properly signed but we'll need to do a
            // bit of TPM<->Bouncy Castle data type conversion.


            tpm.FlushContext(hCertifyingKey);
            tpm.FlushContext(hKeyToBeCertified);
        } // TestCertifyX509_1
Пример #4
0
        void EcdhSample(Tpm2 tpm, TestContext testCtx)
        {
            //
            // Peer A (e.g. local machine):
            //

            // Template for an ECC key with the ECDH scheme:
            var inPub = new TpmPublic(TpmAlgId.Sha256,
                                      ObjectAttr.Decrypt | ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin,
                                      null,
                                      new EccParms(new SymDefObject(), new SchemeEcdh(TpmAlgId.Sha256),
                                                   EccCurve.NistP256, new NullKdfScheme()),
                                      new EccPoint());

            // Boilerplate stuff
            var          pcrSel = new PcrSelection[0];
            CreationData crData;

            byte[]     crHash;
            TkCreation crTk;

            // Create a key for ECDH
            TpmPublic pubA;
            TpmHandle hKeyA = tpm.CreatePrimary(TpmRh.Owner, new SensitiveCreate(), inPub, null, new PcrSelection[0],
                                                out pubA, out crData, out crHash, out crTk);

            //
            // Peer B (e.g. remote machine):
            //

            // Receives 'pubA' from peer A

            // Load public key
            TpmHandle hPubKeyA = tpm.LoadExternal(null, pubA, TpmRh.Owner);

            // Create shared secret 'zB', and a public ECC point for exchange
            EccPoint ephPubPt;
            EccPoint zB = tpm.EcdhKeyGen(hPubKeyA, out ephPubPt);

            tpm.FlushContext(hPubKeyA);

            //
            // Peer A again:
            //

            // Receives 'ephPubPt' from peer B

            // A full key is required here
            EccPoint zA = tpm.EcdhZGen(hKeyA, ephPubPt);

            testCtx.AssertEqual("SharedSecret", zA, zB);

            tpm.FlushContext(hKeyA);
        } // EcdhSample
Пример #5
0
        void DuplicateImportRsaSample(Tpm2 tpm, TestContext testCtx)
        {
            TpmAlgId nameAlg = Substrate.Random(TpmCfg.HashAlgs);
            var      policy  = new PolicyTree(nameAlg);

            policy.SetPolicyRoot(new TpmPolicyCommand(TpmCc.Duplicate));

            var inPub = new TpmPublic(nameAlg,
                                      ObjectAttr.Sign | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin,
                                      policy.GetPolicyDigest(),
                                      new RsaParms(new SymDefObject(),
                                                   new SchemeRsassa(Substrate.Random(TpmCfg.HashAlgs)),
                                                   Substrate.Random(TpmCfg.RsaKeySizes), 0),
                                      new Tpm2bPublicKeyRsa());

            TpmHandle hKey = Substrate.CreateAndLoad(tpm, inPub, out TpmPublic pub);

            // Duplicate
            TpmPrivate priv = TpmHelper.GetPlaintextPrivate(tpm, hKey, policy);

            tpm.FlushContext(hKey);

            // Import
            TpmPrivate privImp = tpm.Import(Substrate.LoadRsaPrimary(tpm), null, pub, priv, null, new SymDefObject());
        } // SimpleDuplicateImportRsaSample
Пример #6
0
        /// <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
            //
            TpmHandle hashHandle = tpm.HashSequenceStart(AuthValue.FromRandom(8), 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.
            // It picks up the appropriate auth value from the handle used in the command
            // (hashHandle in this case).
            //
            TkHashcheck validate;

            tpm[s0].SequenceUpdate(hashHandle, new byte[] { 0, 2, 1 });
            byte[] hashedData = tpm[s0].SequenceComplete(hashHandle,
                                                         new byte[] { 2, 3, 4 },
                                                         TpmRh.Owner,
                                                         out validate);

            Console.WriteLine("Hashed data (HMAC authorized sequence): " + BitConverter.ToString(hashedData));
            tpm.FlushContext(s0);
        }
Пример #7
0
        void TestSerialization(Tpm2 tpm, TestContext testCtx)
        {
            // test library serialization (not a TPM test)
            TpmAlgId hashAlg = Substrate.Random(TpmCfg.HashAlgs);

            // make some moderately complicated TPM structures
            var inPub = new TpmPublic(hashAlg,
                                      ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
                                      | ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin,
                                      null,
                                      new RsaParms(new SymDefObject(), new SchemeRsassa(hashAlg),
                                                   Substrate.Random(TpmCfg.RsaKeySizes), 0),
                                      new Tpm2bPublicKeyRsa());

            TpmPublic pub;
            TpmHandle hKey = Substrate.CreateAndLoad(tpm, inPub, out pub);

            TpmHash hashToSign = TpmHash.FromRandom(hashAlg);
            var     proof      = new TkHashcheck(TpmRh.Null, null);
            var     sig        = tpm.Sign(hKey, hashToSign, new SchemeRsassa(hashAlg), proof);

            tpm.FlushContext(hKey);

            // Simple TPM-hash to/from JSON
            TpmHash h = TpmHash.FromString(hashAlg, "hello");

            MemoryStream s2 = new MemoryStream();
            DataContractJsonSerializer ser2 = new DataContractJsonSerializer(typeof(TpmHash));

            ser2.WriteObject(s2, h);
            s2.Flush();
            string jsonString2 = Encoding.ASCII.GetString(s2.ToArray());

            TpmHash h2 = (TpmHash)ser2.ReadObject(new MemoryStream(s2.ToArray()));

            testCtx.AssertEqual("JSON.Simple", h, h2);

            // JSON more complex -
            MemoryStream s = new MemoryStream();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TpmPublic));

            ser.WriteObject(s, pub);
            s.Flush();
            string    jsonString  = Encoding.ASCII.GetString(s.ToArray());
            TpmPublic reconstruct = (TpmPublic)ser.ReadObject(new MemoryStream(s.ToArray()));

            testCtx.AssertEqual("JSON.Complex", pub, reconstruct);

            // XML
            s = new MemoryStream();
            DataContractSerializer s4 = new DataContractSerializer(typeof(TpmPublic));

            s4.WriteObject(s, pub);
            s.Flush();
            string    xmlString = Encoding.ASCII.GetString(s.ToArray());
            TpmPublic rec4      = (TpmPublic)s4.ReadObject(new MemoryStream(s.ToArray()));

            testCtx.AssertEqual("XML.Complex", pub, rec4, s4);
        } // TestSerialization
Пример #8
0
        public void Provision(string encodedHmacKey, string hostName, string deviceId = "")
        {
            TpmHandle    nvHandle      = new TpmHandle(AIOTH_PERSISTED_URI_INDEX + logicalDeviceId);
            TpmHandle    ownerHandle   = new TpmHandle(TpmRh.Owner);
            TpmHandle    hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE + logicalDeviceId);
            TpmHandle    srkHandle     = new TpmHandle(SRK_HANDLE);
            UTF8Encoding utf8          = new UTF8Encoding();

            byte[] nvData  = utf8.GetBytes(hostName + "/" + deviceId);
            byte[] hmacKey = System.Convert.FromBase64String(encodedHmacKey);

            // Open the TPM
            Tpm2Device tpmDevice = new TbsDevice();

            tpmDevice.Connect();
            var tpm = new Tpm2(tpmDevice);

            // Define the store
            tpm.NvDefineSpace(ownerHandle,
                              new byte[0],
                              new NvPublic(nvHandle,
                                           TpmAlgId.Sha256,
                                           NvAttr.Authwrite | NvAttr.Authread | NvAttr.NoDa,
                                           new byte[0],
                                           (ushort)nvData.Length));

            // Write the store
            tpm.NvWrite(nvHandle, nvHandle, nvData, 0);

            // Import the HMAC key under the SRK
            TpmPublic    hmacPub;
            CreationData creationData;

            byte[]     creationhash;
            TkCreation ticket;
            TpmPrivate hmacPrv = tpm.Create(srkHandle,
                                            new SensitiveCreate(new byte[0],
                                                                hmacKey),
                                            new TpmPublic(TpmAlgId.Sha256,
                                                          ObjectAttr.UserWithAuth | ObjectAttr.NoDA | ObjectAttr.Sign,
                                                          new byte[0],
                                                          new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)),
                                                          new Tpm2bDigestKeyedhash()),
                                            new byte[0],
                                            new PcrSelection[0],
                                            out hmacPub,
                                            out creationData,
                                            out creationhash,
                                            out ticket);

            // Load the HMAC key into the TPM
            TpmHandle loadedHmacKey = tpm.Load(srkHandle, hmacPrv, hmacPub);

            // Persist the key in NV
            tpm.EvictControl(ownerHandle, loadedHmacKey, hmacKeyHandle);

            // Unload the transient copy from the TPM
            tpm.FlushContext(loadedHmacKey);
        }
Пример #9
0
        internal static byte[] RsaDecrypt(Tpm2 tpm, byte[] data)
        {
            var handle1 = KeyHelpers.CreatePrimaryRsaKey(tpm, null, new byte[] { 2 }, new byte[] { 1, 2, 3 }, out TpmPublic key);

            byte[] decrypted1 = tpm.RsaDecrypt(handle1, data, decScheme, null);
            tpm.FlushContext(handle1);
            return(decrypted1);
        }
Пример #10
0
        /// <summary>
        /// This sample illustrates the use of the resource manager built into
        /// Tpm2Lib.  Using the resource manager relieves the programmer of the
        /// (sometimes burdensome) chore of juggling a small number of TPM slots
        /// </summary>
        /// <param name="tpm">Reference to the TPM object.</param>
        static void ResourceManager(Tpm2 tpm)
        {
            //
            // The Tbs device class has a built-in resource manager. We create an
            // instance of the Tbs device class, but hook it up to the TCP device
            // created above. We also tell the Tbs device class to clean the TPM
            // before we start using it.
            // This sample won't work on top of the default Windows resource manager
            // (TBS).
            //
            var tbs    = new Tbs(tpm._GetUnderlyingDevice(), false);
            var tbsTpm = new Tpm2(tbs.CreateTbsContext());

            //
            // Make more sessions than the TPM has room for
            //
            const int count    = 32;
            var       sessions = new AuthSession[count];

            for (int j = 0; j < count; j++)
            {
                sessions[j] = tbsTpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha1);
            }

            Console.WriteLine("Created {0} sessions.", count);

            //
            // And now use them. The resource manager will use ContextLoad and
            // ContextSave to bring them into the TPM
            //
            for (int j = 0; j < count; j++)
            {
                tbsTpm.PolicyAuthValue(sessions[j].Handle);
            }

            Console.WriteLine("Used {0} sessions.", count);

            //
            // And now clean up
            //
            for (int j = 0; j < count; j++)
            {
                tbsTpm.FlushContext(sessions[j].Handle);
            }

            Console.WriteLine("Cleaned up.");

            //
            // Dispose of the Tbs device object.
            //
            tbsTpm.Dispose();
        }
Пример #11
0
        } // CreateRsaPrimaryStorageKey()

        /// <summary>
        /// Main logic of the Import sample.
        /// The sample demonstrates how to create in software (using TSS.net helpers)
        /// keys of different kinds, then import them into TPM and make sure they work.
        /// </summary>
        static void ImportSample(Tpm2 tpm)
        {
            // Templates of the keys to be generated and imported
            var inPubs = new TpmPublic[] {
                new TpmPublic(TpmAlgId.Sha256,
                              ObjectAttr.Decrypt | ObjectAttr.UserWithAuth,
                              null,
                              new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb),
                              new Tpm2bDigestSymcipher()),
                new TpmPublic(TpmAlgId.Sha256,
                              ObjectAttr.Sign | ObjectAttr.UserWithAuth,
                              null,
                              new RsaParms(new SymDefObject(),
                                           new SchemeRsassa(TpmAlgId.Sha256),
                                           2048, 0),
                              new Tpm2bPublicKeyRsa()),
                new TpmPublic(TpmAlgId.Sha256,
                              ObjectAttr.Sign | ObjectAttr.UserWithAuth,
                              null,
                              new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)),
                              new Tpm2bDigestKeyedhash())
            };

            // Create a TPM based key that will serve as a parent for the imported keys.
            // This should be a storage key, i.e. it must have Restricted and Decrypt
            // attributes, no signing or decryption scheme, and non-empty symmetric
            // specification (even if it is an asymmetric key) as part of its parameters.
            // NOTE 1 - We use an empty auth value for the parent key. If you want one,
            // uncomment the optional second parameter.
            // NOTE 2 - The size of the auth value shall not exceed the size of the digest
            // produced by the name algorithm of the key. In this case name algorithm is
            // hardcoded inside the helper, so that we do not have control over it at
            // this point, and therefore we use the maximal number that is safe for any
            // modern hash algorithm (SHA-1 or larger), though for the given implementation
            // of CreateRsaPrimaryStorageKey() we could use 32 (for SHA-256).
            TpmHandle hPrim = CreateRsaPrimaryStorageKey(tpm /*, AuthValue.FromRandom(20)*/);

            foreach (var inPub in inPubs)
            {
                GenerateAndImport(tpm, inPub, hPrim);

                // Now do the same using an inner wrapper (additional layer of cryptographic
                // protection in the form of symmetric encryption for the duplication blob).
                GenerateAndImport(tpm, inPub, hPrim,
                                  new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb));
            }

            tpm.FlushContext(hPrim);
        } // ImportSample()
Пример #12
0
        public static TpmPrivate GetPlaintextPrivate(Tpm2 tpm, TpmHandle key, PolicyTree policy)
        {
            AuthSession sess = tpm.StartAuthSessionEx(TpmSe.Policy, policy.HashAlg);

            sess.RunPolicy(tpm, policy);
            TpmPrivate privPlain = null;

            byte[] symSeed;
            tpm[sess]._ExpectResponses(TpmRc.Success, TpmRc.Attributes)
            .Duplicate(key, TpmRh.Null, null, new SymDefObject(),
                       out privPlain, out symSeed);
            Debug.Assert(!tpm._LastCommandSucceeded() || symSeed.Length == 0);
            tpm.FlushContext(sess);
            return(Globs.IsEmpty(privPlain.buffer) ? null : privPlain);
        }
Пример #13
0
        void TestVendorSpecific(Tpm2 tpm, TestContext testCtx)
        {
            if (!TpmCfg.IsImplemented(TpmCc.VendorTcgTest))
            {
                Substrate.WriteToLog("TestVendorSpecific skipped", ConsoleColor.DarkCyan);
                return;
            }

            TpmHandle h = Substrate.CreateDataObject(tpm);

            byte[] inData = Substrate.RandomBytes(24);

            testCtx.ReportParams("Input data size: " + inData.Length);
            byte[] outData = tpm.VendorTcgTest(inData);
            testCtx.Assert("CertDataReceived", outData.Length > 0, outData.Length);

            tpm.FlushContext(h);
        } // TestVendorSpecific
Пример #14
0
    /// <summary>
    /// Provision the key in the TPM
    /// </summary>
    /// <param name="key">the access key</param>
    public void Provision(byte[] key)
    {
        TpmHandle ownerHandle   = new TpmHandle(TpmRh.Owner);
        TpmHandle hmacKeyHandle = new TpmHandle(PERSISTED_KEY_HANDLE + logicalDeviceId);
        TpmHandle srkHandle     = new TpmHandle(TPM_20_SRK_HANDLE);

        // Open the TPM
        Tpm2Device tpmDevice = new TbsDevice();

        tpmDevice.Connect();
        using (var tpm = new Tpm2(tpmDevice))
        {
#pragma warning disable IDE0059 // Value assigned to symbol is never used
            // Import the HMAC key under the SRK
            TpmPrivate hmacPrv = tpm.Create(srkHandle,
                                            new SensitiveCreate(Array.Empty <byte>(),
                                                                key),
                                            new TpmPublic(TpmAlgId.Sha256,
                                                          ObjectAttr.UserWithAuth | ObjectAttr.NoDA | ObjectAttr.Sign,
                                                          Array.Empty <byte>(),
                                                          new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)),
                                                          new Tpm2bDigestKeyedhash()),
                                            Array.Empty <byte>(),
                                            Array.Empty <PcrSelection>(),
                                            out TpmPublic hmacPub,
                                            out CreationData creationData,
                                            out byte[] creationhash,
                                            out TkCreation ticket);
#pragma warning restore IDE0059 // Value assigned to symbol is never used

            // Load the HMAC key into the TPM
            TpmHandle loadedHmacKey = tpm.Load(srkHandle, hmacPrv, hmacPub);

            // Persist the key in NV
            tpm.EvictControl(ownerHandle, loadedHmacKey, hmacKeyHandle);

            // Unload the transient copy from the TPM
            tpm.FlushContext(loadedHmacKey);
        }
    }
Пример #15
0
        void LoadExternalFullRsaKeySample(Tpm2 tpm, TestContext testCtx)
        {
            var hashAlg = TpmAlgId.Sha256;
            var inPub   = new TpmPublic(hashAlg,
                                        ObjectAttr.Decrypt | ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin,
                                        null,
                                        new RsaParms(new SymDefObject(), new SchemeOaep(hashAlg), 2048, 0),
                                        new Tpm2bPublicKeyRsa());

            // Create a software RSA key
            var swKey = new AsymCryptoSystem(inPub);

            // The crucial point in loading a software key is preparing the TPM-formatted private part of the key
            Sensitive sens = swKey.GetSensitive();

            TpmHandle extKey = tpm.LoadExternal(sens, swKey.GetPublicParms(), TpmRh.Null);

            //
            // Make sure that the key was loaded correctly
            //

            // This particular label is used by the TPM while doing OAEP for its internal protocols
            // (though in n general any label can be used).
            byte[] label   = RawRsa.GetLabel("OaepLabel");
            byte[] origMsg = Substrate.RandomBytes(64);

            // Encrypt using software key (the paublic part is used)
            byte[] encMsg = swKey.EncryptOaep(origMsg, label);

            testCtx.AssertNotEqual("SwEnc", origMsg, encMsg);

            // Decrypt using the TPM (the private part is used)
            byte[] decMsg = tpm.RsaDecrypt(extKey, encMsg, null, label);

            testCtx.AssertEqual("CrossEncDec", origMsg, decMsg);

            tpm.FlushContext(extKey);
        }
Пример #16
0
        /// <summary>
        /// This sample illustrates the use of a TpmPolicyOr.
        /// </summary>
        static void PolicyOr(Tpm2 tpm)
        {
            Console.WriteLine("PolicyOr 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,
                TpmCc.PolicyAuthValue
            };

            foreach (var commandCode in usedCommands)
            {
                if (!tpm.Helpers.IsImplemented(commandCode))
                {
                    Console.WriteLine("Cancel Policy OR sample, because command {0} is not implemented by TPM.", commandCode);
                    return;
                }
            }

            var pcrs = new uint[] { 1, 2, 3 };
            var sel  = new PcrSelection(TpmAlgId.Sha, pcrs);

            PcrSelection[] selOut;
            Tpm2bDigest[]  pcrValues;

            //
            // First read the PCR values
            //
            tpm.PcrRead(new[] { sel }, out selOut, out pcrValues);

            //
            // 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);

            //
            // First branch of PolicyOr
            //
            var branch1 = new PolicyAce[]
            {
                new TpmPolicyPcr(expectedPcrVals),
                "branch_1"
            };

            //
            // Second branch of PolicyOr
            //
            var branch2 = new PolicyAce[]
            {
                new TpmPolicyAuthValue(),
                "branch_2"
            };

            //
            // Create the policy. CreateNormalizedPolicy takes an array-of-arrays
            // of PolicyACEs that are to be OR'ed together (the branches themselves cannot
            // contain TpmPOlicyOrs). The library code constructs a policy tree with
            // minimum number of TpmPolicyOrs at the root.
            //
            policy.CreateNormalizedPolicy(new[] { branch1, branch2 });

            //
            // 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 };
            var       authVal    = new byte[] { 1, 2 };
            TpmHandle primHandle = CreateSealedPrimaryObject(tpm,
                                                             dataToSeal,
                                                             authVal,
                                                             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, "branch_1");

            //
            // And unseal the object
            //
            byte[] unsealedData = tpm[session].Unseal(primHandle);
            Console.WriteLine("Unsealed data for branch_1: " + BitConverter.ToString(unsealedData));

            //
            // Now run the other branch
            //
            tpm.PolicyRestart(session.Handle);
            session.RunPolicy(tpm, policy, "branch_2");

            //
            // And the session will be unusable
            //
            unsealedData = tpm[session].Unseal(primHandle);
            Console.WriteLine("Unsealed data for branch_2: " + BitConverter.ToString(unsealedData));

            //
            // Clean up
            //
            tpm.FlushContext(session.Handle);
            tpm.FlushContext(primHandle);
        }
Пример #17
0
        void TestAutomaticAuth(Tpm2 tpm, TestContext testCtx)
        {
            TpmHandle hPrim = Substrate.LoadRsaPrimary(tpm);

            // Make an RSA encryption key.
            var    decScheme = new SchemeOaep(Substrate.Random(TpmCfg.HashAlgs));
            var    sigScheme = new SchemeRsassa(Substrate.Random(TpmCfg.HashAlgs));
            ushort keyLength = Substrate.RandomRsaKeySize(decScheme.hashAlg);
            var    inPub     = new TpmPublic(Substrate.Random(TpmCfg.HashAlgs),
                                             ObjectAttr.Decrypt | ObjectAttr.Sign
                                             | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
                                             | ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin,
                                             null,
                                             new RsaParms(new SymDefObject(), null, keyLength, 0),
                                             new Tpm2bPublicKeyRsa());

            TpmPublic  keyPublic;
            TpmPrivate keyPrivate = Substrate.Create(tpm, hPrim, inPub, out keyPublic);

            TpmHandle keyHandle = null;

            tpm._Behavior.Strict = true;
            try
            {
                // No auth session is added automatically when TPM object is in strict mode.
                tpm._ExpectError(TpmRc.AuthMissing)
                .Load(hPrim, keyPrivate, keyPublic);

                // Now explicitly request an auth session of appropriate type
                keyHandle = tpm[Auth.Default].Load(hPrim, keyPrivate, keyPublic);
            }
            finally
            {
                tpm._Behavior.Strict = false;
            }

            byte[] message = Substrate.RandBytes(1, TpmHelper.MaxOaepMsgSize(keyLength, decScheme.hashAlg));

            byte[] encrypted = tpm.RsaEncrypt(keyHandle, message, decScheme, null);

            // An auth session is added automatically when TPM object is not in strict mode.
            byte[] decrypted1 = tpm.RsaDecrypt(keyHandle, encrypted, decScheme, null);

            TpmAlgId auditHashAlg = Substrate.Random(TpmCfg.HashAlgs);

            byte[] nonceTpm;

            // AuthSession object can be built from session handle concatenated, if necessary,
            // with session flags and unencrypted salt value (not used in this example).
            AuthSession auditSess = tpm.StartAuthSession(
                TpmRh.Null,                              // no salt
                TpmRh.Null,                              // no bind object
                Substrate.RandomNonce(auditHashAlg),     // nonceCaller
                null,                                    // no salt
                TpmSe.Hmac,                              // session type
                new SymDef(),                            // no encryption/decryption
                auditHashAlg,                            // authHash
                out nonceTpm)
                                    + (SessionAttr.ContinueSession | SessionAttr.Audit);

            /*
             * Alternatively one of the StartAuthSessionEx helpers can be used)
             * AuthSession auditSess = tpm.StartAuthSessionEx(TpmSe.Hmac, auditHashAlg, null,
             *                                                SessionAttr.ContinueSession | SessionAttr.Audit);
             */

            // TSS-specific call to verify TPM auditing correctness.
            tpm._SetCommandAuditAlgorithm(auditHashAlg);

            // Appropriate auth value is added automatically into the provided session
            byte[] decrypted2 = tpm[auditSess]._Audit()
                                .RsaDecrypt(keyHandle, encrypted, decScheme, null);

            ISignatureUnion sig;
            Attest          attest;

            // A session is added automatically to authorize TpmRh.Endorsement usage.
            attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess,
                                               null, new NullSigScheme(), out sig);

            // But if the corresponding auth value stored in the Tpm2 object is invalid, ...
            AuthValue endorsementAuth = tpm.EndorsementAuth;

            tpm.EndorsementAuth = Globs.ByteArray(16, 0xde);
            // ... the command will fail
            tpm._ExpectError(TpmRc.BadAuth)
            .GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess,
                                   null, new NullSigScheme(), out sig);
            // Restore correct auth value.
            tpm.EndorsementAuth = endorsementAuth;

            // Verify that both decryption and auditing worked correctly.
            SessionAuditInfo info = (SessionAuditInfo)attest.attested;

            byte[] auditDigest = tpm._GetAuditHash();
            testCtx.AssertEqual("AuditSessionDigest", info.sessionDigest, auditDigest);
            testCtx.AssertEqual("Decryption", decrypted1, decrypted2);

            // Change auth value of the decryption key.
            TpmPrivate newKeyPrivate = tpm.ObjectChangeAuth(keyHandle, hPrim,
                                                            Substrate.RandomAuth(keyPublic.nameAlg));
            TpmHandle newKeyHandle = tpm.Load(hPrim, newKeyPrivate, keyPublic);

            auditSess.Attrs &= ~SessionAttr.AuditExclusive;
            // Correct auth value (corresponding to newKeyHandle, and different from
            // the one used for keyHandle) will be added to auditSess.
            decrypted1 = tpm[auditSess]._Audit().RsaDecrypt(newKeyHandle, encrypted, decScheme, null);

            // And now two sessions are auto-generated (for TpmRh.Endorsement and keyHandle).
            attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess,
                                               null, sigScheme, out sig);
            bool sigOk = keyPublic.VerifySignatureOverData(
                Marshaller.GetTpmRepresentation(attest), sig);

            testCtx.Assert("AuditSessionSignatute.1", sigOk);

            // Here the first session is generated based on session type indicator
            // (Auth.Pw), and the second one is added automatically.
            attest = tpm[Auth.Pw].GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess,
                                                        null, sigScheme, out sig);

            // Verify that auditing worked correctly.
            sigOk = keyPublic.VerifySignatureOverData(
                Marshaller.GetTpmRepresentation(attest), sig);
            testCtx.Assert("AuditSessionSignatute.2", sigOk);

            tpm.FlushContext(newKeyHandle);
            tpm.FlushContext(auditSess);

            if (!TestCfg.HasTRM)
            {
                // Deplete TPM's active session storage
                List <AuthSession> landfill = new List <AuthSession>();

                for (;;)
                {
                    tpm._AllowErrors();
                    AuthSession s = tpm.StartAuthSessionEx(TpmSe.Hmac, Substrate.Random(TpmCfg.HashAlgs),
                                                           SessionAttr.ContinueSession);
                    if (!tpm._LastCommandSucceeded())
                    {
                        break;
                    }
                    landfill.Add(s);
                }

                // Check if session type indicators are processed correctly
                tpm[Auth.Hmac]._ExpectError(TpmRc.SessionMemory)
                .RsaDecrypt(keyHandle, encrypted, null, null);
                tpm[Auth.Pw].RsaDecrypt(keyHandle, encrypted, null, null);

                // Check if default session type defined by the TPM device is processed correctly
                bool needHmac = tpm._GetUnderlyingDevice().NeedsHMAC;

                tpm._GetUnderlyingDevice().NeedsHMAC = true;
                tpm._ExpectError(TpmRc.SessionMemory)
                .RsaDecrypt(keyHandle, encrypted, null, null);
                tpm[Auth.Default]._ExpectError(TpmRc.SessionMemory)
                .RsaDecrypt(keyHandle, encrypted, null, null);

                tpm._GetUnderlyingDevice().NeedsHMAC = false;
                tpm.RsaDecrypt(keyHandle, encrypted, null, null);
                tpm[Auth.Default].RsaDecrypt(keyHandle, encrypted, null, null);

                tpm._GetUnderlyingDevice().NeedsHMAC = needHmac;

                landfill.ForEach(s => tpm.FlushContext(s));
            }
            tpm.FlushContext(keyHandle);
        } // TestAutomaticAuth
Пример #18
0
        } // StorageRootKey()

        /// <summary>
        /// This sample demonstrates the async interface to the TPM for selected slow operations.
        /// await-async is preferred when calling slow TPM functions on a UI-thread.  Only a few TPM
        /// functions have an async-form.
        /// </summary>
        /// <param name="tpm">Reference to TPM object</param>
        /// <param name="Event">Synchronization object to signal calling function when we're done.</param>
        static async void PrimarySigningKeyAsync(Tpm2 tpm, AutoResetEvent Event)
        {
            //
            // 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.Sha256,                               // Name algorithm
                                            ObjectAttr.UserWithAuth | ObjectAttr.Sign |    // Signing key
                                            ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-migratable
                                            ObjectAttr.SensitiveDataOrigin,
                                            null,                                          // No policy
                                            new RsaParms(new SymDefObject(),
                                                         new SchemeRsassa(TpmAlgId.Sha256), 2048, 0),
                                            new Tpm2bPublicKeyRsa());
            //
            // Authorization for the key we are about to create
            //
            var keyAuth = new byte[] { 1, 2, 3 };

            //
            // Ask the TPM to create a new primary RSA signing key
            //
            Tpm2CreatePrimaryResponse newPrimary = await tpm.CreatePrimaryAsync(
                TpmRh.Owner,                                                    // In the owner-hierarchy
                new SensitiveCreate(keyAuth, null),                             // With this auth-value
                keyTemplate,                                                    // Key params
                null,                                                           // For creation ticket
                new PcrSelection[0]);                                           // For creation ticket

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

            //
            // Use the key to sign some data
            //
            byte[]  message    = Encoding.Unicode.GetBytes("ABC");
            TpmHash dataToSign = TpmHash.FromData(TpmAlgId.Sha256, message);
            var     sig        = await tpm.SignAsync(newPrimary.handle,                 // Signing key handle
                                                     dataToSign,                        // Data to sign
                                                     new SchemeRsassa(TpmAlgId.Sha256), // Default scheme
                                                     TpmHashCheck.Null());

            //
            // Print the signature. A different structure is returned for each
            // signing scheme, so cast the interface to our signature type.
            //
            var actualSig = (SignatureRsassa)sig;

            Console.WriteLine("Signature: " + BitConverter.ToString(actualSig.sig));

            //
            // Clean up
            //
            tpm.FlushContext(newPrimary.handle);

            //
            // Tell caller, we're done.
            //
            Event.Set();
        }
Пример #19
0
        } // CreateRsaPrimaryStorageKey()

        /// <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)
        {
            Console.WriteLine("\nPCR Quote sample started.");

            //
            // First use a library routine to create an RSA/AES primary storage key
            // with null user-auth.
            //
            TpmHandle primHandle = CreateRsaPrimaryStorageKey(tpm);

            //
            // Template for a signing key.  We will make the key restricted so that we
            // can quote with it too.
            //
            var signKeyPubTemplate = new TpmPublic(TpmAlgId.Sha256,
                                                   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
                                                   null,
                                                   new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0),
                                                   new Tpm2bPublicKeyRsa());
            //
            // Auth-data for new key
            //
            var userAuth   = new byte[] { 1, 2, 3, 4 };
            var sensCreate = new SensitiveCreate(userAuth, null);

            //
            // Creation data (not used in this sample)
            //
            CreationData childCreationData;
            TkCreation   creationTicket;

            byte[] creationHash;

            //
            // Create the key
            //
            TpmPublic  keyPub;
            TpmPrivate keyPriv = tpm.Create(primHandle,          // Child of primary key created above
                                            sensCreate,          // Auth-data
                                            signKeyPubTemplate,  // Template created above
                                            null,                // Other parms are not used here
                                            new PcrSelection[0], // Not bound to any PCRs
                                            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 hSigKey = tpm.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(hSigKey.Name));

            //
            // A nonce (or qualifying data)
            //
            TpmHash nonce = TpmHash.FromData(TpmAlgId.Sha256, new byte[] { 4, 3, 2, 1 });

            //
            // PCRs to quote.  SHA-256 bank, PCR-indices 1, 2, and 3
            //
            var pcrsToQuote = new PcrSelection[]
            {
                new PcrSelection(TpmAlgId.Sha256, new uint[] { 1, 2, 3 })
            };

            //
            // Ask the TPM to quote the PCR (with the given nonce).  The TPM
            // returns both the signature and the quote data that were signed.
            //
            ISignatureUnion quoteSig;
            Attest          quotedInfo = tpm.Quote(hSigKey,
                                                   nonce,
                                                   new SchemeRsassa(TpmAlgId.Sha256),
                                                   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.Sha256, new uint[] { 1, 2, 3 })
            },
                        out outSelection,
                        out outValues);

            //
            // Use the TSS.Net library to validate the quote against the
            // values just read.
            //
            bool quoteOk = keyPub.VerifyQuote(TpmAlgId.Sha256, outSelection, outValues,
                                              nonce, 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, null);

            tpm._ExpectError(TpmRc.Ticket)
            .Sign(hSigKey, nonce, new SchemeRsassa(TpmAlgId.Sha256), 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 tkSafeHash;
            TpmHandle   hashHandle = tpm.HashSequenceStart(null, TpmAlgId.Sha256);

            //
            // The ticket is only generated if the data is "safe."
            //
            tpm.SequenceComplete(hashHandle, new byte[] { 4, 3, 2, 1 },
                                 TpmRh.Owner, out tkSafeHash);
            //
            // 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.Sign(hSigKey, nonce,
                                           new SchemeRsassa(TpmAlgId.Sha256), tkSafeHash);
            //
            // 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(hSigKey);

            Console.WriteLine("PCR Quote sample finished.");
        } // QuotePcrs()
        /// <summary>
        /// Activates a symmetric identity within the Hardware Security Module.
        /// </summary>
        /// <param name="activation">The authentication challenge key supplied by the service.</param>
        public override void ActivateSymmetricIdentity(byte[] activation)
        {
            Destroy();

            // Take the pieces out of the container
            var m = new Marshaller(activation, DataRepresentation.Tpm);

            byte[] credentialBlob = new byte[m.Get <ushort>()];
            credentialBlob = m.GetArray <byte>(credentialBlob.Length, "credentialBlob");
            byte[] encryptedSecret = new byte[m.Get <ushort>()];
            encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret");
            TpmPrivate dupBlob = m.Get <TpmPrivate>();

            byte[] encWrapKey = new byte[m.Get <ushort>()];
            encWrapKey = m.GetArray <byte>(encryptedSecret.Length, "encWrapKey");
            UInt16 pubSize = m.Get <UInt16>();

            _idKeyPub = m.Get <TpmPublic>();
            byte[] cipherText = new byte[m.Get <ushort>()];
            cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo");

            // Setup the authorization session for the EK
            var policyNode = new TpmPolicySecret(
                TpmHandle.RhEndorsement, _ekAuth ?? Array.Empty <byte>(),
                new AuthValue(),
                false,
                0,
                Array.Empty <byte>(),
                Array.Empty <byte>());

            var policy = new PolicyTree(_ekPub.nameAlg);

            policy.SetPolicyRoot(policyNode);
            AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg);

            ekSession.RunPolicy(_tpm2, policy);

            // Perform the activation
            ekSession.Attrs  &= ~SessionAttr.ContinueSession;
            _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential(
                new TpmHandle(TPM_20_SRK_HANDLE),
                new TpmHandle(TPM_20_EK_HANDLE),
                credentialBlob,
                encryptedSecret);

            TpmPrivate importedKeyBlob = _tpm2.Import(
                new TpmHandle(TPM_20_SRK_HANDLE),
                _activationSecret,
                _idKeyPub,
                dupBlob,
                encWrapKey,
                new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb));

            _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub);

            // Persist the key in NV
            TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE);

            _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle);

            // Unload the transient copy from the TPM
            _tpm2.FlushContext(_idKeyHandle);
            _idKeyHandle = hmacKeyHandle;

            // Unwrap the URI
            byte[] clearText = SymmCipher.Decrypt(
                new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb),
                _activationSecret,
                new byte[16],
                cipherText);

            UnicodeEncoding unicode = new UnicodeEncoding();
            string          uriData = unicode.GetString(clearText);
            int             idx     = uriData.IndexOf('/');

            if (idx > 0)
            {
                string hostName = uriData.Substring(0, idx);
                string deviceId = uriData.Substring(idx + 1);

                // Persist the URI
                ProvisionUri(hostName, deviceId);
            }
        }
Пример #21
0
        /// <summary>
        /// Activates an identity key within the TPM device.
        /// </summary>
        /// <param name="encryptedKey">The encrypted identity key.</param>
        public override void ActivateIdentityKey(byte[] encryptedKey)
        {
            if (Logging.IsEnabled)
            {
                Logging.Enter(this, $"{encryptedKey}", nameof(ActivateIdentityKey));
            }
            Destroy();

            // Take the pieces out of the container
            var           m      = new Marshaller(encryptedKey, DataRepresentation.Tpm);
            Tpm2bIdObject cred2b = m.Get <Tpm2bIdObject>();

            byte[] encryptedSecret = new byte[m.Get <ushort>()];
            encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret");
            TpmPrivate dupBlob = m.Get <TpmPrivate>();

            byte[] encWrapKey = new byte[m.Get <ushort>()];
            encWrapKey = m.GetArray <byte>(encWrapKey.Length, "encWrapKey");
            UInt16 pubSize = m.Get <UInt16>();

            _idKeyPub = m.Get <TpmPublic>();
            byte[] cipherText = new byte[m.Get <ushort>()];
            cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo");

            // Setup the authorization session for the EK
            var policyNode = new TpmPolicySecret(TpmHandle.RhEndorsement, false, 0, Array.Empty <byte>(), Array.Empty <byte>());
            var policy     = new PolicyTree(_ekPub.nameAlg);

            policy.SetPolicyRoot(policyNode);
            AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg);

            ekSession.RunPolicy(_tpm2, policy);

            // Perform the activation
            ekSession.Attrs  &= ~SessionAttr.ContinueSession;
            _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential(
                new TpmHandle(TPM_20_SRK_HANDLE),
                new TpmHandle(TPM_20_EK_HANDLE),
                cred2b.credential,
                encryptedSecret);

            TpmPrivate importedKeyBlob = _tpm2.Import(
                new TpmHandle(TPM_20_SRK_HANDLE),
                _activationSecret,
                _idKeyPub,
                dupBlob,
                encWrapKey,
                new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb));

            _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub);

            // Persist the key in NV
            TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE);

            _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle);

            // Unload the transient copy from the TPM
            _tpm2.FlushContext(_idKeyHandle);
            _idKeyHandle = hmacKeyHandle;

            if (Logging.IsEnabled)
            {
                Logging.Exit(this, $"{encryptedKey}", nameof(ActivateIdentityKey));
            }
        }
Пример #22
0
        /// <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);
        }
Пример #23
0
        /// <summary>
        /// Performs the following operations:
        /// - Generates in software (using TSS.net helpers) a key with the given template,
        /// - Creates TPM-compatible dupliction blob for the given TPM based parent key,
        /// - Import the duplication blob into TPM
        /// - Loads the imported key into the TPM
        /// - Makes sure that the imported key works.
        /// </summary>
        /// <param name="tpm">TPM instance to use</param>
        /// <param name="keyPub">Template for the software generated key.</param>
        /// <param name="hParent">Intended TPM based parent key for the software generated key.</param>
        /// <param name="innerSymDef">Specification of the optional inner wrapper for the duplication blob.</param>
        static void GenerateAndImport(Tpm2 tpm, TpmPublic keyPub, TpmHandle hParent,
                                      SymDefObject innerSymDef = null)
        {
            //
            // Create a software key with the given template
            //

            // Generate a random auth value for the key to be created (though we could
            // use an empty buffer, too).
            var keyAuth = AuthValue.FromRandom(CryptoLib.DigestSize(keyPub.nameAlg));

            // Generate the key
            TssObject swKey = TssObject.Create(keyPub, keyAuth);

            //
            // Create duplication blob for the new key with the SRK as the new parent
            //

            // Create a symmetric software key if an inner wrapper is requested.
            var innerWrapKey = innerSymDef == null ? null : SymCipher.Create(innerSymDef);

            // Retrieve the public area of the intended parent key from the TPM
            // We do not need the name (and qualified name) of the key here, but
            // the TPM command returns them anyway.
            // NOTE - Alternatively we could get the public area from the overloaded
            // form of the CreateRsaPrimaryStorageKey() helper used to create the parent
            // key, as all TPM key creation commands (TPM2_CreatePrimary(), TPM2_Create()
            // and TPM2_CreateLoaded()) return it.
            byte[]    name, qname;
            TpmPublic pubParent = tpm.ReadPublic(hParent, out name, out qname);

            byte[]     encSecret;
            TpmPrivate dupBlob = swKey.GetDuplicationBlob(pubParent, innerWrapKey, out encSecret);

            // Import the duplication blob into the TPM
            TpmPrivate privImp = tpm.Import(hParent, innerWrapKey, swKey.Public, dupBlob,
                                            encSecret, innerSymDef ?? new SymDefObject());

            // Load the imported key ...
            TpmHandle hKey = tpm.Load(hParent, privImp, swKey.Public)
                             .SetAuth(swKey.Sensitive.authValue);

            // ... and validate that it works
            byte[] message = Globs.GetRandomBytes(32);

            if (keyPub.objectAttributes.HasFlag(ObjectAttr.Decrypt))
            {
                // Encrypt something
                if (keyPub.type == TpmAlgId.Symcipher)
                {
                    // Only need software symcypher here to query IV size.
                    // Normally, when you use a fixed algorithm, you can hardcode it.
                    var    swSym = SymCipher.Create(keyPub.parameters as SymDefObject);
                    byte[] ivIn  = Globs.GetRandomBytes(swSym.IVSize),
                    ivOut = null;
                    byte[] cipher = swKey.Encrypt(message, ref ivIn, out ivOut);

                    // Not all TPMs implement TPM2_EncryptDecrypt() command
                    tpm._ExpectResponses(TpmRc.Success, TpmRc.TbsCommandBlocked);
                    byte[] decrypted = tpm.EncryptDecrypt(hKey, 1, TpmAlgId.Null, ivIn,
                                                          cipher, out ivOut);
                    if (tpm._LastCommandSucceeded())
                    {
                        bool decOk = Globs.ArraysAreEqual(message, decrypted);
                        Console.WriteLine("Imported symmetric key validation {0}",
                                          decOk ? "SUCCEEDED" : "FAILED");
                    }
                }
            }
            else
            {
                // Sign something (works for both asymmetric and MAC keys)
                string keyType = keyPub.type == TpmAlgId.Rsa ? "RSA"
                               : keyPub.type == TpmAlgId.Keyedhash ? "HMAC"
                               : "UNKNOWN"; // Should not happen in this sample
                TpmAlgId        sigHashAlg = GetSchemeHash(keyPub);
                TpmHash         toSign     = TpmHash.FromData(sigHashAlg, message);
                var             proofx     = new TkHashcheck(TpmRh.Null, null);
                ISignatureUnion sig        = tpm.Sign(hKey, toSign, null, proofx);
                bool            sigOk      = swKey.VerifySignatureOverHash(toSign, sig);
                Console.WriteLine("Imported {0} key validation {1}", keyType,
                                  sigOk ? "SUCCEEDED" : "FAILED");
            }

            // Free TPM resources taken by the loaded imported key
            tpm.FlushContext(hKey);
        } // GenerateAndImport
Пример #24
0
        /// <summary>
        /// Funzione per il salvataggio della chiave privata da utilizzare per firmare con HMAC tramite TPM
        /// </summary>
        /// <param name="encodedHmacKey"></param>
        public static void SaveHmacKey(string encodedHmacKey)
        {
            // Definizione area di memoria non volatile nel TPM
            TpmHandle nvHandle = new TpmHandle(AIOTH_PERSISTED_URI_INDEX + logicalDeviceId);

            // Definizione dell'handle contenente l'Owner nel TPM
            TpmHandle ownerHandle = new TpmHandle(TpmRh.Owner);

            // Definizione dell'handle per la memorizzazione dell'oggetto HMAC
            TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE + logicalDeviceId);

            // Definizione dell'handle della Storage Root Key, si tratta della chiave
            // principale utilizzata per il salvataggio di altre chiavi. Ogni chiave salvata
            // nel TPM infatti viene cifrata utilizzando la sua chiave "padre".
            // La SRK è la chiave più alta dell'albero
            TpmHandle    srkHandle = new TpmHandle(SRK_HANDLE);
            UTF8Encoding utf8      = new UTF8Encoding();

            // dati descrittivi dell'host e del device id
            byte[] nvData = utf8.GetBytes(hostName + "/" + deviceId);

            // chiave privata che intendiamo memorizzare nel TPM
            byte[] hmacKey = System.Convert.FromBase64String(encodedHmacKey);

            // Apertura del TPM
            Tpm2Device tpmDevice = new TbsDevice();

            tpmDevice.Connect();
            var tpm = new Tpm2(tpmDevice);

            // Definizione dello store Non volatile
            // Il primo parametro è l'Owner TPM
            // il terzo parametro è la funzione HMAC che intendiamo salvare
            // (NvPublic sta per Non volatile public area)
            tpm.NvDefineSpace(ownerHandle,
                              new byte[0],
                              new NvPublic(
                                  nvHandle,
                                  TpmAlgId.Sha256,
                                  NvAttr.Authwrite | NvAttr.Authread | NvAttr.NoDa,
                                  new byte[0],
                                  (ushort)nvData.Length));

            // Scrittura nello store non volatile della funzione HMAC
            tpm.NvWrite(nvHandle, nvHandle, nvData, 0);

            // Importazione della chiave HMAC sotto la Storage Root Key
            TpmPublic    hmacPub;
            CreationData creationData;

            byte[]     creationhash;
            TkCreation ticket;

            // Passaggio della chiave privata
            var sensitiveCreate = new SensitiveCreate(new byte[0], hmacKey);

            // Definizione dell'uso che si farà della chiave
            var tpmPublic = new TpmPublic(
                TpmAlgId.Sha256,
                ObjectAttr.UserWithAuth | ObjectAttr.NoDA | ObjectAttr.Sign,
                new byte[0],
                new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)),
                new Tpm2bDigestKeyedhash());

            // Salvataggio della chiave privata nel tpm
            TpmPrivate hmacPrv = tpm.Create(
                srkHandle,
                sensitiveCreate,
                tpmPublic,
                new byte[0],
                new PcrSelection[0],
                out hmacPub,
                out creationData,
                out creationhash,
                out ticket);

            // Caricamento della chiave HMAC nel TPM
            TpmHandle loadedHmacKey = tpm.Load(srkHandle, hmacPrv, hmacPub);

            // Salvataggio della chiave nella memoria Non Volatile
            tpm.EvictControl(ownerHandle, loadedHmacKey, hmacKeyHandle);

            // Flush degli oggetti transienti dal tpm
            tpm.FlushContext(loadedHmacKey);
        }
Пример #25
0
    /// <summary>
    /// Get the endorsement key from the TPM. If the key has not yet been set, a new one is generated
    /// </summary>
    /// <returns></returns>
    /// <remarks>
    /// Picked from https://github.com/Azure/azure-iot-sdk-csharp/blob/e1dd08eacd1caf58f3b318d8ad5ad94dde961d78/security/tpm/src/SecurityProviderTpmHsm.cs#L258-L324
    /// </remarks>
    public static byte[] GetEndorsementKey()
    {
        TpmHandle ekHandle = new TpmHandle(TPM_20_EK_HANDLE);

        byte[] result = Array.Empty <byte>();

        try
        {
            // Open the TPM
            Tpm2Device tpmDevice = new TbsDevice();
            tpmDevice.Connect();
            using (var tpm = new Tpm2(tpmDevice))
            {
                // Read EK from the TPM, temporarily allowing errors
                TpmPublic ekPub = tpm.
                                  _AllowErrors()
                                  .ReadPublic(ekHandle, out byte[] name, out byte[] qualifiedName);

                // if the last command did not succeed, we do not have an endorsement key yet, so create it
                if (!tpm._LastCommandSucceeded())
                {
                    // Get the real EK ready.
                    TpmPublic ekTemplate = new TpmPublic(
                        TpmAlgId.Sha256,
                        ObjectAttr.FixedTPM | ObjectAttr.FixedParent | ObjectAttr.SensitiveDataOrigin |
                        ObjectAttr.AdminWithPolicy | ObjectAttr.Restricted | ObjectAttr.Decrypt,
                        new byte[] {
                        0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8, 0x1a, 0x90, 0xcc, 0x8d, 0x46, 0xa5, 0xd7, 0x24,
                        0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64, 0xf2, 0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa
                    },
                        new RsaParms(
                            new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb),
                            new NullAsymScheme(),
                            2048,
                            0),
                        new Tpm2bPublicKeyRsa(new byte[2048 / 8]));

                    TpmHandle keyHandle = tpm.CreatePrimary(
                        new TpmHandle(TpmHandle.RhEndorsement),
                        new SensitiveCreate(),
                        ekTemplate,
                        Array.Empty <byte>(),
                        Array.Empty <PcrSelection>(),
                        out ekPub,
                        out CreationData creationData,
                        out byte[] creationHash,
                        out TkCreation creationTicket);

                    tpm.EvictControl(TpmHandle.RhOwner, keyHandle, ekHandle);
                    tpm.FlushContext(keyHandle);
                }

                // Get the EK representation
                result = ekPub.GetTpm2BRepresentation();
            }
        }
        catch { }


        return(result);
    }
Пример #26
0
        /// <summary>
        /// Illustrates various cases of automatic authorization handling.
        /// </summary>
        static void AutomaticAuth(Tpm2 tpm)
        {
            TpmHandle primHandle = CreateRsaPrimaryKey(tpm);

            TpmPublic keyPublic;
            TpmHandle keyHandle = CreateSigningDecryptionKey(tpm, primHandle, out keyPublic);

            byte[] message = Globs.GetRandomBytes(32);

            IAsymSchemeUnion decScheme = new SchemeOaep(TpmAlgId.Sha1);
            ISigSchemeUnion  sigScheme = new SchemeRsassa(TpmAlgId.Sha1);

            //
            // TSS.Net implicitly creates an auth session to authorize keyHandle.
            // It uses the auth value cached in the TpmHandle object.
            //
            byte[] encrypted = tpm.RsaEncrypt(keyHandle, message, decScheme, null);

            Console.WriteLine("Automatic authorization of a decryption key.");

            //
            // An auth session is added automatically when TPM object is not in strict mode.
            //
            byte[] decrypted1 = tpm.RsaDecrypt(keyHandle, encrypted, decScheme, null);

            byte[] nonceTpm;

            Console.WriteLine("Session object construction.");

            //
            // If a session with specific properties is required, an AuthSession object
            // can be built from the session handle returned by the TPM2_StartAuthSession
            // command concatenated, if necessary, with session flags and unencrypted salt
            // value (not used in this example).
            //
            AuthSession auditSess = tpm.StartAuthSession(
                TpmRh.Null,                             // no salt
                TpmRh.Null,                             // no bind object
                Globs.GetRandomBytes(16),               // nonceCaller
                null,                                   // no salt
                TpmSe.Hmac,                             // session type
                new SymDef(),                           // no encryption/decryption
                TpmAlgId.Sha256,                        // authHash
                out nonceTpm)
                                    + (SessionAttr.ContinueSession | SessionAttr.Audit);

            /*
             * Alternatively one of the StartAuthSessionEx helpers can be used). E.g.
             *
             * AuthSession auditSess = tpm.StartAuthSessionEx(TpmSe.Hmac, TpmAlgId.Sha256,
             *                                  SessionAttr.ContinueSession | SessionAttr.Audit);
             */

            //
            // TSS.Net specific call to verify TPM auditing correctness.
            //
            tpm._SetCommandAuditAlgorithm(TpmAlgId.Sha256);

            Console.WriteLine("Automatic authorization using explicitly created session object.");

            //
            // Appropriate auth value is added automatically into the provided session.
            //
            // Note that the call to _Audit() is optional and is only used when one
            // needs the TSS.Net framework to compute the audit digest on its own (e.g.
            // when simulating the TPM functionality without access to an actual TPM).
            //
            byte[] decrypted2 = tpm[auditSess]._Audit()
                                .RsaDecrypt(keyHandle, encrypted, decScheme, null);

            ISignatureUnion signature;
            Attest          attest;

            //
            // A session is added automatically to authorize usage of the permanent
            // handle TpmRh.Endorsement.
            //
            // Note that if auth value of TpmRh.Endorsement is not empty, you need to
            // explicitly assign it to the tpm.EndorsementAuth property of the given
            // Tpm2 object.
            //
            attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess,
                                               null, new NullSigScheme(), out signature);

            //
            // But if the corresponding auth value stored in the Tpm2 object is invalid, ...
            //
            AuthValue endorsementAuth = tpm.EndorsementAuth;

            tpm.EndorsementAuth = Globs.ByteArray(16, 0xde);

            //
            // ... the command will fail.
            //
            tpm._ExpectError(TpmRc.BadAuth)
            .GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess,
                                   null, new NullSigScheme(), out signature);
            //
            // Restore correct auth value.
            //
            tpm.EndorsementAuth = endorsementAuth;

            //
            // Verify that decryption worked correctly.
            //
            Debug.Assert(Globs.ArraysAreEqual(decrypted1, decrypted2));

            //
            // Verify that auditing worked correctly.
            //
            SessionAuditInfo info = (SessionAuditInfo)attest.attested;

            Debug.Assert(Globs.ArraysAreEqual(info.sessionDigest, tpm._GetAuditHash().HashData));

            Console.WriteLine("Auth value tracking by TSS.Net.");

            //
            // Change auth value of the decryption key.
            //
            TpmPrivate newKeyPrivate = tpm.ObjectChangeAuth(keyHandle, primHandle, AuthValue.FromRandom(16));
            TpmHandle  newKeyHandle  = tpm.Load(primHandle, newKeyPrivate, keyPublic);

            //
            // Allow non-exclusive usage of the audit session.
            //
            auditSess.Attrs &= ~SessionAttr.AuditExclusive;

            //
            // Correct auth value (corresponding to newKeyHandle, and different from
            // the one used for keyHandle) will be added to auditSess.
            //
            decrypted1 = tpm[auditSess]._Audit()
                         .RsaDecrypt(newKeyHandle, encrypted, decScheme, null);

            Console.WriteLine("Automatic authorization with multiple sessions.");

            //
            // Now two sessions are auto-generated (for TpmRh.Endorsement and keyHandle).
            //
            attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess,
                                               null, sigScheme, out signature);

            //
            // Verify that the previous command worked correctly.
            //
            bool sigOk = keyPublic.VerifySignatureOverData(Marshaller.GetTpmRepresentation(attest),
                                                           signature);

            Debug.Assert(sigOk);

            //
            // In the following example the first session is generated based on session
            // type indicator (Auth.Pw), and the second one is added automatically.
            //
            attest = tpm[Auth.Pw].GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess,
                                                        null, sigScheme, out signature);

            //
            // Verify that the previous command worked correctly.
            //
            sigOk = keyPublic.VerifySignatureOverData(Marshaller.GetTpmRepresentation(attest),
                                                      signature);
            Debug.Assert(sigOk);

            //
            // Release TPM resources that we do not need anymore.
            //
            tpm.FlushContext(newKeyHandle);
            tpm.FlushContext(auditSess);

            //
            // The following example works correctly only when TPM resource management
            // is not enabled (e.g. with TPM simulator, or when actual TPM is in raw mode).
            //
            if (!tpm._GetUnderlyingDevice().HasRM())
            {
                Console.WriteLine("Using session type indicators.");

                //
                // Deplete TPM's active session storage
                //
                List <AuthSession> landfill = new List <AuthSession>();

                for (;;)
                {
                    tpm._AllowErrors();
                    AuthSession s = tpm.StartAuthSessionEx(TpmSe.Hmac, TpmAlgId.Sha256,
                                                           SessionAttr.ContinueSession);
                    if (!tpm._LastCommandSucceeded())
                    {
                        break;
                    }
                    landfill.Add(s);
                }

                //
                // Check if session type indicators are processed correctly
                //
                tpm[Auth.Hmac]._ExpectError(TpmRc.SessionMemory)
                .RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null);
                //
                // Password authorization protocol session uses a predefined handle value,
                // so it must work even when there are no free session slots in the TPM.
                //
                tpm[Auth.Pw].RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null);

                //
                // Check if default session type defined by the TPM device is processed correctly.
                //
                bool needHmac = tpm._GetUnderlyingDevice().NeedsHMAC;

                tpm._GetUnderlyingDevice().NeedsHMAC = true;

                tpm._ExpectError(TpmRc.SessionMemory)
                .RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null);

                tpm[Auth.Default]._ExpectError(TpmRc.SessionMemory)
                .RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null);

                tpm._GetUnderlyingDevice().NeedsHMAC = false;

                tpm.RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null);
                tpm[Auth.Default].RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null);

                tpm._GetUnderlyingDevice().NeedsHMAC = needHmac;

                landfill.ForEach(s => tpm.FlushContext(s));
            }

            //
            // Release TPM resources.
            //
            tpm.FlushContext(keyHandle);
            tpm.FlushContext(primHandle);

            Console.WriteLine("Done.");
        }
Пример #27
0
        void ActivateAikSample(Tpm2 tpm, TestContext testCtx)
        {
            // Use an RSA primary key in the Endorsement hierarchy (EK) to 'activate'
            // another primary in the Endorsement hierarchy (AIK).

            // Note: this procedure can be used to activate a key in the Storage hierarchy, too.

            // "Activation" means secure passing sensitive data generated by a CA (e.g.
            // a symmetric key protecting a freshly generated certificate), so that only
            // a device with the TPM owning the target AIK and EK can access these data.

            // Create a primary key that we will certify.

            //////////////////////////////////////////////////////////////////////////////
            // Device side code
            //////////////////////////////////////////////////////////////////////////////

            // Name algorithm of the new AIK
            TpmAlgId nameAlg = TpmAlgId.Sha256;

            // The key to be certified needs a policy. It can be ANY policy, but here
            // it is configured to allow AIK usage only with the following commands
            var policyAIK = new PolicyTree(nameAlg);
            var policyOR  = new TpmPolicyOr();

            policyAIK.SetPolicyRoot(policyOR);
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.ActivateCredential, "Activate"));
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.Certify, "Certify"));
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.CertifyCreation, "CertifyCreation"));
            policyOR.AddPolicyBranch(new TpmPolicyCommand(TpmCc.Quote, "Quote"));

            var inAIKPub = new TpmPublic(nameAlg,
                                         ObjectAttr.Restricted | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
                                         | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin,
                                         policyAIK.GetPolicyDigest(),
                                         new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0),
                                         new Tpm2bPublicKeyRsa());

            TpmPublic    AIKpub;
            var          inSens = new SensitiveCreate(Substrate.RandomAuth(nameAlg), null);
            CreationData creationData;

            byte[]     creationHash;
            TkCreation creationTk;
            TpmHandle  hAIK = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inAIKPub, null, null, out AIKpub,
                                                out creationData, out creationHash, out creationTk);
            // An alternative using test substrate helper
            //TpmHandle hAIK = Substrate.CreatePrimary(tpm, inAIKPub, TpmRh.Endorsement);

            // Normally a device would have a pre-provisioned persistent EK with the above handle
            TpmHandle hEK = new TpmHandle(0x81010001);

            // Get its public part
            TpmPublic EKpub = null;

            // In a test environment the real EK may be absent. In this case use
            // a primary key temporarily created in the Endorsement hierarchy.
            byte[] name, qname;
            tpm._AllowErrors()
            .ReadPublic(hEK, out name, out qname);
            if (!tpm._LastCommandSucceeded())
            {
                var inEKpub = new TpmPublic(TpmAlgId.Sha256,
                                            ObjectAttr.Restricted | ObjectAttr.Decrypt | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
                                            | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin,
                                            new byte[] { 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xb3, 0xf8,
                                                         0x1a, 0x90, 0xcc, 0x8d, 0x46, 0xa5, 0xd7, 0x24,
                                                         0xfd, 0x52, 0xd7, 0x6e, 0x06, 0x52, 0x0b, 0x64,
                                                         0xf2, 0xa1, 0xda, 0x1b, 0x33, 0x14, 0x69, 0xaa },
                                            new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), null, 2048, 0),
                                            new Tpm2bPublicKeyRsa());

                inSens = new SensitiveCreate(null, null);
                hEK    = tpm.CreatePrimary(TpmRh.Endorsement, inSens, inEKpub, null, null, out EKpub,
                                           out creationData, out creationHash, out creationTk);
            }

            // Marshal public parts of AIK and EK

            byte[] AIKpubBytes = AIKpub.GetTpmRepresentation();
            byte[] EKpubBytes  = EKpub.GetTpmRepresentation();

            // Here the device uses network to pass AIKpubBytes and EKpubBytes (as well as
            // the EK certificate) to CA service.


            //////////////////////////////////////////////////////////////////////////////
            // Service (CA) side code
            //////////////////////////////////////////////////////////////////////////////

            // Unmarshal AIKpub and EKpub (and EK certificate)

            var m = new Marshaller(AIKpubBytes);

            AIKpub = m.Get <TpmPublic>();
            m      = new Marshaller(EKpubBytes);
            EKpub  = m.Get <TpmPublic>();

            // Symmetric key to be used by CA to encrypt the new certificate it creates for AIK
            byte[] secretKey = Substrate.RandomBytes(32);

            // Here CA does the following (the sample does not show this code):
            // - Validates EK certificate
            // - Generates a new certificate for AIK (AIKcert)
            // - Encrypts AIKcert with secretKey

            // Create an activation blob

            // Internal wrapper key encrypted with EKpub to be used by TPM2_ActivateCredential() command.
            byte[] encSecret;

            // An encrypted and HMACed object tied to the destination TPM. It contains
            // 'secret' to be extracted by the successful TPM2_ActivateCredential() command
            // (that can only succeeed on the TPM that originated both EK and AIK).
            IdObject certInfo;

            // Run TSS.Net equivalent of TPM2_MakeCredential() command (convenient for the server side,
            // as it will likely be faster than the TPM transaction and allows concurrent execution).
            certInfo = EKpub.CreateActivationCredentials(secretKey, AIKpub.GetName(), out encSecret);

            // Marshal certInfo

            // IdObject data type requires customized marshaling
            m = new Marshaller();
            m.Put(certInfo.integrityHMAC.Length, "integrityHMAC.Length");
            m.Put(certInfo.integrityHMAC, "integrityHMAC");
            m.Put(certInfo.encIdentity.Length, "encIdentity");
            m.Put(certInfo.encIdentity, "encIdentity.Length");
            byte[] certInfoBytes = m.GetBytes();

            // Here the CA passes certInfoBytes and encSecret (as well as the encrypted
            // AIK certificate) back to the device via network.


            //////////////////////////////////////////////////////////////////////////////
            // Device side code again
            //////////////////////////////////////////////////////////////////////////////

            // Unmarshal certInfo and encSecret (and encrypted AIK certificate)

            m = new Marshaller(certInfoBytes);
            int len = m.Get <int>();

            certInfo.integrityHMAC = m.GetArray <byte>(len);
            len = m.Get <int>();
            certInfo.encIdentity = m.GetArray <byte>(len);
            // encSecret is a byte array, so, normally, no special unmarshalling is required

            // Create policy session to authorize AIK usage
            AuthSession sessAIK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);

            sessAIK.RunPolicy(tpm, policyAIK, "Activate");

            // Create policy description and corresponding policy session to authorize EK usage
            var policyEK = new PolicyTree(EKpub.nameAlg);

            policyEK.SetPolicyRoot(new TpmPolicySecret(TpmRh.Endorsement, false, 0, null, null));

            AuthSession sessEK = tpm.StartAuthSessionEx(TpmSe.Policy, EKpub.nameAlg);

            sessEK.RunPolicy(tpm, policyEK);

            byte[] recoveredSecretKey = tpm[sessAIK, sessEK].ActivateCredential(hAIK, hEK, certInfo, encSecret);

            testCtx.AssertEqual("Secret.1", recoveredSecretKey, secretKey);

            // Here the device can use recoveredSecretKey to decrypt the AIK certificate

            //////////////////////////////////////////////////////////////////////////////
            // End of activation sequence
            //////////////////////////////////////////////////////////////////////////////


            //
            // Now prepare activation using the TPM built-in command
            //

            byte[]   encSecret2 = null;
            IdObject certInfo2  = tpm.MakeCredential(hEK, secretKey, AIKpub.GetName(), out encSecret2);

            // Reinitialize policy sessions
            tpm.PolicyRestart(sessAIK);
            sessAIK.RunPolicy(tpm, policyAIK, "Activate");
            tpm.PolicyRestart(sessEK);
            sessEK.RunPolicy(tpm, policyEK);

            recoveredSecretKey = tpm[sessAIK, sessEK].ActivateCredential(hAIK, hEK, certInfo2, encSecret2);
            testCtx.AssertEqual("Secret.2", recoveredSecretKey, secretKey);

            // Cleanup
            tpm.FlushContext(sessAIK);
            tpm.FlushContext(sessEK);
            tpm.FlushContext(hAIK);

            if (hEK.handle != 0x81010001)
            {
                tpm.FlushContext(hEK);
            }
        } // ActivateAikSample
Пример #28
0
        /// <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);
        }
Пример #29
0
        /// <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);
        }
Пример #30
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 TSS.Net 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,
                                                null,                                          // 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(
                    TpmRh.Owner,                                             // In the owner-hierarchy
                    new SensitiveCreate(keyAuth, null),                      // With this auth-value
                    keyTemplate,                                             // Describes key
                    null,                                                    // Extra data for creation ticket
                    new PcrSelection[0],                                     // Non-PCR-bound
                    out keyPublic,                                           // PubKey and attributes
                    out creationData, out creationHash, out creationTicket); // Not used here

                //
                // 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 digestToSign = 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
                                                  digestToSign,         // Data to sign
                                                  null,                 // Use key's scheme
                                                  TpmHashCheck.Null()) 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, TpmRh.Owner);
                tpm.VerifySignature(pubHandle, digestToSign, 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, digestToSign, 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();
        }