/// <summary> /// The response hash includes the command ordinal, response code, and the actual command bytes. /// </summary> /// <param name="hashAlg"></param> /// <param name="commandCode"></param> /// <param name="responseCode"></param> /// <param name="responseParmsNoHandles"></param> /// <returns></returns> private byte[] GetExpectedResponseHash( TpmAlgId hashAlg, byte[] responseParmsNoHandles, TpmCc commandCode, TpmRc responseCode) { var temp = new Marshaller(); temp.Put(responseCode, "responseCode"); temp.Put(commandCode, "currentCommand"); temp.Put(responseParmsNoHandles, null); byte[] parmsHash = CryptoLib.HashData(hashAlg, temp.GetBytes()); return parmsHash; }
// ReSharper disable once InconsistentNaming internal override TpmRc Execute(Tpm2 tpm, AuthSession authSession, PolicyTree policy) { byte[] nonceTpm = UseNonceTpm ? Globs.CopyData(authSession.NonceTpm) : new byte[0]; var dataToSign = new Marshaller(); dataToSign.Put(nonceTpm, ""); ISignatureUnion signature; // If the library has been given a signing key we can do the challenge here (else we need to call out) TpmHandle verificationKey; if (SigningKey != null) { dataToSign.Put(ExpirationTime, ""); dataToSign.Put(CpHash, ""); dataToSign.Put(PolicyRef, ""); // Just ask the key to sign the challenge signature = SigningKey.Sign(dataToSign.GetBytes()); verificationKey = tpm.LoadExternal(null, SigningKeyPub, TpmRh.Owner); } else { TpmPublic verifier; signature = AssociatedPolicy.ExecuteSignerCallback(this, nonceTpm, out verifier); verificationKey = tpm.LoadExternal(null, verifier, TpmRh.Owner); } TkAuth policyTicket; Timeout = tpm.PolicySigned(verificationKey, authSession, nonceTpm, CpHash, PolicyRef, ExpirationTime, signature, out policyTicket); TpmRc responseCode = tpm._GetLastResponseCode(); // Save the policyTicket in case it is needed later PolicyTicket = policyTicket; tpm.FlushContext(verificationKey); return responseCode; }
} // UpdateHandleData() /// <summary> /// Calculate the command hash. Note that the handles are replaced by the name of the referenced object /// </summary> /// <param name="hashAlg"></param> /// <param name="commandParms"></param> /// <param name="handles"></param> /// <returns></returns> private byte[] GetCommandHash(TpmAlgId hashAlg, byte[] commandParms, TpmHandle[] handles) { var temp = new Marshaller(); temp.Put(CurrentCommand, "ordinal"); for (int j = 0; j < handles.Length; j++) { temp.Put(handles[j].Name, "name + " + j); } temp.Put(commandParms, "commandParms"); byte[] parmsHash = CryptoLib.HashData(hashAlg, temp.GetBytes()); return parmsHash; }
/// <summary> /// Verify that a TPM quote matches an expect PCR selection, is well formed, and is properly signed /// by the private key corresponding to this public key. /// </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) { if (!(quotedInfo.attested is QuoteInfo)) { return false; } if (quotedInfo.magic != Generated.Value) { return false; } if (!quotedInfo.extraData.IsEqual(nonce)) { return false; } // Check environment of signer (name) is expected if (qualifiedNameOfSigner != null) { if (!quotedInfo.qualifiedSigner.IsEqual(qualifiedNameOfSigner)) { 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)) { 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)) { return false; } // And finally check the signature bool sigOk = VerifySignatureOverData(quotedInfo.GetTpmRepresentation(), signature); return sigOk; }
/// <summary> /// Return an updated policy hash according to the TPM specification. /// </summary> /// <param name="?"></param> /// <param name="currentHash"></param> /// <param name="commandCode"></param> /// <param name="name"></param> /// <param name="refData"></param> /// <returns></returns> internal TpmHash PolicyUpdate(TpmHash currentHash, TpmCc commandCode, byte[] name, byte[] refData) { var m = new Marshaller(); m.Put(commandCode, "commandCode"); m.Put(name, "name"); TpmHash h1 = currentHash.Extend(m.GetBytes()); TpmHash h2 = h1.Extend(refData); return h2; }
public static string ParseCommand(byte[] buf) { CommandHeader commandHeader; TpmHandle[] inHandles; SessionIn[] inSessions; byte[] commandParmsNoHandles; string response = ""; bool ok = CrackCommand(buf, out commandHeader, out inHandles, out inSessions, out commandParmsNoHandles); if (!ok) { response = "The TPM command is not properly formatted. Doing the best I can...\n"; } CommandInfo command = Tpm2.CommandInfoFromCommandCode(commandHeader.CommandCode); if (command == null) { response += String.Format("The command-code {0} is not defined. Aborting\n", commandHeader.CommandCode); return response; } response += "Header:\n"; response += commandHeader + "\n"; var m2 = new Marshaller(); foreach (TpmHandle h in inHandles) { m2.Put(h, ""); } byte[] commandParmsWithHandles = Globs.Concatenate(new[] {m2.GetBytes(), commandParmsNoHandles}); var m = new Marshaller(commandParmsWithHandles); object inParms = m.Get(command.InStructType, ""); response += "Command Parameters:\n"; response += inParms + "\n"; response += "Sessions [" + inSessions.Length + "]\n"; for (int j = 0; j < inSessions.Length; j++) { // ReSharper disable once FormatStringProblem response += String.Format("{0}: 0x{1:x}\n", j, inSessions[j]); } return response; }
/// <summary> /// This is a formatting helper to help callbacks create a properly formed hash to sign. /// </summary> /// <returns></returns> public static byte[] GetDataStructureToSign(int expirationTime, byte[] nonceTpm, byte[] cpHash, byte[] policyRef) { var dataToSign = new Marshaller(); dataToSign.Put(nonceTpm, ""); dataToSign.Put(expirationTime, ""); dataToSign.Put(cpHash, ""); dataToSign.Put(policyRef, ""); return dataToSign.GetBytes(); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(TpmCc.PolicyPCR, "ordinal"); m.Put(Pcrs.GetTpmlPcrSelection(), "selection"); m.Put(Pcrs.GetSelectionHash(hashAlg).HashData, "pcrs"); return GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(OperandB, "operandB"); m.Put(Offset, "offset"); m.Put(Operation, "operation"); byte[] toHash = m.GetBytes(); byte[] args = CryptoLib.HashData(hashAlg, toHash); m = new Marshaller(); m.Put(TpmCc.PolicyCounterTimer, "cc"); m.Put(args, "args"); TpmHash tailHash = GetNextAcePolicyDigest(hashAlg); TpmHash hashNow = tailHash.Extend(m.GetBytes()); return hashNow; }
/// <summary> /// Implements the first step of the policy digest update (see the PolicyUpdate() /// method), and also used by PolicyAuthorizeNV. /// </summary> internal TpmHash PolicyUpdate1(TpmHash currentHash, TpmCc commandCode, byte[] name) { var m = new Marshaller(); m.Put(commandCode, "commandCode"); m.Put(name, "name"); return currentHash.Extend(m.GetBytes()); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { int numBranches = PolicyBranches.Count; if (numBranches < 2 || numBranches > 8) { Globs.Throw("GetPolicyDigest: Must have between 2 and 8 branches in a PolicyOr"); } var m = new Marshaller(); m.Put(TpmHash.ZeroHash(hashAlg).HashData, "zero"); m.Put(TpmCc.PolicyOR, "ordinal"); foreach (PolicyAce branch in PolicyBranches) { TpmHash branchPolicyHash = branch.GetPolicyDigest(hashAlg); m.Put(branchPolicyHash.HashData, "h"); } byte[] polVal = CryptoLib.HashData(hashAlg, m.GetBytes()); return new TpmHash(hashAlg, polVal); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(TpmCc.PolicyNvWritten, "ordinal"); byte writtenName = IsNvIndexRequiredToHaveBeenWritten ? (byte)1 : (byte)0; m.Put(writtenName, "writtenSet"); TpmHash previous = GetNextAcePolicyDigest(hashAlg); return previous.Extend(m.GetBytes()); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(TpmCc.PolicyDuplicationSelect, "ordinal"); if (IncludeObjectNameInPolicyHash) { m.Put(NameOfObject, "objectName"); } m.Put(NameOfNewParent, "newParent"); byte includeName = IncludeObjectNameInPolicyHash ? (byte)1 : (byte)0; m.Put(includeName, "includeObject"); TpmHash previous = GetNextAcePolicyDigest(hashAlg); return previous.Extend(m.GetBytes()); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { TpmCc commandCode = 0; if (TicketType == TpmSt.AuthSecret) commandCode = TpmCc.PolicySecret; else if (TicketType == TpmSt.AuthSigned) commandCode = TpmCc.PolicySigned; else { Globs.Throw<ArgumentException>("Ticket type is not recognized"); return new TpmHash(hashAlg); } if (ObjectName == null) { ObjectName = AuthorizingKey.GetName(); } var m = new Marshaller(); m.Put(commandCode, "ordinal"); m.Put(ObjectName, "name"); // ReSharper disable once UnusedVariable TpmHash atStart = GetNextAcePolicyDigest(hashAlg); TpmHash firstExtend = GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()); TpmHash secondExtend = firstExtend.Extend(PolicyRef); return secondExtend; }
/// <summary> /// Create a TPM command byte stream from constituent components /// </summary> /// <param name="commandCode"></param> /// <param name="handles"></param> /// <param name="sessions"></param> /// <param name="parmsWithoutHandles"></param> /// <returns></returns> public static byte[] CreateCommand( TpmCc commandCode, TpmHandle[] handles, SessionIn[] sessions, byte[] parmsWithoutHandles) { // ReSharper disable once UnusedVariable CommandInfo commandInfo = Tpm2.CommandInfoFromCommandCode(commandCode); var m = new Marshaller(); TpmSt tag = sessions.Length == 0 ? TpmSt.NoSessions : TpmSt.Sessions; m.Put(tag, "tag"); m.PushLength(4); m.Put(commandCode, "commandCode"); foreach (TpmHandle h in handles) { m.Put(h, "handle"); } if (tag == TpmSt.Sessions) { var m2 = new Marshaller(); foreach (SessionIn s in sessions) { m2.Put(s, "session"); } m.PutUintPrependedArray(m2.GetBytes(), "sessions"); } m.Put(parmsWithoutHandles, "parms"); m.PopAndSetLengthToTotalLength(); return m.GetBytes(); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(TpmCc.PolicyCommandCode, "ordinal"); m.Put(AllowedCommand, "allowedCommand"); return GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()); }
public static byte[] CreateResponse( TpmRc responseCode, TpmHandle[] handles, SessionOut[] sessions, byte[] responseParmsNoHandles) { var m = new Marshaller(); TpmSt tag = sessions.Length == 0 ? TpmSt.NoSessions : TpmSt.Sessions; m.Put(tag, "tag"); m.PushLength(4); m.Put(responseCode, "responseCode"); foreach (TpmHandle h in handles) { m.Put(h, "handle"); } if (tag == TpmSt.Sessions) { m.Put((uint)responseParmsNoHandles.Length, "parmsLenght"); } m.Put(responseParmsNoHandles, "parms"); foreach (SessionOut s in sessions) m.Put(s, "session"); m.PopAndSetLengthToTotalLength(); return m.GetBytes(); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(TpmCc.PolicyNameHash, "commandCod"); m.Put(NameHash, "hashData"); return GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()); }
public byte[] GetTpmRepresentation() { var m = new Marshaller(); ToNet(m); return m.GetBytes(); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(TpmCc.PolicyLocality, "ordinal"); m.Put(AllowedLocality, "locality"); return GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()); }
/// <summary> /// Create a 10 byte error response that matches TPM error responses. /// </summary> /// <param name="errorCode"></param> /// <returns></returns> private byte[] FormatError(TpmRc errorCode) { var m = new Marshaller(); m.Put(TpmSt.NoSessions, ""); m.Put((uint)10, ""); m.Put(errorCode, ""); return m.GetBytes(); }
internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { var m = new Marshaller(); m.Put(OperandB, "operandB"); m.Put(Offset, "offset"); m.Put(Operation, "operation"); byte[] args = CryptoLib.HashData(hashAlg, m.GetBytes()); m = new Marshaller(); m.Put(TpmCc.PolicyNV, "ord"); m.Put(args, "args"); m.Put(IndexName, "name"); return GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()); }
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
/// <summary> /// Get the hash of the concatenation of the values in the array order defined by the PcrSelection[] /// returned from GetPcrSelectionArray. /// </summary> /// <param name="hashAlg"></param> /// <returns></returns> public TpmHash GetSelectionHash(TpmAlgId hashAlg) { var m = new Marshaller(); PcrSelection[] selections = GetPcrSelectionArray(); foreach (PcrSelection sel in selections) { uint[] pcrIndices = sel.GetSelectedPcrs(); foreach (uint index in pcrIndices) { PcrValue v = GetSpecificValue(sel.hash, index); m.Put(v.value.HashData, "hash"); } } var valueHash = new TpmHash(hashAlg, CryptoLib.HashData(hashAlg, m.GetBytes())); return valueHash; }