internal void SetPersistedUri(string uri) { TpmHandle nvHandle = new TpmHandle(PERSISTED_URI_INDEX + logicalDeviceId); TpmHandle ownerHandle = new TpmHandle(TpmRh.Owner); UTF8Encoding utf8 = new UTF8Encoding(); byte[] nvData = utf8.GetBytes(uri); // Open the TPM Tpm2Device tpmDevice = new TbsDevice(); tpmDevice.Connect(); using (var tpm = new Tpm2(tpmDevice)) { // Define the store tpm.NvDefineSpace(ownerHandle, Array.Empty <byte>(), new NvPublic(nvHandle, TpmAlgId.Sha256, NvAttr.Authwrite | NvAttr.Authread | NvAttr.NoDa, Array.Empty <byte>(), (ushort)nvData.Length)); // Write the store tpm.NvWrite(nvHandle, nvHandle, nvData, 0); } }
internal static void NVCounter(Tpm2 tpm) { TpmHandle nvHandle = TpmHandle.NV(3001); tpm._AllowErrors().NvUndefineSpace(TpmRh.Owner, nvHandle); tpm.NvDefineSpace(TpmRh.Owner, AuthValue.FromRandom(8), new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Counter | NvAttr.Authread | NvAttr.Authwrite, null, 8)); tpm.NvIncrement(nvHandle, nvHandle); byte[] nvRead = tpm.NvRead(nvHandle, nvHandle, 8, 0); var initVal = Marshaller.FromTpmRepresentation <ulong>(nvRead); tpm.NvIncrement(nvHandle, nvHandle); nvRead = tpm.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); tpm.NvUndefineSpace(TpmRh.Owner, nvHandle); } //NVCounter
public void Provision(string encodedHmacKey, string hostName, string deviceId = "") { TpmHandle nvHandle = new TpmHandle(AIOTH_PERSISTED_URI_INDEX + logicalDeviceId); TpmHandle ownerHandle = new TpmHandle(TpmRh.Owner); TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE + logicalDeviceId); TpmHandle srkHandle = new TpmHandle(SRK_HANDLE); UTF8Encoding utf8 = new UTF8Encoding(); byte[] nvData = utf8.GetBytes(hostName + "/" + deviceId); byte[] hmacKey = System.Convert.FromBase64String(encodedHmacKey); // Open the TPM Tpm2Device tpmDevice = new TbsDevice(); tpmDevice.Connect(); var tpm = new Tpm2(tpmDevice); // Define the store tpm.NvDefineSpace(ownerHandle, new byte[0], new NvPublic(nvHandle, TpmAlgId.Sha256, NvAttr.Authwrite | NvAttr.Authread | NvAttr.NoDa, new byte[0], (ushort)nvData.Length)); // Write the store tpm.NvWrite(nvHandle, nvHandle, nvData, 0); // Import the HMAC key under the SRK TpmPublic hmacPub; CreationData creationData; byte[] creationhash; TkCreation ticket; TpmPrivate hmacPrv = tpm.Create(srkHandle, new SensitiveCreate(new byte[0], hmacKey), new TpmPublic(TpmAlgId.Sha256, ObjectAttr.UserWithAuth | ObjectAttr.NoDA | ObjectAttr.Sign, new byte[0], new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)), new Tpm2bDigestKeyedhash()), new byte[0], new PcrSelection[0], out hmacPub, out creationData, out creationhash, out ticket); // Load the HMAC key into the TPM TpmHandle loadedHmacKey = tpm.Load(srkHandle, hmacPrv, hmacPub); // Persist the key in NV tpm.EvictControl(ownerHandle, loadedHmacKey, hmacKeyHandle); // Unload the transient copy from the TPM tpm.FlushContext(loadedHmacKey); }
/// <summary> /// Demonstrate use of NV counters. /// </summary> /// <param name="tpm">Reference to the TPM object.</param> 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. // TpmHandle nvHandle = TpmHandle.NV(3001); // // Clean up any slot that was left over from an earlier run // tpm._AllowErrors() .NvUndefineSpace(TpmRh.Owner, nvHandle); // // Scenario 2 - A NV-counter // tpm.NvDefineSpace(TpmRh.Owner, AuthValue.FromRandom(8), new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Counter | NvAttr.Authread | NvAttr.Authwrite, null, 8)); // // Must write before we can read // tpm.NvIncrement(nvHandle, nvHandle); // // Read the current value // byte[] nvRead = tpm.NvRead(nvHandle, nvHandle, 8, 0); var initVal = Marshaller.FromTpmRepresentation <ulong>(nvRead); // // Increment // tpm.NvIncrement(nvHandle, nvHandle); // // Read again and see if the answer is what we expect // nvRead = tpm.NvRead(nvHandle, nvHandle, 8, 0); var finalVal = Marshaller.FromTpmRepresentation <ulong>(nvRead); if (finalVal != initVal + 1) { throw new Exception("NV-counter fail"); } this.textBlock.Text += "Incremented counter from " + initVal.ToString() + " to " + finalVal.ToString() + ". "; // // Clean up // tpm.NvUndefineSpace(TpmRh.Owner, nvHandle); }
internal static 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._AllowErrors() .NvUndefineSpace(TpmRh.Owner, nvHandle); // // Scenario 1 - write and read a 32-byte NV-slot // AuthValue nvAuth = AuthValue.FromRandom(8); tpm.NvDefineSpace(TpmRh.Owner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Authread | NvAttr.Authwrite, null, 32)); // // Write some data // var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; tpm.NvWrite(nvHandle, nvHandle, nvData, 0); // // And read it back // byte[] nvRead = tpm.NvRead(nvHandle, nvHandle, (ushort)nvData.Length, 0); // // Is it correct? // bool correct = nvData.SequenceEqual(nvRead); if (!correct) { throw new Exception("NV data was incorrect."); } Console.WriteLine("NV data written and read."); // // And clean up // tpm.NvUndefineSpace(TpmRh.Owner, nvHandle); }
private void ProvisionUri(string hostName, string deviceId = "") { TpmHandle nvHandle = new TpmHandle(AIOTH_PERSISTED_URI_INDEX); TpmHandle ownerHandle = new TpmHandle(TpmRh.Owner); UTF8Encoding utf8 = new UTF8Encoding(); byte[] nvData = utf8.GetBytes(hostName + "/" + deviceId); // Define the store _tpm2.NvDefineSpace(ownerHandle, Array.Empty <byte>(), new NvPublic(nvHandle, TpmAlgId.Sha256, NvAttr.Authwrite | NvAttr.Authread | NvAttr.NoDa, Array.Empty <byte>(), (ushort)nvData.Length)); // Write the store _tpm2.NvWrite(nvHandle, nvHandle, nvData, 0); }
public void TestTpmCollector() { var PcrAlgorithm = TpmAlgId.Sha256; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var process = TpmSim.GetTpmSimulator(); process.Start(); var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; uint nvIndex = 3001; var tpmc = new TpmCollector(new CollectorOptions() { Verbose = true }, null, TestMode: true); // Prepare to write to NV 3001 TpmHandle nvHandle = TpmHandle.NV(nvIndex); TcpTpmDevice tcpTpmDevice = new TcpTpmDevice("127.0.0.1", 2321, stopTpm: false); tcpTpmDevice.Connect(); using var tpm = new Tpm2(tcpTpmDevice); tcpTpmDevice.PowerCycle(); tpm.Startup(Su.Clear); try { tpm._AllowErrors() .NvUndefineSpace(TpmRh.Owner, nvHandle); tpm.NvDefineSpace(TpmRh.Owner, null, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.NoDa | NvAttr.Ownerread | NvAttr.Ownerwrite, null, 32)); // Write to NV 3001 tpm.NvWrite(TpmRh.Owner, nvHandle, nvData, 0); var nvOut = tpm.NvRead(TpmRh.Owner, nvHandle, (ushort)nvData.Length, 0); Assert.IsTrue(nvOut.SequenceEqual(nvData)); } catch (TpmException e) { Log.Debug(e, "Failed to Write to NV."); Assert.Fail(); } // Verify that all the PCRs are blank to start with var pcrs = TpmCollector.DumpPCRs(tpm, PcrAlgorithm, new PcrSelection[] { new PcrSelection(PcrAlgorithm, new uint[] { 15, 16 }) }); Assert.IsTrue(pcrs.All(x => x.Value.SequenceEqual(new byte[x.Value.Length]))); // Measure to PCR 16 try { tpm.PcrExtend(TpmHandle.Pcr(16), tpm.PcrEvent(TpmHandle.Pcr(16), nvData)); } catch (TpmException e) { Log.Debug(e, "Failed to Write PCR."); } // Verify that we extended the PCR var pcrs2 = TpmCollector.DumpPCRs(tpm, PcrAlgorithm, new PcrSelection[] { new PcrSelection(PcrAlgorithm, new uint[] { 15, 16 }, 24) }); Assert.IsTrue(pcrs2[(PcrAlgorithm, 15)].SequenceEqual(pcrs[(PcrAlgorithm, 15)]));
/// <summary> /// Funzione per il salvataggio della chiave privata da utilizzare per firmare con HMAC tramite TPM /// </summary> /// <param name="encodedHmacKey"></param> public static void SaveHmacKey(string encodedHmacKey) { // Definizione area di memoria non volatile nel TPM TpmHandle nvHandle = new TpmHandle(AIOTH_PERSISTED_URI_INDEX + logicalDeviceId); // Definizione dell'handle contenente l'Owner nel TPM TpmHandle ownerHandle = new TpmHandle(TpmRh.Owner); // Definizione dell'handle per la memorizzazione dell'oggetto HMAC TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE + logicalDeviceId); // Definizione dell'handle della Storage Root Key, si tratta della chiave // principale utilizzata per il salvataggio di altre chiavi. Ogni chiave salvata // nel TPM infatti viene cifrata utilizzando la sua chiave "padre". // La SRK è la chiave più alta dell'albero TpmHandle srkHandle = new TpmHandle(SRK_HANDLE); UTF8Encoding utf8 = new UTF8Encoding(); // dati descrittivi dell'host e del device id byte[] nvData = utf8.GetBytes(hostName + "/" + deviceId); // chiave privata che intendiamo memorizzare nel TPM byte[] hmacKey = System.Convert.FromBase64String(encodedHmacKey); // Apertura del TPM Tpm2Device tpmDevice = new TbsDevice(); tpmDevice.Connect(); var tpm = new Tpm2(tpmDevice); // Definizione dello store Non volatile // Il primo parametro è l'Owner TPM // il terzo parametro è la funzione HMAC che intendiamo salvare // (NvPublic sta per Non volatile public area) tpm.NvDefineSpace(ownerHandle, new byte[0], new NvPublic( nvHandle, TpmAlgId.Sha256, NvAttr.Authwrite | NvAttr.Authread | NvAttr.NoDa, new byte[0], (ushort)nvData.Length)); // Scrittura nello store non volatile della funzione HMAC tpm.NvWrite(nvHandle, nvHandle, nvData, 0); // Importazione della chiave HMAC sotto la Storage Root Key TpmPublic hmacPub; CreationData creationData; byte[] creationhash; TkCreation ticket; // Passaggio della chiave privata var sensitiveCreate = new SensitiveCreate(new byte[0], hmacKey); // Definizione dell'uso che si farà della chiave var tpmPublic = new TpmPublic( TpmAlgId.Sha256, ObjectAttr.UserWithAuth | ObjectAttr.NoDA | ObjectAttr.Sign, new byte[0], new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)), new Tpm2bDigestKeyedhash()); // Salvataggio della chiave privata nel tpm TpmPrivate hmacPrv = tpm.Create( srkHandle, sensitiveCreate, tpmPublic, new byte[0], new PcrSelection[0], out hmacPub, out creationData, out creationhash, out ticket); // Caricamento della chiave HMAC nel TPM TpmHandle loadedHmacKey = tpm.Load(srkHandle, hmacPrv, hmacPub); // Salvataggio della chiave nella memoria Non Volatile tpm.EvictControl(ownerHandle, loadedHmacKey, hmacKeyHandle); // Flush degli oggetti transienti dal tpm tpm.FlushContext(loadedHmacKey); }
/// <summary> /// This sample demonstrates the creation and use of TPM NV-storage /// </summary> /// <param name="tpm">Reference to TPM object.</param> static void NvReadWriteWithOwnerAuth(Tpm2 tpm) { if (tpm._GetUnderlyingDevice().GetType() != typeof(TbsDevice)) { return; } int nvIndex = 3001; // arbitrarely chosen TpmHandle nvHandle = TpmHandle.NV(nvIndex); // // The NV auth value is required to read and write the NV slot after it has been // created. Because this test is supposed to be used in different conditions: // first as Administrator to create the NV slot, and then as Standard User to read // it, the test uses a well defined authorization value. // // In a real world scenario, tha authorization value should be bigger and random, // or include a policy with better policy. For example, the next line could be // substitued with: // AuthValue nvAuth = AuthValue.FromRandom(32); // which requires storage of the authorization value for reads. // AuthValue nvAuth = new AuthValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; WindowsIdentity identity = WindowsIdentity.GetCurrent(); WindowsPrincipal principal = new WindowsPrincipal(identity); if (principal.IsInRole(WindowsBuiltInRole.Administrator)) { Console.WriteLine("Running as Administrator. Deleting and re-creating NV entry."); // // 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. // byte[] ownerAuth; if (GetOwnerAuthFromOS(out ownerAuth)) { tpm.OwnerAuth = ownerAuth; } else { Console.WriteLine("Could not retrieve owner auth from registry. Trying empty auth."); } bool failed; do { failed = false; // // Clean up any slot that was left over from an earlier run. // Only clean up the nvIndex if data from a possible previous invocation // should be deleted. // // Another approach could be to invoke NvDefineSpace, check if the call // returns TpmRc.NvDefined, then try a read with the known/stored // NV authorization value. If that succeeds, the likelyhood that this // NV index already contains valid data is high. // tpm._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle); // // Define the NV slot. The authorization passed in as nvAuth will be // needed for future NvRead and NvWrite access. (Attribute Authread // specifies that authorization is required to read. Attribute Authwrite // specifies that authorization is required to write.) // try { tpm.NvDefineSpace(TpmHandle.RhOwner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.Authread | NvAttr.Authwrite, new byte[0], 32)); } catch (TpmException e) { if (e.RawResponse == TpmRc.NvDefined) { nvIndex++; nvHandle = TpmHandle.NV(nvIndex); Console.WriteLine("NV index already taken, trying next."); failed = true; } else { Console.WriteLine("Exception {0}\n{1}", e.Message, e.StackTrace); return; } } // // Store successful nvIndex and nvAuth, so next invocation as client // knows which index to read. For instance in registry. Storage of // nvAuth is only required if attributes of NvDefineSpace include // NvAttr.Authread. // } while (failed); // // Now that NvDefineSpace succeeded, write some random data (nvData) to // nvIndex. Note that NvDefineSpace defined the NV slot to be 32 bytes, // so a NvWrite (nor NvRead) should try to write more than that. // If more data has to be written to the NV slot, NvDefineSpace should // be adjusted accordingly. // Console.WriteLine("Writing NVIndex {0}.", nvIndex); tpm[nvAuth].NvWrite(nvHandle, nvHandle, nvData, 0); Console.WriteLine("Written: {0}", BitConverter.ToString(nvData)); } // // Read the data back. // Console.WriteLine("Reading NVIndex {0}.", nvIndex); byte[] nvRead = tpm[nvAuth].NvRead(nvHandle, nvHandle, (ushort)nvData.Length, 0); Console.WriteLine("Read: {0}", BitConverter.ToString(nvRead)); // // Optional: compare if data read from NV slot is the same as data // written to it. // We can only compare if running as admin, because the data has been // generated with admin account. // if (principal.IsInRole(WindowsBuiltInRole.Administrator)) { bool correct = nvData.SequenceEqual(nvRead); if (!correct) { throw new Exception("NV data was incorrect."); } } Console.WriteLine("NV access complete."); if (principal.IsInRole(WindowsBuiltInRole.Administrator)) { // // Optional: clean up. // If NvIndex should stick around, skip this code. // //tpm.NvUndefineSpace(TpmHandle.RhOwner, nvHandle); } }