/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key - SymDefObject symDef = GetSymDef(keyParameters); byte[] symmKey; if (symDef.Algorithm != TpmAlgId.Null) { using (var symmCipher = SymmCipher.Create(symDef)) { symmKey = symmCipher.KeyData; } } else { symmKey = new byte[0]; } // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return(newKey); }
/// <summary> /// This sample demonstrates the creation and use of TPM NV-storage /// </summary> /// <param name="tpm">Reference to TPM object.</param> void NVReadWrite(Tpm2 tpm) { // // 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(); TpmHandle nvHandle = TpmHandle.NV(3001); // // Clean up any slot that was left over from an earlier run // tpm[ownerAuth]._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle); // // Scenario 1 - write and read a 32-byte NV-slot // AuthValue nvAuth = AuthValue.FromRandom(8); tpm[ownerAuth].NvDefineSpace(TpmHandle.RhOwner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Authread | NvAttr.Authwrite, new byte[0], 32)); // // Write some data // var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; tpm[nvAuth].NvWrite(nvHandle, nvHandle, nvData, 0); // // And read it back // byte[] nvRead = tpm[nvAuth].NvRead(nvHandle, nvHandle, (ushort)nvData.Length, 0); // // Is it correct? // bool correct = nvData.SequenceEqual(nvRead); if (!correct) { throw new Exception("NV data was incorrect."); } this.textBlock.Text += "NV data written and read. "; // // And clean up // tpm[ownerAuth].NvUndefineSpace(TpmHandle.RhOwner, nvHandle); }
public TpmPolicySecret( TpmHandle authorityHandle, byte[] authorityName, AuthValue theAuthVal, bool useNonceTpm, int expirationTime, byte[] cpHash, byte[] policyRef, string branchName = "") : base(useNonceTpm, expirationTime, cpHash, policyRef, branchName) { AuthVal = theAuthVal; AuthorityHandle = authorityHandle; AuthorityName = Globs.CopyData(authorityName); }
/// <summary> /// Creates a *software* key. The key will be random (not created from /// a seed). The key can be used as the root of a software hierarchy that /// can be translated into a duplication blob ready for import into a TPM. /// Depending on the type of key, the software root key can be a parent for /// other root keys that can comprise a migration group. The caller should /// specify necessary key parameters in Public. /// /// Parameter keyData is used only with symmetric or HMAC keys. If non-null /// on entry, it contains the key bytes supplied by the caller, otherwise the /// key will be randomly generated. For asymmetric keys keyData must be null. /// /// Parameter authVal specifies the authorization value associated with the key. /// If it is null, then an random value will be used. /// </summary> /// <param name="pub"></param> /// <param name="authVal"></param> /// <param name="keyData"></param> /// <returns></returns> public static TssObject Create(TpmPublic pub, AuthValue authVal = null, byte[] keyData = null) { var newKey = new TssObject(); // Create a new key from the supplied parameters IPublicIdUnion publicId; var sensData = CreateSensitiveComposite(pub, ref keyData, out publicId); var nameSize = CryptoLib.DigestSize(pub.nameAlg); // Create the associated seed value byte[] seed = Globs.GetRandomBytes(nameSize); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal ?? AuthValue.FromRandom(nameSize), seed, sensData); newKey.Sensitive = sens; newKey.Private = new TpmPrivate(sens.GetTpm2BRepresentation()); // fill in the public data newKey.Public = pub.Copy(); if (pub.type == TpmAlgId.Keyedhash || pub.type == TpmAlgId.Symcipher) { byte[] unique = null; if (pub.objectAttributes.HasFlag(ObjectAttr.Restricted | ObjectAttr.Decrypt)) { unique = CryptoLib.Hmac(pub.nameAlg, seed, keyData); } else { unique = CryptoLib.HashData(pub.nameAlg, seed, keyData); } newKey.Public.unique = pub.type == TpmAlgId.Keyedhash ? new Tpm2bDigestKeyedhash(unique) as IPublicIdUnion : new Tpm2bDigestSymcipher(unique); } else { newKey.Public.unique = publicId; } // And return the new key return(newKey); }
/// <summary> /// Create a non-migratable RSA primary with the specified use-auth value and key size. /// </summary> /// <param name="parentAuth"></param> /// <param name="keyLen"></param> /// <param name="restricted"></param> /// <param name="useAuth"></param> /// <param name="parentHandle"></param> /// <param name="policy"></param> /// <returns></returns> public async Task <Tpm2CreateResponse> CreateRsaSigningAsync( TpmHandle parentHandle, AuthValue parentAuth, int keyLen, bool restricted, AuthValue useAuth, TpmHash policy = null) { ObjectAttr attr = ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicatable ObjectAttr.SensitiveDataOrigin | ObjectAttr.UserWithAuth; // Authorize with auth-data if (restricted) { attr |= ObjectAttr.Restricted; } var thePolicy = new byte[0]; if ((Object)policy != null) { thePolicy = policy; attr |= ObjectAttr.AdminWithPolicy; } var signKeyPubTemplate = new TpmPublic(H.NameHash, attr, thePolicy, new RsaParms(new SymDefObject(), // Key type and sig scheme H.RsaSigScheme, (ushort)keyLen, 0), new Tpm2bPublicKeyRsa()); // Auth-data for new key var sensCreate = new SensitiveCreate(useAuth, new byte[0]); // Create the key var newKey = await H.Tpm[parentAuth].CreateAsync(parentHandle, sensCreate, signKeyPubTemplate, new byte[0], new PcrSelection[0]); return(newKey); }
/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key byte[] symmKey = Globs.GetRandomBytes(CryptoLib.DigestSize(keyParameters.nameAlg)); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return(newKey); }
CreatePrimaryRsaAsync(int keyLen, AuthValue useAuth) { return(await CreatePrimaryRsaAsyncInternal(keyLen, useAuth.AuthVal, null, null)); }
/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key - SymDefObject symDef = GetSymDef(keyParameters); byte[] symmKey; if (symDef.Algorithm != TpmAlgId.Null) { using (var symmCipher = SymmCipher.Create(symDef)) { symmKey = symmCipher.KeyData; } } else { symmKey = new byte[0]; } // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return newKey; }
/// <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 Tpm2Lib 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, new byte[0], // 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( TpmHandle.RhOwner, // In the owner-hierarchy new SensitiveCreate(keyAuth, new byte[0]), // With this auth-value keyTemplate, // Describes key new byte[0], // For creation ticket new PcrSelection[0], // For creation ticket out keyPublic, // Out pubKey and attributes out creationData, out creationHash, // Not used here out creationTicket); // // 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 dataToSign = 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 dataToSign.HashData, // Data to sign new SchemeRsassa(TpmAlgId.Sha1), // Default scheme TpmHashCheck.NullHashCheck()) 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, TpmHandle.RhOwner); tpm.VerifySignature(pubHandle, dataToSign.HashData, 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, dataToSign.HashData, signature); tpm._AllowErrors().VerifySignature(pubHandle, dataToSign.HashData, 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> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key byte[] symmKey = Globs.GetRandomBytes(CryptoLib.DigestSize(keyParameters.nameAlg)); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return newKey; }
/// <summary> /// Create a sealed-object primary that can be accessed with the given policy. SHA256 is assumed. /// </summary> /// <param name="tpm"></param> /// <param name="dataToSeal"></param> /// <param name="authValue"></param> /// <param name="policy"></param> /// <returns></returns> private static TpmHandle CreateSealedPrimaryObject(Tpm2 tpm, byte[] dataToSeal, byte[] authValue, byte[] policy) { ObjectAttr attrs = ObjectAttr.FixedTPM | ObjectAttr.FixedParent; if (authValue != null) { attrs |= ObjectAttr.UserWithAuth; } byte[] policyVal = policy ?? new byte[0]; var sealedInPublic = new TpmPublic(TpmAlgId.Sha256, attrs, policyVal, new KeyedhashParms(new NullSchemeKeyedhash()), new Tpm2bDigestKeyedhash()); // // Envelope for sealed data and auth // byte[] authVal = authValue ?? new byte[0]; var sealedInSensitive = new SensitiveCreate(authVal, dataToSeal); TkCreation creationTicket; byte[] creationHashSealed; TpmPublic sealedPublic; CreationData sealedCreationData; // // 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(); // // Ask the TPM to create a primary containing the "sealed" data // TpmHandle primHandle = tpm[ownerAuth].CreatePrimary(TpmHandle.RhOwner, sealedInSensitive, sealedInPublic, new byte[0], new PcrSelection[0], out sealedPublic, out sealedCreationData, out creationHashSealed, out creationTicket); return primHandle; }
/// <summary> /// Associates authorization value with the handle. /// This association is done automatically by TPM commands producing the /// corresponding handle or changing object's auth value. /// However on many occasions the library does not have access to the auth /// value at any moment before it is required for authorizing access to the /// handle. Notably, when an externally created key is imported, pre-existing /// NV index or persistent object is used, SetAuth() is required to associate /// auth value with the handle. /// </summary> /// <param name="auth"></param> /// <returns>Reference to this object, which can be used for chaining.</returns> public TpmHandle SetAuth(AuthValue auth) { Auth = auth; return this; }
/// <summary> /// Associates authorization value with the handle. /// This association is done automatically by TPM commands producing the /// corresponding handle or changing object's auth value. /// However on many occasions the library does not have access to the auth /// value at any moment before it is required for authorizing access to the /// handle. Notably, when an externally created key is imported, pre-existing /// NV index or persistent object is used, SetAuth() is required to associate /// auth value with the handle. /// </summary> /// <param name="auth"></param> /// <returns>Reference to this object, which can be used for chaining.</returns> public TpmHandle SetAuth(AuthValue auth) { Auth = auth; return(this); }
CreatePrimaryRsaAsync(int keyLen, AuthValue useAuth, TpmHash adminPolicy) { return(await CreatePrimaryRsaAsyncInternal(keyLen, useAuth.AuthVal, adminPolicy, null)); }
} // DoParmEncryption() /// <summary> /// Updates information associated by the library with TPM entity handles upon /// successful completion of a command that either creates a new entity or /// changes the properties of an existing one. /// /// Some important data associated with TPM entities cannot be retrieved from /// TPM either because of their sensitivity or because of substantial overhead. /// The information of the former kind is an auth value (for permanent handles, /// transient and persistent objects, NV indices) and a bound handle (for /// sessions). Information tracked for the sake of performance optimization /// is objects and NV index name. /// </summary> /// <param name="ordinal"></param> /// <param name="inParms"></param> /// <param name="inHandles"></param> // ReSharper disable once UnusedParameter.Local private void UpdateHandleData(TpmCc ordinal, TpmStructureBase inParms, TpmHandle[] inHandles, TpmStructureBase outParms) { switch (ordinal) { case TpmCc.Create: { var req = (Tpm2CreateRequest)inParms; var resp = (Tpm2CreateResponse)outParms; TpmHash priv = TpmHash.FromData(PrivHashAlg, resp.outPrivate.buffer); AuthValues[priv] = Globs.CopyData(req.inSensitive.userAuth); break; } case TpmCc.CreatePrimary: { var req = (Tpm2CreatePrimaryRequest)inParms; var resp = (Tpm2CreatePrimaryResponse)outParms; resp.objectHandle.Auth = req.inSensitive.userAuth; ProcessName(resp.objectHandle, resp.name, resp.outPublic); break; } case TpmCc.Load: { var req = (Tpm2LoadRequest)inParms; var resp = (Tpm2LoadResponse)outParms; TpmHash priv = TpmHash.FromData(PrivHashAlg, req.inPrivate.buffer); if (AuthValues.ContainsKey(priv)) resp.objectHandle.Auth = AuthValues[priv]; ProcessName(resp.objectHandle, resp.name, req.inPublic); break; } case TpmCc.LoadExternal: { var req = (Tpm2LoadExternalRequest)inParms; var resp = (Tpm2LoadExternalResponse)outParms; byte[] name = req.inPublic.GetName(); ProcessName(resp.objectHandle, resp.name, req.inPublic); break; } case TpmCc.StartAuthSession: { var req = (Tpm2StartAuthSessionRequest)inParms; var resp = (Tpm2StartAuthSessionResponse)outParms; SessionParams[resp.sessionHandle] = new AuthSession(req.sessionType, req.tpmKey, req.bind, req.nonceCaller, resp.nonceTPM, req.symmetric, req.authHash); break; } case TpmCc.HmacStart: { var req = (Tpm2HmacStartRequest)inParms; var resp = (Tpm2HmacStartResponse)outParms; resp.sequenceHandle.Auth = req.auth; resp.sequenceHandle.Name = null; break; } case TpmCc.NvDefineSpace: { var req = (Tpm2NvDefineSpaceRequest)inParms; req.publicInfo.nvIndex.Auth = req.auth; req.publicInfo.nvIndex.Name = null; break; } case TpmCc.NvChangeAuth: { var req = (Tpm2NvChangeAuthRequest)inParms; req.nvIndex.Auth = req.newAuth; break; } case TpmCc.ObjectChangeAuth: { var req = (Tpm2ObjectChangeAuthRequest)inParms; var resp = (Tpm2ObjectChangeAuthResponse)outParms; TpmHash priv = TpmHash.FromData(PrivHashAlg, resp.outPrivate.buffer); AuthValues[priv] = Globs.CopyData(req.newAuth); break; } case TpmCc.HierarchyChangeAuth: { var req = (Tpm2HierarchyChangeAuthRequest)inParms; AuthValue auth = Globs.CopyData(req.newAuth); switch (req.authHandle.handle) { case (uint)TpmRh.Owner: OwnerAuth = auth; break; case (uint)TpmRh.Endorsement: EndorsementAuth = auth; break; case (uint)TpmRh.Platform: PlatformAuth = auth; break; case (uint)TpmRh.Lockout: LockoutAuth = auth; break; } req.authHandle.Auth = auth; break; } case TpmCc.PcrSetAuthValue: { var req = (Tpm2PcrSetAuthValueRequest)inParms; req.pcrHandle.Auth = req.auth; if (PcrHandles == null) { uint numPcrs = GetProperty(this, Pt.PcrCount); PcrHandles = new TpmHandle[numPcrs]; } int pcrId = (int)req.pcrHandle.GetOffset(); Debug.Assert(pcrId < PcrHandles.Length); PcrHandles[pcrId] = req.pcrHandle; break; } case TpmCc.EvictControl: { var req = (Tpm2EvictControlRequest)inParms; var resp = (Tpm2EvictControlResponse)outParms; if (req.objectHandle.GetType() != Ht.Persistent) { req.persistentHandle.Auth = req.objectHandle.Auth; req.persistentHandle.Name = req.objectHandle.Name; } break; } case TpmCc.Clear: { OwnerAuth = new AuthValue(); EndorsementAuth = new AuthValue(); LockoutAuth = new AuthValue(); break; } case TpmCc.NvWrite: { var req = (Tpm2NvWriteRequest)inParms; // Force name recalculation before next use req.nvIndex.Name = null; break; } case TpmCc.NvWriteLock: { var req = (Tpm2NvWriteLockRequest)inParms; // Force name recalculation before next use req.nvIndex.Name = null; break; } case TpmCc.NvReadLock: { var req = (Tpm2NvReadLockRequest)inParms; // Force name recalculation before next use req.nvIndex.Name = null; break; } case TpmCc.HashSequenceStart: { var req = (Tpm2HashSequenceStartRequest)inParms; var resp = (Tpm2HashSequenceStartResponse)outParms; resp.sequenceHandle.Auth = req.auth; break; } case TpmCc.Startup: { var req = (Tpm2StartupRequest)inParms; if (req.startupType == Su.Clear) { PlatformAuth = new AuthValue(); } break; } case TpmCc.ContextSave: { var req = (Tpm2ContextSaveRequest)inParms; var resp = (Tpm2ContextSaveResponse)outParms; resp.context.savedHandle.Auth = req.saveHandle.Auth; resp.context.savedHandle.Name = req.saveHandle.Name; break; } case TpmCc.ContextLoad: { var req = (Tpm2ContextLoadRequest)inParms; var resp = (Tpm2ContextLoadResponse)outParms; resp.loadedHandle.Auth = req.context.savedHandle.Auth; resp.loadedHandle.Name = req.context.savedHandle.Name; break; } case TpmCc.NvUndefineSpaceSpecial: { var req = (Tpm2NvUndefineSpaceSpecialRequest)inParms; req.nvIndex.Auth = null; break; } } } // UpdateHandleData()
/// <summary> /// Create an RSA primary with the specified use-auth value and key size. /// </summary> /// <param name="keyLen"></param> /// <param name="useAuth"></param> /// <returns></returns> public async Task <Tpm2CreatePrimaryResponse> CreatePrimaryRsaAsync(int keyLen, AuthValue useAuth) { return(await CreatePrimaryRsaAsyncInternal(keyLen, useAuth.AuthVal, null, null)); }
/// <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.PolicyLocality, 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 policyTree = 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. // policyTree.Create( new PolicyAce[] { new TpmPolicyLocality(LocalityAttr.TpmLocZero), new TpmPolicyPcr(expectedPcrVals), "leaf" } ); // // Ask Tpm2Lib for the expected policy-hash for this policy // TpmHash expectedPolicyHash = policyTree.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, policyTree, "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, policyTree, 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); }
/// <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); }
internal static bool IsNull(AuthValue auth) { return(auth == null || auth.AuthVal.Length == 0); }
/// <summary> /// This sample demonstrates a policy containing ALL policy commands. /// It also demonstrates serialization of the policy, and the use /// of callbacks to satisfy the conditions in a policy (e.g. knowledge /// of a private key, or the NV-index associated with a name. /// </summary> /// <param name="tpm">Reference to the TPM used.</param> static void SamplePolicySerializationAndCallbacks(Tpm2 tpm) { Console.WriteLine("Policy sample that serializes all policy commands."); // // 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.PolicyPhysicalPresence, TpmCc.PolicySigned, TpmCc.PolicySecret, TpmCc.PolicyPCR, TpmCc.PolicyLocality, TpmCc.PolicyNV, TpmCc.PolicyCounterTimer, TpmCc.PolicyCommandCode, TpmCc.PolicyPassword, TpmCc.PolicyAuthorize, TpmCc.PolicyPhysicalPresence, TpmCc.PolicyCpHash, TpmCc.PolicyTicket, TpmCc.PolicyNameHash, TpmCc.PolicyCpHash, TpmCc.PolicyDuplicationSelect, TpmCc.PolicyAuthValue, TpmCc.PolicyNvWritten }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Policy serialization and callback sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // 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(); var pInit = new PolicyTree(TpmAlgId.Sha256); var p = new PolicyTree(TpmAlgId.Sha256); // // In the first part of this sample we establish keys, NV-slots, // etc. that will be used in the policy. // // // create a new RSA software signing key. We will use this for both // TpmPolicySigned AND TpmPolicyAuthorize. // var signKeyPublicTemplate = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Sign | ObjectAttr.Restricted | ObjectAttr.FixedTPM, new byte[0], new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa()); _publicSigningKey = new AsymCryptoSystem(signKeyPublicTemplate); // // Get an authorization ticket for TpmPolicyAuthorize. We will authorize // a policy-digest consisting of policyPhysPresense. // var tempPolicy = new PolicyTree(TpmAlgId.Sha256); tempPolicy.Create( new PolicyAce[] { new TpmPolicyPhysicalPresence(), "leaf" }); TpmHash initPolicyHash = tempPolicy.GetPolicyDigest(); var policyAuthRef = new byte[0]; byte[] dataToSign = Globs.Concatenate(initPolicyHash.HashData, policyAuthRef); byte[] aHash = CryptoLib.HashData(TpmAlgId.Sha256, Globs.Concatenate(initPolicyHash.HashData, policyAuthRef)); // // Sign the simple policy just containing PolicyPhysPres so that // we can change it to a new value with PolicyAuthorize. // ISignatureUnion policyAuthSig = _publicSigningKey.Sign(dataToSign); // // Get a ticket verifying the signature. // TpmHandle verifierHandle = tpm.LoadExternal(null, _publicSigningKey.GetPublicParms(), TpmHandle.RhOwner); tpm.VerifySignature(verifierHandle, aHash, policyAuthSig); tpm.FlushContext(verifierHandle); // // Get the value of PCR[1] // var pcrs = new uint[] { 1 }; var sel = new PcrSelection(TpmAlgId.Sha, pcrs); PcrSelection[] selOut; Tpm2bDigest[] pcrValues; tpm.PcrRead(new[] { sel }, out selOut, out pcrValues); // // Save the current PCR values in a convenient data structure // var expectedPcrVals = new PcrValueCollection(selOut, pcrValues); // // Set up an NV slot // TpmHandle nvHandle = TpmHandle.NV(3001); // // Clean anything that might have been there before // tpm[ownerAuth]._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle); AuthValue nvAuth = AuthValue.FromRandom(8); tpm[ownerAuth].NvDefineSpace(TpmHandle.RhOwner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.TpmaNvAuthread | NvAttr.TpmaNvAuthwrite, new byte[0], 32)); // // write some data // var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; tpm[nvAuth].NvWrite(nvHandle, nvHandle, nvData, 0); byte[] nvName; tpm.NvReadPublic(nvHandle, out nvName); // // Install evaluation callback // Note: generally the callback will check that the parameters are // actions that it is willing to authorize. Those checks are omitted here. // p.SetNvCallback((PolicyTree policyTree, TpmPolicyNV ace, out SessionBase authorizingSession, out TpmHandle authorizedEntityHandle, out TpmHandle nvHandleIs) => { authorizedEntityHandle = nvHandle; nvHandleIs = nvHandle; authorizingSession = nvAuth; }); // // counter-timer: The policy will check that the reset-count // is the current value. // int start, end; TimeInfo now = tpm.ReadClock(); Marshaller.GetFragmentInfo(now, "resetCount", out start, out end); byte[] operandB = Marshaller.GetTpmRepresentation(now.clockInfo.resetCount); // // Get a cpHash for the command we want to execute // var cpHash = new TpmHash(TpmAlgId.Sha256); tpm._GetCpHash(cpHash).HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); p.SetSignerCallback(SignerCallback); // // PolicySecret tests knowledge of ownerAuth. Note that the callback // will generally check that it is prepared to authorize what it is // being asked to authorize. Those checks are omitted here (we just // provide a PWAP session containing ownerAuth. // p.SetPolicySecretCallback((PolicyTree policyTree, TpmPolicySecret ace, out SessionBase authorizingSession, out TpmHandle authorizedEntityHandle, out bool flushAuthEntity) => { authorizingSession = ownerAuth; authorizedEntityHandle = TpmHandle.RhOwner; flushAuthEntity = false; }); // // If the policy contains a TpmPolicyAction then print out the // action string on the console. // p.SetPolicyActionCallback((PolicyTree policy, TpmPolicyAction ace) => Console.WriteLine(ace.Action)); var policyRef = new byte[] { 1, 2, 3, 4 }; // // Ticket expiration times have to be negative. // Positive expiration times do not generate a ticket. // _expectedExpirationTime = -60; // // A normalized policy is an array of policy-chains written as // arrays. Here "most" of the policy-ACEs are in the first chain, but some // ACEs cannot co-exist, and some need a ticket from a prior evaluation. // pInit.CreateNormalizedPolicy( new[] { new PolicyAce[] { new TpmPolicySigned(_publicSigningKey.GetPublicParms().GetName(), // Newly created PubKey true, // Nonce in signed data _expectedExpirationTime, // expirationTime new byte[0], // cpHash policyRef) // policyRef {NodeId = "Signing Key 1"}, // Distinguishing name // // Include owner-auth // new TpmPolicySecret(TpmHandle.RhOwner.GetName(), true, new byte[0], new byte[] {1, 2, 3}, 0), // // Include PCR-values read earlier // new TpmPolicyPcr(expectedPcrVals), // // Command must be issued at locality two // new TpmPolicyLocality(LocalityAttr.TpmLocTwo), // // NV-data we set earlier must be present // new TpmPolicyNV(nvName, nvData, 0, Eo.Eq), // // This is a "dummy ACE" that is not executed on the TPM but // a callback will be invoked at when the policy is executed. // One use case for this is to increment a counter between two // PolicyNV counter-checks. // new TpmPolicyAction("Output of TpmPolicyAction when executed."), // // Boot-count must be what we read earlier // new TpmPolicyCounterTimer(operandB, (ushort) start, Eo.Eq), // // Only authorize HierarchyChangeAuth // new TpmPolicyCommand(TpmCc.HierarchyChangeAuth), // // Include password // new TpmPolicyPassword(), // // Authorize a change from PolicyPP (last ACE below) // new TpmPolicyAuthorize(initPolicyHash.HashData, policyAuthRef, _publicSigningKey.GetPublicParms(), TpmAlgId.Sha256, policyAuthSig), // // Demand that the command be executed with PP asserted // new TpmPolicyPhysicalPresence(), // // Name for this branch // "branch_1" }, new PolicyAce[] { // // Bind to command/parameters // new TpmPolicyCpHash(cpHash), // // Name for this branch // "branch_2" }, new PolicyAce[] { new TpmPolicyTicket(_publicSigningKey.GetPublicParms(), policyRef, TpmSt.AuthSigned) // // Distinguishing name for this node // {NodeId = "PolicyTicket"}, // // Name for this branch // "branch_3" }, // // TODO: These ACEs are not evaluated yet in this sample // new PolicyAce[] { new TpmPolicyNameHash(), new TpmPolicyCpHash(cpHash), new TpmPolicyDuplicationSelect(new byte[0], new byte[0], true), new TpmPolicyAuthValue(), // Include entity authValue in HMAC new TpmPolicyNvWritten(), "branch_4" } } ); TpmHash policyHash = pInit.GetPolicyDigest(); // // Check that we can serialize and deserialize the policy // const string fileName = @".\test1.xml"; pInit.SerializeToFile("Sample Policy",PolicySerializationFormat.Xml, fileName); p.DeserializeFromFile(PolicySerializationFormat.Xml, fileName); // // And check that the policy hash is the same // TpmHash deserializedHash = p.GetPolicyDigest(); if (policyHash != deserializedHash) { throw new Exception("Serialization error"); } // // Execute the policy on the TPM. Start with "branch_1". // AuthSession s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); s0.RunPolicy(tpm, p, "branch_1"); // // Check that the executed policy has the correct digest // byte[] actualPolicyDigest = tpm.PolicyGetDigest(s0.Handle); if (policyHash != actualPolicyDigest) { throw new Exception("Policy Evaluation error"); } // // Set a command to use the policy // tpm[ownerAuth].SetPrimaryPolicy(TpmHandle.RhOwner, policyHash.HashData, TpmAlgId.Sha256); // // And then execute the command // tpm._AssertPhysicalPresence(true); tpm._SetLocality(LocalityAttr.TpmLocTwo); tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); tpm._SetLocality(LocalityAttr.TpmLocZero); tpm._AssertPhysicalPresence(false); tpm.FlushContext(s0.Handle); // // Next, "branch_2". // s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); s0.RunPolicy(tpm, p, "branch_2"); tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); tpm.FlushContext(s0.Handle); // // Now "branch_3" - ticket. Copy parms out of the ticket/ACE returned // from TpmPolicySinged above. // var sigAce = p.GetAce<TpmPolicySigned>("Signing Key 1"); TkAuth signedTicket = p.GetTicket("Signing Key 1"); var tickAce = p.GetAce<TpmPolicyTicket>("PolicyTicket"); tickAce.CpHash = sigAce.CpHash; tickAce.PolicyRef = sigAce.PolicyRef; tickAce.ExpirationTime = sigAce.GetTimeout(); tickAce.SetTicket(signedTicket); s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); s0.RunPolicy(tpm, p, "branch_3"); tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); tpm.FlushContext(s0.Handle); Console.WriteLine("Finished SamplePolicySerializationAndCallbacks."); }
/// <summary> /// Demonstrate use of NV counters. /// </summary> /// <param name="tpm">Reference to the TPM object.</param> static void NVCounter(Tpm2 tpm) { // // 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(); TpmHandle nvHandle = TpmHandle.NV(3001); // // Clean up any slot that was left over from an earlier run // tpm[ownerAuth]._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle); // // Scenario 2 - A NV-counter // AuthValue nvAuth = AuthValue.FromRandom(8); tpm[ownerAuth].NvDefineSpace(TpmHandle.RhOwner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Counter | NvAttr.Authread | NvAttr.Authwrite, new byte[0], 8)); // // Must write before we can read // tpm[nvAuth].NvIncrement(nvHandle, nvHandle); // // Read the current value // byte[] nvRead = tpm[nvAuth].NvRead(nvHandle, nvHandle, 8, 0); var initVal = Marshaller.FromTpmRepresentation<ulong>(nvRead); // // Increment // tpm[nvAuth].NvIncrement(nvHandle, nvHandle); // // Read again and see if the answer is what we expect // nvRead = tpm[nvAuth].NvRead(nvHandle, nvHandle, 8, 0); var finalVal = Marshaller.FromTpmRepresentation<ulong>(nvRead); if (finalVal != initVal + 1) { throw new Exception("NV-counter fail"); } Console.WriteLine("Incremented counter from {0} to {1}.", initVal, finalVal); // // Clean up // tpm[ownerAuth].NvUndefineSpace(TpmHandle.RhOwner, nvHandle); }
internal static bool IsNull(AuthValue auth) { return auth == null || auth.AuthVal.Length == 0; }