/// <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."); }
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