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> /// Provision the key in the TPM /// </summary> /// <param name="key">the access key</param> public void Provision(byte[] key) { TpmHandle ownerHandle = new TpmHandle(TpmRh.Owner); TpmHandle hmacKeyHandle = new TpmHandle(PERSISTED_KEY_HANDLE + logicalDeviceId); TpmHandle srkHandle = new TpmHandle(TPM_20_SRK_HANDLE); // Open the TPM Tpm2Device tpmDevice = new TbsDevice(); tpmDevice.Connect(); using (var tpm = new Tpm2(tpmDevice)) { #pragma warning disable IDE0059 // Value assigned to symbol is never used // Import the HMAC key under the SRK TpmPrivate hmacPrv = tpm.Create(srkHandle, new SensitiveCreate(Array.Empty <byte>(), key), new TpmPublic(TpmAlgId.Sha256, ObjectAttr.UserWithAuth | ObjectAttr.NoDA | ObjectAttr.Sign, Array.Empty <byte>(), new KeyedhashParms(new SchemeHmac(TpmAlgId.Sha256)), new Tpm2bDigestKeyedhash()), Array.Empty <byte>(), Array.Empty <PcrSelection>(), out TpmPublic hmacPub, out CreationData creationData, out byte[] creationhash, out TkCreation ticket); #pragma warning restore IDE0059 // Value assigned to symbol is never used // 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); } }
} // 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> /// 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> /// Creates a child of the given storage key, which can be used both for signing and decryption. /// Illustrates strict mode effect on automatic authorization handling. /// </summary> /// <returns>Handle of the created key.</returns> static TpmHandle CreateSigningDecryptionKey(Tpm2 tpm, TpmHandle primHandle, out TpmPublic keyPublic) { TpmPublic keyInPublic = new TpmPublic( TpmAlgId.Sha1, ObjectAttr.Decrypt | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin, null, new RsaParms( new SymDefObject(), new NullAsymScheme(), 2048, 0), new Tpm2bPublicKeyRsa()); SensitiveCreate sensCreate = new SensitiveCreate(new byte[] { 1, 2, 3 }, null); CreationData keyCreationData; TkCreation creationTicket; byte[] creationHash; Console.WriteLine("Automatic authorization of a primary storage key."); // // An auth session is added automatically to authorize access to primHandle. // TpmPrivate keyPrivate = tpm.Create(primHandle, sensCreate, keyInPublic, null, new PcrSelection[0], out keyPublic, out keyCreationData, out creationHash, out creationTicket); TpmHandle keyHandle = null; Console.WriteLine("Strict mode."); // // Switch TPM object to the strict mode. (Note that this is a TSS.Net // specific piece of functionality, not a part of TPM 2.0 specification). // tpm._Behavior.Strict = true; // // No auth session is added automatically when TPM object is in strict mode. // tpm._ExpectError(TpmRc.AuthMissing) .Load(primHandle, keyPrivate, keyPublic); // // Now explicitly request an auth session of a desired type. // The actual auth value will be supplied by TSS.Net implicitly. // keyHandle = tpm[Auth.Default].Load(primHandle, keyPrivate, keyPublic); Console.WriteLine("Signing decryption key created."); // // Switch TPM object back to the normal mode. // tpm._Behavior.Strict = false; return(keyHandle); }