internal static TpmHandle CreateEncryptionDecryptionKey(Tpm2 tpm, TpmHandle parent) { var sensCreate = new SensitiveCreate(null, null); var sym = new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb); var pub = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Decrypt | ObjectAttr.UserWithAuth, null, sym, new Tpm2bDigestSymcipher()); TssObject swKey = TssObject.Create(pub); var innerWrapKey = sym == null ? null : SymCipher.Create(sym); byte[] name, qname; TpmPublic pubParent = tpm.ReadPublic(parent, out name, out qname); byte[] encSecret; TpmPrivate dupBlob = swKey.GetDuplicationBlob(pubParent, innerWrapKey, out encSecret); TpmPrivate privImp = tpm.Import(parent, innerWrapKey, swKey.Public, dupBlob, encSecret, sym ?? new SymDefObject()); TpmHandle hKey = tpm.Load(parent, privImp, swKey.Public) .SetAuth(swKey.Sensitive.authValue); return(hKey); }
/// <summary> /// De-envelope inner-wrapped duplication blob. /// TODO: Move this to TpmPublic and make it fully general /// </summary> /// <param name="exportedPrivate"></param> /// <param name="encAlg"></param> /// <param name="encKey"></param> /// <param name="nameAlg"></param> /// <param name="name"></param> /// <returns></returns> public static Sensitive SensitiveFromDuplicateBlob(TpmPrivate exportedPrivate, SymDefObject encAlg, byte[] encKey, TpmAlgId nameAlg, byte[] name) { byte[] dupBlob = exportedPrivate.buffer; byte[] sensNoLen; using (SymmCipher c = Create(encAlg, encKey)) { byte[] innerObject = c.Decrypt(dupBlob); byte[] innerIntegrity, sensitive; KDF.Split(innerObject, 16 + CryptoLib.DigestSize(nameAlg) * 8, out innerIntegrity, 8 * (innerObject.Length - CryptoLib.DigestSize(nameAlg) - 2), out sensitive); byte[] expectedInnerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(nameAlg, sensitive, name)); if (!Globs.ArraysAreEqual(expectedInnerIntegrity, innerIntegrity)) { Globs.Throw("SensitiveFromDuplicateBlob: Bad inner integrity"); } sensNoLen = Marshaller.Tpm2BToBuffer(sensitive); } var sens = Marshaller.FromTpmRepresentation <Sensitive>(sensNoLen); return(sens); }
} // SimpleDuplicateImportRsaSample TssObject ImportExternalRsaKey(Tpm2 tpm, TpmHandle hParent, int keySizeInBits, IAsymSchemeUnion scheme, byte[] publicPart, byte[] privatePart, ObjectAttr keyAttrs, byte[] authVal = null, byte[] policyDigest = null) { TpmAlgId sigHashAlg = TpmHelper.GetSchemeHash(scheme), nameAlg = sigHashAlg; // TPM signing key template with the actual public key bits var inPub = new TpmPublic(nameAlg, keyAttrs, policyDigest, new RsaParms(new SymDefObject(), scheme as IAsymSchemeUnion, (ushort)keySizeInBits, 0), new Tpm2bPublicKeyRsa(publicPart)); // Wrap the key in a TSS helper class TssObject swKey = TssObject.Create(inPub, authVal, privatePart); // Get a key duplication blob in TPM 2.0 compatibale format TpmPrivate dupBlob = swKey.GetPlaintextDuplicationBlob(); // Importing a duplication blob creates a new TPM private key blob protected // with its new parent key. swKey.Private = tpm.Import(hParent, null, swKey.Public, dupBlob, null, new SymDefObject()); return(swKey); } // ImportExternalRsaKey
void DuplicateImportRsaSample(Tpm2 tpm, TestContext testCtx) { TpmAlgId nameAlg = Substrate.Random(TpmCfg.HashAlgs); var policy = new PolicyTree(nameAlg); policy.SetPolicyRoot(new TpmPolicyCommand(TpmCc.Duplicate)); var inPub = new TpmPublic(nameAlg, ObjectAttr.Sign | ObjectAttr.AdminWithPolicy | ObjectAttr.SensitiveDataOrigin, policy.GetPolicyDigest(), new RsaParms(new SymDefObject(), new SchemeRsassa(Substrate.Random(TpmCfg.HashAlgs)), Substrate.Random(TpmCfg.RsaKeySizes), 0), new Tpm2bPublicKeyRsa()); TpmHandle hKey = Substrate.CreateAndLoad(tpm, inPub, out TpmPublic pub); // Duplicate TpmPrivate priv = TpmHelper.GetPlaintextPrivate(tpm, hKey, policy); tpm.FlushContext(hKey); // Import TpmPrivate privImp = tpm.Import(Substrate.LoadRsaPrimary(tpm), null, pub, priv, null, new SymDefObject()); } // SimpleDuplicateImportRsaSample
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> /// Instantiates the object using a TPM generated key pair /// </summary> /// <param name="pub"></param> /// <param name="priv"></param> public RawRsa(TpmPublic pub, TpmPrivate priv) { var m = new Marshaller(priv.buffer); var privSize = m.Get <UInt16>(); // Assert that the private key blob is in plain text Debug.Assert(priv.buffer.Length == privSize + 2); var sens = m.Get <Sensitive>(); Init(pub, sens.sensitive as Tpm2bPrivateKeyRsa); }
public Sensitive GetSensitive() { TpmPublic fromCspPublic; TpmPrivate fromCspPrivate = Csp.CspToTpm(ExportCspBlob(), out fromCspPublic); var m = new Marshaller(fromCspPrivate.buffer); ushort privSize = m.Get <UInt16>(); if (fromCspPrivate.buffer.Length != privSize + 2) { Globs.Throw("Invalid key blob"); } return(m.Get <Sensitive>()); }
public static TpmPrivate GetPlaintextPrivate(Tpm2 tpm, TpmHandle key, PolicyTree policy) { AuthSession sess = tpm.StartAuthSessionEx(TpmSe.Policy, policy.HashAlg); sess.RunPolicy(tpm, policy); TpmPrivate privPlain = null; byte[] symSeed; tpm[sess]._ExpectResponses(TpmRc.Success, TpmRc.Attributes) .Duplicate(key, TpmRh.Null, null, new SymDefObject(), out privPlain, out symSeed); Debug.Assert(!tpm._LastCommandSucceeded() || symSeed.Length == 0); tpm.FlushContext(sess); return(Globs.IsEmpty(privPlain.buffer) ? null : privPlain); }
/// <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); } }
/// <summary> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <param name="privKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(Native.BCRYPT_RSA_ALGORITHM); cs.Key = alg.LoadRSAKey(exponent, modulus, prime1, prime2); alg.Close(); #else var dotNetPubParms = new RSAParameters() { Exponent = exponent, Modulus = modulus }; if (privKey != null) { dotNetPubParms.P = prime1; dotNetPubParms.Q = prime2; dotNetPubParms.D = RawRsa.ToBigEndian(rr.D); dotNetPubParms.InverseQ = RawRsa.ToBigEndian(rr.InverseQ); dotNetPubParms.DP = RawRsa.ToBigEndian(rr.DP); dotNetPubParms.DQ = RawRsa.ToBigEndian(rr.DQ); } cs.RsaProvider = new RSACryptoServiceProvider(); cs.RsaProvider.ImportParameters(dotNetPubParms); #endif break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(algId); cs.Key = alg.ImportKeyPair(Native.BCRYPT_ECCPUBLIC_BLOB, keyBlob); alg.Close(); if (cs.Key == UIntPtr.Zero) { Globs.Throw("Failed to create new RSA key"); return(null); } #else CngKey eccKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob); if (pubKey.objectAttributes.HasFlag(ObjectAttr.Sign)) { cs.EcdsaProvider = new ECDsaCng(eccKey); } else { cs.EcDhProvider = new ECDiffieHellmanCng(eccKey); } #endif // !TSS_USE_BCRYPT break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
public TssObject(TpmPublic thePublicPart, TpmPrivate thePrivatePart) { Public = thePublicPart; Private = thePrivatePart; }
} // 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> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; AsymmetricKeyAlgorithmProvider rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); uint primeLen1 = 0, primeLen2 = 0; // Compute the size of BCRYPT_RSAKEY_BLOB int rsaKeySize = exponent.Length + modulus.Length + 24; if (prime1 != null && prime1.Length > 0) { if (prime2 == null || prime2.Length == 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The second prime is missing"); return(null); } primeLen1 = (uint)prime1.Length; primeLen2 = (uint)prime2.Length; rsaKeySize += prime1.Length + prime2.Length; } else if (prime2 != null && prime2.Length > 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The first prime is missing"); return(null); } var rsaKey = new byte[rsaKeySize]; // Initialize BCRYPT_RSAKEY_BLOB int offset = 0; WriteToBuffer(ref rsaKey, ref offset, primeLen1 == 0 ? BCRYPT_RSAPUBLIC_MAGIC : BCRYPT_RSAPRIVATE_MAGIC); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length * 8); WriteToBuffer(ref rsaKey, ref offset, (uint)exponent.Length); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, exponent); WriteToBuffer(ref rsaKey, ref offset, modulus); if (primeLen1 != 0) { WriteToBuffer(ref rsaKey, ref offset, prime1); WriteToBuffer(ref rsaKey, ref offset, prime2); } IBuffer rsaBuffer = CryptographicBuffer.CreateFromByteArray(rsaKey); if (primeLen1 == 0) { cs.Key = rsaProvider.ImportPublicKey(rsaBuffer, CryptographicPublicKeyBlobType.BCryptPublicKey); } else { cs.Key = rsaProvider.ImportKeyPair(rsaBuffer, CryptographicPrivateKeyBlobType.BCryptPrivateKey); } break; } case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); AsymmetricKeyAlgorithmProvider eccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algId); cs.Key = eccProvider.ImportKeyPair(CryptographicBuffer.CreateFromByteArray(keyBlob)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
public TssObject(TpmPublic thePublicPart, TpmPrivate thePrivatePart) { publicPart = thePublicPart; privatePart = thePrivatePart; }
/// <summary> /// Activates a symmetric identity within the Hardware Security Module. /// </summary> /// <param name="activation">The authentication challenge key supplied by the service.</param> public override void ActivateSymmetricIdentity(byte[] activation) { Destroy(); // Take the pieces out of the container var m = new Marshaller(activation, DataRepresentation.Tpm); byte[] credentialBlob = new byte[m.Get <ushort>()]; credentialBlob = m.GetArray <byte>(credentialBlob.Length, "credentialBlob"); byte[] encryptedSecret = new byte[m.Get <ushort>()]; encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret"); TpmPrivate dupBlob = m.Get <TpmPrivate>(); byte[] encWrapKey = new byte[m.Get <ushort>()]; encWrapKey = m.GetArray <byte>(encryptedSecret.Length, "encWrapKey"); UInt16 pubSize = m.Get <UInt16>(); _idKeyPub = m.Get <TpmPublic>(); byte[] cipherText = new byte[m.Get <ushort>()]; cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo"); // Setup the authorization session for the EK var policyNode = new TpmPolicySecret( TpmHandle.RhEndorsement, _ekAuth ?? Array.Empty <byte>(), new AuthValue(), false, 0, Array.Empty <byte>(), Array.Empty <byte>()); var policy = new PolicyTree(_ekPub.nameAlg); policy.SetPolicyRoot(policyNode); AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg); ekSession.RunPolicy(_tpm2, policy); // Perform the activation ekSession.Attrs &= ~SessionAttr.ContinueSession; _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential( new TpmHandle(TPM_20_SRK_HANDLE), new TpmHandle(TPM_20_EK_HANDLE), credentialBlob, encryptedSecret); TpmPrivate importedKeyBlob = _tpm2.Import( new TpmHandle(TPM_20_SRK_HANDLE), _activationSecret, _idKeyPub, dupBlob, encWrapKey, new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb)); _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub); // Persist the key in NV TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE); _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle); // Unload the transient copy from the TPM _tpm2.FlushContext(_idKeyHandle); _idKeyHandle = hmacKeyHandle; // Unwrap the URI byte[] clearText = SymmCipher.Decrypt( new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), _activationSecret, new byte[16], cipherText); UnicodeEncoding unicode = new UnicodeEncoding(); string uriData = unicode.GetString(clearText); int idx = uriData.IndexOf('/'); if (idx > 0) { string hostName = uriData.Substring(0, idx); string deviceId = uriData.Substring(idx + 1); // Persist the URI ProvisionUri(hostName, deviceId); } }
/// <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); }
void TestAutomaticAuth(Tpm2 tpm, TestContext testCtx) { TpmHandle hPrim = Substrate.LoadRsaPrimary(tpm); // Make an RSA encryption key. var decScheme = new SchemeOaep(Substrate.Random(TpmCfg.HashAlgs)); var sigScheme = new SchemeRsassa(Substrate.Random(TpmCfg.HashAlgs)); ushort keyLength = Substrate.RandomRsaKeySize(decScheme.hashAlg); var inPub = new TpmPublic(Substrate.Random(TpmCfg.HashAlgs), ObjectAttr.Decrypt | ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin, null, new RsaParms(new SymDefObject(), null, keyLength, 0), new Tpm2bPublicKeyRsa()); TpmPublic keyPublic; TpmPrivate keyPrivate = Substrate.Create(tpm, hPrim, inPub, out keyPublic); TpmHandle keyHandle = null; tpm._Behavior.Strict = true; try { // No auth session is added automatically when TPM object is in strict mode. tpm._ExpectError(TpmRc.AuthMissing) .Load(hPrim, keyPrivate, keyPublic); // Now explicitly request an auth session of appropriate type keyHandle = tpm[Auth.Default].Load(hPrim, keyPrivate, keyPublic); } finally { tpm._Behavior.Strict = false; } byte[] message = Substrate.RandBytes(1, TpmHelper.MaxOaepMsgSize(keyLength, decScheme.hashAlg)); byte[] encrypted = tpm.RsaEncrypt(keyHandle, message, decScheme, null); // An auth session is added automatically when TPM object is not in strict mode. byte[] decrypted1 = tpm.RsaDecrypt(keyHandle, encrypted, decScheme, null); TpmAlgId auditHashAlg = Substrate.Random(TpmCfg.HashAlgs); byte[] nonceTpm; // AuthSession object can be built from session handle concatenated, if necessary, // with session flags and unencrypted salt value (not used in this example). AuthSession auditSess = tpm.StartAuthSession( TpmRh.Null, // no salt TpmRh.Null, // no bind object Substrate.RandomNonce(auditHashAlg), // nonceCaller null, // no salt TpmSe.Hmac, // session type new SymDef(), // no encryption/decryption auditHashAlg, // authHash out nonceTpm) + (SessionAttr.ContinueSession | SessionAttr.Audit); /* * Alternatively one of the StartAuthSessionEx helpers can be used) * AuthSession auditSess = tpm.StartAuthSessionEx(TpmSe.Hmac, auditHashAlg, null, * SessionAttr.ContinueSession | SessionAttr.Audit); */ // TSS-specific call to verify TPM auditing correctness. tpm._SetCommandAuditAlgorithm(auditHashAlg); // Appropriate auth value is added automatically into the provided session byte[] decrypted2 = tpm[auditSess]._Audit() .RsaDecrypt(keyHandle, encrypted, decScheme, null); ISignatureUnion sig; Attest attest; // A session is added automatically to authorize TpmRh.Endorsement usage. attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess, null, new NullSigScheme(), out sig); // But if the corresponding auth value stored in the Tpm2 object is invalid, ... AuthValue endorsementAuth = tpm.EndorsementAuth; tpm.EndorsementAuth = Globs.ByteArray(16, 0xde); // ... the command will fail tpm._ExpectError(TpmRc.BadAuth) .GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess, null, new NullSigScheme(), out sig); // Restore correct auth value. tpm.EndorsementAuth = endorsementAuth; // Verify that both decryption and auditing worked correctly. SessionAuditInfo info = (SessionAuditInfo)attest.attested; byte[] auditDigest = tpm._GetAuditHash(); testCtx.AssertEqual("AuditSessionDigest", info.sessionDigest, auditDigest); testCtx.AssertEqual("Decryption", decrypted1, decrypted2); // Change auth value of the decryption key. TpmPrivate newKeyPrivate = tpm.ObjectChangeAuth(keyHandle, hPrim, Substrate.RandomAuth(keyPublic.nameAlg)); TpmHandle newKeyHandle = tpm.Load(hPrim, newKeyPrivate, keyPublic); auditSess.Attrs &= ~SessionAttr.AuditExclusive; // Correct auth value (corresponding to newKeyHandle, and different from // the one used for keyHandle) will be added to auditSess. decrypted1 = tpm[auditSess]._Audit().RsaDecrypt(newKeyHandle, encrypted, decScheme, null); // And now two sessions are auto-generated (for TpmRh.Endorsement and keyHandle). attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess, null, sigScheme, out sig); bool sigOk = keyPublic.VerifySignatureOverData( Marshaller.GetTpmRepresentation(attest), sig); testCtx.Assert("AuditSessionSignatute.1", sigOk); // Here the first session is generated based on session type indicator // (Auth.Pw), and the second one is added automatically. attest = tpm[Auth.Pw].GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess, null, sigScheme, out sig); // Verify that auditing worked correctly. sigOk = keyPublic.VerifySignatureOverData( Marshaller.GetTpmRepresentation(attest), sig); testCtx.Assert("AuditSessionSignatute.2", sigOk); tpm.FlushContext(newKeyHandle); tpm.FlushContext(auditSess); if (!TestCfg.HasTRM) { // Deplete TPM's active session storage List <AuthSession> landfill = new List <AuthSession>(); for (;;) { tpm._AllowErrors(); AuthSession s = tpm.StartAuthSessionEx(TpmSe.Hmac, Substrate.Random(TpmCfg.HashAlgs), SessionAttr.ContinueSession); if (!tpm._LastCommandSucceeded()) { break; } landfill.Add(s); } // Check if session type indicators are processed correctly tpm[Auth.Hmac]._ExpectError(TpmRc.SessionMemory) .RsaDecrypt(keyHandle, encrypted, null, null); tpm[Auth.Pw].RsaDecrypt(keyHandle, encrypted, null, null); // Check if default session type defined by the TPM device is processed correctly bool needHmac = tpm._GetUnderlyingDevice().NeedsHMAC; tpm._GetUnderlyingDevice().NeedsHMAC = true; tpm._ExpectError(TpmRc.SessionMemory) .RsaDecrypt(keyHandle, encrypted, null, null); tpm[Auth.Default]._ExpectError(TpmRc.SessionMemory) .RsaDecrypt(keyHandle, encrypted, null, null); tpm._GetUnderlyingDevice().NeedsHMAC = false; tpm.RsaDecrypt(keyHandle, encrypted, null, null); tpm[Auth.Default].RsaDecrypt(keyHandle, encrypted, null, null); tpm._GetUnderlyingDevice().NeedsHMAC = needHmac; landfill.ForEach(s => tpm.FlushContext(s)); } tpm.FlushContext(keyHandle); } // TestAutomaticAuth
/// <summary> /// Illustrates various cases of automatic authorization handling. /// </summary> static void AutomaticAuth(Tpm2 tpm) { TpmHandle primHandle = CreateRsaPrimaryKey(tpm); TpmPublic keyPublic; TpmHandle keyHandle = CreateSigningDecryptionKey(tpm, primHandle, out keyPublic); byte[] message = Globs.GetRandomBytes(32); IAsymSchemeUnion decScheme = new SchemeOaep(TpmAlgId.Sha1); ISigSchemeUnion sigScheme = new SchemeRsassa(TpmAlgId.Sha1); // // TSS.Net implicitly creates an auth session to authorize keyHandle. // It uses the auth value cached in the TpmHandle object. // byte[] encrypted = tpm.RsaEncrypt(keyHandle, message, decScheme, null); Console.WriteLine("Automatic authorization of a decryption key."); // // An auth session is added automatically when TPM object is not in strict mode. // byte[] decrypted1 = tpm.RsaDecrypt(keyHandle, encrypted, decScheme, null); byte[] nonceTpm; Console.WriteLine("Session object construction."); // // If a session with specific properties is required, an AuthSession object // can be built from the session handle returned by the TPM2_StartAuthSession // command concatenated, if necessary, with session flags and unencrypted salt // value (not used in this example). // AuthSession auditSess = tpm.StartAuthSession( TpmRh.Null, // no salt TpmRh.Null, // no bind object Globs.GetRandomBytes(16), // nonceCaller null, // no salt TpmSe.Hmac, // session type new SymDef(), // no encryption/decryption TpmAlgId.Sha256, // authHash out nonceTpm) + (SessionAttr.ContinueSession | SessionAttr.Audit); /* * Alternatively one of the StartAuthSessionEx helpers can be used). E.g. * * AuthSession auditSess = tpm.StartAuthSessionEx(TpmSe.Hmac, TpmAlgId.Sha256, * SessionAttr.ContinueSession | SessionAttr.Audit); */ // // TSS.Net specific call to verify TPM auditing correctness. // tpm._SetCommandAuditAlgorithm(TpmAlgId.Sha256); Console.WriteLine("Automatic authorization using explicitly created session object."); // // Appropriate auth value is added automatically into the provided session. // // Note that the call to _Audit() is optional and is only used when one // needs the TSS.Net framework to compute the audit digest on its own (e.g. // when simulating the TPM functionality without access to an actual TPM). // byte[] decrypted2 = tpm[auditSess]._Audit() .RsaDecrypt(keyHandle, encrypted, decScheme, null); ISignatureUnion signature; Attest attest; // // A session is added automatically to authorize usage of the permanent // handle TpmRh.Endorsement. // // Note that if auth value of TpmRh.Endorsement is not empty, you need to // explicitly assign it to the tpm.EndorsementAuth property of the given // Tpm2 object. // attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess, null, new NullSigScheme(), out signature); // // But if the corresponding auth value stored in the Tpm2 object is invalid, ... // AuthValue endorsementAuth = tpm.EndorsementAuth; tpm.EndorsementAuth = Globs.ByteArray(16, 0xde); // // ... the command will fail. // tpm._ExpectError(TpmRc.BadAuth) .GetSessionAuditDigest(TpmRh.Endorsement, TpmRh.Null, auditSess, null, new NullSigScheme(), out signature); // // Restore correct auth value. // tpm.EndorsementAuth = endorsementAuth; // // Verify that decryption worked correctly. // Debug.Assert(Globs.ArraysAreEqual(decrypted1, decrypted2)); // // Verify that auditing worked correctly. // SessionAuditInfo info = (SessionAuditInfo)attest.attested; Debug.Assert(Globs.ArraysAreEqual(info.sessionDigest, tpm._GetAuditHash().HashData)); Console.WriteLine("Auth value tracking by TSS.Net."); // // Change auth value of the decryption key. // TpmPrivate newKeyPrivate = tpm.ObjectChangeAuth(keyHandle, primHandle, AuthValue.FromRandom(16)); TpmHandle newKeyHandle = tpm.Load(primHandle, newKeyPrivate, keyPublic); // // Allow non-exclusive usage of the audit session. // auditSess.Attrs &= ~SessionAttr.AuditExclusive; // // Correct auth value (corresponding to newKeyHandle, and different from // the one used for keyHandle) will be added to auditSess. // decrypted1 = tpm[auditSess]._Audit() .RsaDecrypt(newKeyHandle, encrypted, decScheme, null); Console.WriteLine("Automatic authorization with multiple sessions."); // // Now two sessions are auto-generated (for TpmRh.Endorsement and keyHandle). // attest = tpm.GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess, null, sigScheme, out signature); // // Verify that the previous command worked correctly. // bool sigOk = keyPublic.VerifySignatureOverData(Marshaller.GetTpmRepresentation(attest), signature); Debug.Assert(sigOk); // // In the following example the first session is generated based on session // type indicator (Auth.Pw), and the second one is added automatically. // attest = tpm[Auth.Pw].GetSessionAuditDigest(TpmRh.Endorsement, keyHandle, auditSess, null, sigScheme, out signature); // // Verify that the previous command worked correctly. // sigOk = keyPublic.VerifySignatureOverData(Marshaller.GetTpmRepresentation(attest), signature); Debug.Assert(sigOk); // // Release TPM resources that we do not need anymore. // tpm.FlushContext(newKeyHandle); tpm.FlushContext(auditSess); // // The following example works correctly only when TPM resource management // is not enabled (e.g. with TPM simulator, or when actual TPM is in raw mode). // if (!tpm._GetUnderlyingDevice().HasRM()) { Console.WriteLine("Using session type indicators."); // // Deplete TPM's active session storage // List <AuthSession> landfill = new List <AuthSession>(); for (;;) { tpm._AllowErrors(); AuthSession s = tpm.StartAuthSessionEx(TpmSe.Hmac, TpmAlgId.Sha256, SessionAttr.ContinueSession); if (!tpm._LastCommandSucceeded()) { break; } landfill.Add(s); } // // Check if session type indicators are processed correctly // tpm[Auth.Hmac]._ExpectError(TpmRc.SessionMemory) .RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null); // // Password authorization protocol session uses a predefined handle value, // so it must work even when there are no free session slots in the TPM. // tpm[Auth.Pw].RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null); // // Check if default session type defined by the TPM device is processed correctly. // bool needHmac = tpm._GetUnderlyingDevice().NeedsHMAC; tpm._GetUnderlyingDevice().NeedsHMAC = true; tpm._ExpectError(TpmRc.SessionMemory) .RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null); tpm[Auth.Default]._ExpectError(TpmRc.SessionMemory) .RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null); tpm._GetUnderlyingDevice().NeedsHMAC = false; tpm.RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null); tpm[Auth.Default].RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), null); tpm._GetUnderlyingDevice().NeedsHMAC = needHmac; landfill.ForEach(s => tpm.FlushContext(s)); } // // Release TPM resources. // tpm.FlushContext(keyHandle); tpm.FlushContext(primHandle); Console.WriteLine("Done."); }
/// <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> /// Activates an identity key within the TPM device. /// </summary> /// <param name="encryptedKey">The encrypted identity key.</param> public override void ActivateIdentityKey(byte[] encryptedKey) { if (Logging.IsEnabled) { Logging.Enter(this, $"{encryptedKey}", nameof(ActivateIdentityKey)); } Destroy(); // Take the pieces out of the container var m = new Marshaller(encryptedKey, DataRepresentation.Tpm); Tpm2bIdObject cred2b = m.Get <Tpm2bIdObject>(); byte[] encryptedSecret = new byte[m.Get <ushort>()]; encryptedSecret = m.GetArray <byte>(encryptedSecret.Length, "encryptedSecret"); TpmPrivate dupBlob = m.Get <TpmPrivate>(); byte[] encWrapKey = new byte[m.Get <ushort>()]; encWrapKey = m.GetArray <byte>(encWrapKey.Length, "encWrapKey"); UInt16 pubSize = m.Get <UInt16>(); _idKeyPub = m.Get <TpmPublic>(); byte[] cipherText = new byte[m.Get <ushort>()]; cipherText = m.GetArray <byte>(cipherText.Length, "uriInfo"); // Setup the authorization session for the EK var policyNode = new TpmPolicySecret(TpmHandle.RhEndorsement, false, 0, Array.Empty <byte>(), Array.Empty <byte>()); var policy = new PolicyTree(_ekPub.nameAlg); policy.SetPolicyRoot(policyNode); AuthSession ekSession = _tpm2.StartAuthSessionEx(TpmSe.Policy, _ekPub.nameAlg); ekSession.RunPolicy(_tpm2, policy); // Perform the activation ekSession.Attrs &= ~SessionAttr.ContinueSession; _activationSecret = _tpm2[Array.Empty <byte>(), ekSession].ActivateCredential( new TpmHandle(TPM_20_SRK_HANDLE), new TpmHandle(TPM_20_EK_HANDLE), cred2b.credential, encryptedSecret); TpmPrivate importedKeyBlob = _tpm2.Import( new TpmHandle(TPM_20_SRK_HANDLE), _activationSecret, _idKeyPub, dupBlob, encWrapKey, new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb)); _idKeyHandle = _tpm2.Load(new TpmHandle(TPM_20_SRK_HANDLE), importedKeyBlob, _idKeyPub); // Persist the key in NV TpmHandle hmacKeyHandle = new TpmHandle(AIOTH_PERSISTED_KEY_HANDLE); _tpm2.EvictControl(new TpmHandle(TpmRh.Owner), _idKeyHandle, hmacKeyHandle); // Unload the transient copy from the TPM _tpm2.FlushContext(_idKeyHandle); _idKeyHandle = hmacKeyHandle; if (Logging.IsEnabled) { Logging.Exit(this, $"{encryptedKey}", nameof(ActivateIdentityKey)); } }
/// <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