public TkVerified VerifySignatureOfRecivedMessage(TpmPublic keyPublic, byte[] message, ISignatureUnion signature) { TpmHash dataToSign = TpmHash.FromData(TpmAlgId.Sha256, message); TpmHandle pubHandle = tpm.LoadExternal(null, keyPublic, TpmHandle.RhOwner); return(tpm.VerifySignature(pubHandle, dataToSign.HashData, signature)); }
public static ushort MaxOaepMsgSize(ushort keyBitLen, TpmAlgId hashAlg) { int keySize = keyBitLen / 8; int maxMessageSize = keySize - 2 * TpmHash.DigestSize(hashAlg) - 2; return((ushort)(maxMessageSize > keySize || maxMessageSize < 0 ? 0 : maxMessageSize)); }
static void ReadPcr() { Console.WriteLine("\nPCR sample started."); using (Tpm2Device tpmDevice = new TbsDevice()) { tpmDevice.Connect(); using (var tpm = new Tpm2(tpmDevice)) { var valuesToRead = new PcrSelection[] { new PcrSelection(TpmAlgId.Sha1, new uint[] { 1, 2 }) }; PcrSelection[] valsRead; Tpm2bDigest[] values; tpm.PcrRead(valuesToRead, out valsRead, out values); if (valsRead[0] != valuesToRead[0]) { Console.WriteLine("Unexpected PCR-set"); } var pcr1 = new TpmHash(TpmAlgId.Sha1, values[0].buffer); Console.WriteLine("PCR1: " + pcr1); var dataToExtend = new byte[] { 0, 1, 2, 3, 4 }; tpm.PcrEvent(TpmHandle.Pcr(1), dataToExtend); tpm.PcrRead(valuesToRead, out valsRead, out values); } } }
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
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
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
} // 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> /// This sample demonstrates the use of the TPM Platform Configuration /// Registers (PCR). TSS.Net provides several features to model PCR /// semantics. /// </summary> /// <param name="tpm">Reference to the TPM object.</param> static void Pcrs(Tpm2 tpm) { Console.WriteLine("\nPCR sample started."); // // Read the value of the SHA1 PCR 1 and 2 // var valuesToRead = new PcrSelection[] { new PcrSelection(TpmAlgId.Sha256, new uint[] { 1, 2 }) }; PcrSelection[] valsRead; Tpm2bDigest[] values; tpm.PcrRead(valuesToRead, out valsRead, out values); // // Check that what we read is what we asked for (the TPM does not // guarantee this) // if (valsRead[0] != valuesToRead[0]) { Console.WriteLine("Unexpected PCR-set"); } // // Print out PCR-1 // var pcr1 = new TpmHash(TpmAlgId.Sha256, values[0].buffer); Console.WriteLine("PCR1: " + pcr1); // // Extend (event) PCR[1] in the TPM and in the external library and // see if they match // var dataToExtend = new byte[] { 0, 1, 2, 3, 4 }; // // Note that most PCR must be authorized with "null" authorization // tpm.PcrEvent(TpmHandle.Pcr(1), dataToExtend); // // And read the current value // tpm.PcrRead(valuesToRead, out valsRead, out values); // // Update the "simulated" PCR // pcr1.Event(dataToExtend); // // And see whether the PCR has the value we expect // if (pcr1 != values[0].buffer) { throw new Exception("Event did not work"); } // // Update a resettable PCR // tpm.PcrEvent(TpmHandle.Pcr(16), new byte[] { 1, 2 }); // // And reset it // tpm.PcrReset(TpmHandle.Pcr(16)); // // And check that it is indeed zero // tpm.PcrRead(new PcrSelection[] { new PcrSelection(TpmAlgId.Sha256, new uint[] { 16 }) }, out valsRead, out values); // // Did it reset? // if (TpmHash.ZeroHash(TpmAlgId.Sha256) != values[0].buffer) { throw new Exception("PCR did not reset"); } Console.WriteLine("PCR sample finished."); } // Pcrs
/// <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); }
/// <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); }
/// <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); }
/// <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
public int MaxDataObjectSize(TpmAlgId nameAlg = TpmAlgId.Null) { return(TpmVersion < 149 ? (int)TpmHash.DigestSize(nameAlg) : (int)Implementation.MaxSymData); }
public SignatureRsassa SignMessageToSend(TpmHandle keyHandle, byte[] message) { TpmHash dataToSign = TpmHash.FromData(TpmAlgId.Sha1, message); return(tpm.Sign(keyHandle, dataToSign.HashData, new NullSigScheme(), TpmHashCheck.NullHashCheck()) as SignatureRsassa); }
static void Sign() { using (Tpm2Device tpmDevice = Examples.GetSimulator()) { tpmDevice.Connect(); using (var tpm = new Tpm2(tpmDevice)) { if (tpmDevice is TcpTpmDevice) { tpmDevice.PowerCycle(); } CreateRsaPrimaryKey(tpm, tpmDevice is TcpTpmDevice); 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()); var ownerAuth = new AuthValue(); var keyAuth = new byte[] { 1, 2, 3 }; TpmPublic keyPublic; CreationData creationData; TkCreation creationTicket; byte[] creationHash; 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()); byte[] message = Encoding.Unicode.GetBytes("ABC"); TpmHash digestToSign = TpmHash.FromData(TpmAlgId.Sha1, message); 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)); bool sigOk = keyPublic.VerifySignatureOverData(message, signature); if (!sigOk) { throw new Exception("Signature did not validate."); } Console.WriteLine("Verified signature with TPM2lib (software implementation)."); TpmHandle pubHandle = tpm.LoadExternal(null, keyPublic, TpmRh.Owner); tpm.VerifySignature(pubHandle, digestToSign, signature); Console.WriteLine("Verified signature with TPM."); } } }
} // 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(); }
/// <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(); }
/// <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); }
// returns PCR values after TPM Reset. // NOTE: PCR_Reset() comamnd always resets PCR contents to zeroes. // TODO: use TPM PCR properties public static TpmHash GetPcrResetValue(TpmAlgId hashAlg, int pcrNum) { return(pcrNum >= 17 && pcrNum <= 22 ? TpmHash.AllOnesHash(hashAlg) : TpmHash.ZeroHash(hashAlg)); }
void TestCertifyX509Impl(Tpm2 tpm, TestContext testCtx, TpmPublic subjectTemplate, TpmPublic sigKeyTemplate, PolicyTree policy, string testLabel) { var partialCert = X509Helpers.MakePartialCert(subjectTemplate); var partialCertBytes = partialCert.GetDerEncoded(); // If you want to paste in your own hex put it here and s //var partialCertBytes = Globs.ByteArrayFromHex("01020304"); // Certify RSA with RSA TpmPublic certifyingKeyPub, keyToBeCertifiedPub; TpmHandle hSigKey = Substrate.CreatePrimary(tpm, sigKeyTemplate, out certifyingKeyPub); TpmHandle hSubjectKey = Substrate.CreatePrimary(tpm, subjectTemplate, out keyToBeCertifiedPub); AuthSession sess = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); sess.RunPolicy(tpm, policy); ISignatureUnion sig; byte[] tbsHash; byte[] addedTo = tpm[sess].CertifyX509(hSubjectKey, hSigKey, null, new NullSigScheme(), partialCertBytes, out tbsHash, out sig); tpm.FlushContext(sess); tpm.FlushContext(hSubjectKey); var addedToCert = AddedToCertificate.FromDerEncoding(addedTo); X509Certificate returnedCert = X509Helpers.AssembleCertificate(partialCert, addedToCert, sig is SignatureRsa ? ((SignatureRsa)sig).GetTpmRepresentation() : ((SignatureEcc)sig).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)); // Is the cert properly signed? if (TpmHelper.GetScheme(sigKeyTemplate).GetUnionSelector() != TpmAlgId.Rsapss) { // Software crypto layer does not support PSS bool sigOk = certifyingKeyPub.VerifySignatureOverHash(tbsHash, sig); if (sigKeyTemplate.type == TpmAlgId.Ecc) { #if !__NETCOREAPP2__ // No ECC in .Net Core testCtx.Assert("Sign" + testLabel, sigOk); #endif } else { testCtx.Assert("Sign" + testLabel, sigOk); } } tpm.VerifySignature(hSigKey, tbsHash, sig); tpm.FlushContext(hSigKey); }