/// <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);
byte[] encrypted = tpm.RsaEncrypt(keyHandle, message, decScheme, new byte[0]);
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, new byte[0]);
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
new byte[0], // 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.
//
byte[] decrypted2 = tpm[auditSess]._Audit()
.RsaDecrypt(keyHandle, encrypted, decScheme, new byte[0]);
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,
new byte[0], 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,
new byte[0], 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, new byte[0]);
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,
new byte[0], sigScheme, out signature);
//
// Verify that the previous command worked correctly.
//
bool sigOk = keyPublic.VerifySignatureOverData(Marshaller.GetTpmRepresentation(attest),
signature, TpmAlgId.Sha1);
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,
new byte[0], sigScheme, out signature);
//
// Verify that the previous command worked correctly.
//
sigOk = keyPublic.VerifySignatureOverData(Marshaller.GetTpmRepresentation(attest),
signature, TpmAlgId.Sha1);
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(), new byte[0]);
//
// 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(), new byte[0]);
//
// 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(), new byte[0]);
tpm[Auth.Default]._ExpectError(TpmRc.SessionMemory)
.RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), new byte[0]);
tpm._GetUnderlyingDevice().NeedsHMAC = false;
tpm.RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), new byte[0]);
tpm[Auth.Default].RsaDecrypt(keyHandle, encrypted, new NullAsymScheme(), new byte[0]);
tpm._GetUnderlyingDevice().NeedsHMAC = needHmac;
landfill.ForEach(s => tpm.FlushContext(s));
}
//
// Release TPM resources.
//
tpm.FlushContext(keyHandle);
tpm.FlushContext(primHandle);
Console.WriteLine("Done.");
}