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