Пример #1
0
        /// <summary>
        /// Verify that quotedInfo is properly signed by an associated private key
        /// holder, and that the quotedInfo.type, .extraData and .magic are correct.
        /// Also check that the certified name is what the caller expects.  The caller
        /// must check other fields (for instance the qualified name)
        /// </summary>
        /// <param name="name"></param>
        /// <param name="nonce"></param>
        /// <param name="quotedInfo"></param>
        /// <param name="expectedName"></param>
        /// <param name="signature"></param>
        /// <returns></returns>
        public bool VerifyCertify(TpmHash name, byte[] nonce, Attest quotedInfo,
                                  byte[] expectedName, ISignatureUnion signature)
        {
            // Check generic signature stuff
            if (quotedInfo.type != TpmSt.AttestCertify)
            {
                return(false);
            }

            if (!Globs.ArraysAreEqual(quotedInfo.extraData, nonce))
            {
                return(false);
            }

            if (quotedInfo.magic != Generated.Value)
            {
                return(false);
            }

            // Check specific certify-signature stuff
            var certInfo = (CertifyInfo)quotedInfo.attested;

            if (!Globs.ArraysAreEqual(expectedName, certInfo.name))
            {
                return(false);
            }
            // Check the actual signature
            TpmHash sigHash   = TpmHash.FromData(TpmAlgId.Sha1, quotedInfo.GetTpmRepresentation());
            bool    certifyOk = VerifySignatureOverHash(sigHash, signature);

            return(certifyOk);
        }
Пример #2
0
        /// <summary>
        /// Verify that a TPM quote matches an expect PCR selection, is well formed,
        /// and is properly signed.
        /// </summary>
        /// <param name="pcrDigestAlg"></param>
        /// <param name="expectedSelectedPcr"></param>
        /// <param name="expectedPcrValues"></param>
        /// <param name="nonce"></param>
        /// <param name="quotedInfo"></param>
        /// <param name="signature"></param>
        /// <param name="qualifiedNameOfSigner"></param>
        /// <returns></returns>
        public bool VerifyQuote(TpmAlgId pcrDigestAlg,
                                PcrSelection[] expectedSelectedPcr,
                                Tpm2bDigest[] expectedPcrValues,
                                byte[] nonce,
                                Attest quotedInfo,
                                ISignatureUnion signature,
                                byte[] qualifiedNameOfSigner = null)
        {
            QuoteElt pointOfFailure;

            return(VerifyQuote(pcrDigestAlg, expectedSelectedPcr, expectedPcrValues,
                               nonce, quotedInfo, signature, out pointOfFailure,
                               qualifiedNameOfSigner));
        }
Пример #3
0
        /// <summary>
        // Verify that a TPM quote matches an expect PCR selection, is well formed,
        // and is properly signed. In acse of failure this overload additionally
        // returns information about the specific check that failed.
        /// </summary>
        /// <param name="pcrDigestAlg"></param>
        /// <param name="expectedSelectedPcr"></param>
        /// <param name="expectedPcrValues"></param>
        /// <param name="nonce"></param>
        /// <param name="quotedInfo"></param>
        /// <param name="signature"></param>
        /// <param name="pointOfFailure"></param>
        /// <param name="qualifiedNameOfSigner"></param>
        /// <returns></returns>
        public bool VerifyQuote(TpmAlgId pcrDigestAlg,
                                PcrSelection[] expectedSelectedPcr,
                                Tpm2bDigest[] expectedPcrValues,
                                byte[] nonce,
                                Attest quotedInfo,
                                ISignatureUnion signature,
                                out QuoteElt pointOfFailure,
                                byte[] qualifiedNameOfSigner = null)
        {
            pointOfFailure = QuoteElt.None;

            if (!(quotedInfo.attested is QuoteInfo))
            {
                pointOfFailure = QuoteElt.Type;
                return(false);
            }

            if (quotedInfo.magic != Generated.Value)
            {
                pointOfFailure = QuoteElt.Magic;
                return(false);
            }

            if (!quotedInfo.extraData.IsEqual(nonce))
            {
                pointOfFailure = QuoteElt.ExtraData;
                return(false);
            }

            // Check environment of signer (name) is expected
            if (qualifiedNameOfSigner != null &&
                !quotedInfo.qualifiedSigner.IsEqual(qualifiedNameOfSigner))
            {
                pointOfFailure = QuoteElt.QualifiedSigner;
                return(false);
            }

            // Now check the quote-specific fields
            var quoted = (QuoteInfo)quotedInfo.attested;

            // Check values pcr indices are what we expect
            if (!Globs.ArraysAreEqual(quoted.pcrSelect, expectedSelectedPcr))
            {
                pointOfFailure = QuoteElt.PcrSelect;
                return(false);
            }

            // Check that values in the indices above are what we expect
            // ReSharper disable once UnusedVariable
            var expected = new PcrValueCollection(expectedSelectedPcr, expectedPcrValues);
            var m        = new Marshaller();

            foreach (Tpm2bDigest d in expectedPcrValues)
            {
                m.Put(d.buffer, "");
            }

            TpmHash expectedPcrHash = TpmHash.FromData(pcrDigestAlg, m.GetBytes());

            if (!Globs.ArraysAreEqual(expectedPcrHash, quoted.pcrDigest))
            {
                pointOfFailure = QuoteElt.PcrDigest;
                return(false);
            }

            // And finally check the signature
            if (!VerifySignatureOverData(quotedInfo.GetTpmRepresentation(), signature))
            {
                pointOfFailure = QuoteElt.Signature;
                return(false);
            }
            return(true);
        }
Пример #4
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()