in TPM Parser/Tpm2Lib/Tpm2.cs [736:845]
public static bool CrackCommand(
byte[] command,
out CommandHeader header,
out TpmHandle[] handles,
out SessionIn[] sessions,
out byte[] commandParms)
{
var m = new Marshaller(command);
header = m.Get<CommandHeader>();
CommandInfo commandInfo = Tpm2.CommandInfoFromCommandCode(header.CommandCode);
if (header.Tag == TpmSt.Null)
{
// A diagnostics command. Pass through unmodified
handles = null;
sessions = null;
commandParms = null;
return false;
}
handles = new TpmHandle[commandInfo.HandleCountIn];
for (int j = 0; j < handles.Length; j++)
{
handles[j] = m.Get<TpmHandle>();
}
// Note sessions are only present if the command tag indicates sessions
if (header.Tag == TpmSt.Sessions)
{
uint sessionLength = m.Get<uint>();
uint sessionStart = m.GetGetPos();
uint sessionEnd = sessionStart + sessionLength;
// if bytes between m.GetGetPos() and sessionEnd are all 0xAA this is
// a censored session.
byte[] sessionArray = m.GetNBytes((int)sessionLength);
if (Array.TrueForAll<byte>(sessionArray, element => { return element == 0xAA; }))
{
// yes, censored buffer, try to replace with intelligent guess
// authorization field consist of:
// TPM20_HANDLE Handle; // authHandle: TPM_RH_PW
// UINT16 Nonce2B; // TPM2B_NONCE
// UINT8 Session; // TPMA_SESSION
// UINT16 Auth2B; // TPM2B_AUTH
// to make intelligent guess about size of nonce and auth,
// subtract constant sized field (9 bytes). Nonce is usually
// a hash, so it should be either 20, 32, 48, or 64 bytes.
// the auth value would make up the rest, but also usually
// be the result of a hash operation.
sessionLength = sessionLength - sizeof(uint) - sizeof(ushort) - sizeof(byte) - sizeof(ushort);
ushort nonceSize;
if (sessionLength/2 == TpmHash.DigestSize(TpmAlgId.Sha1) ||
sessionLength/2 == TpmHash.DigestSize(TpmAlgId.Sha256) ||
sessionLength/2 == TpmHash.DigestSize(TpmAlgId.Sha384) ||
sessionLength/2 == TpmHash.DigestSize(TpmAlgId.Sha512))
{
nonceSize = (ushort)(sessionLength / 2);
}
else if (sessionLength >= TpmHash.DigestSize(TpmAlgId.Sha512))
{
nonceSize = TpmHash.DigestSize(TpmAlgId.Sha512);
}
else if (sessionLength >= TpmHash.DigestSize(TpmAlgId.Sha384))
{
nonceSize = TpmHash.DigestSize(TpmAlgId.Sha384);
}
else if (sessionLength >= TpmHash.DigestSize(TpmAlgId.Sha256))
{
nonceSize = TpmHash.DigestSize(TpmAlgId.Sha256);
}
else if (sessionLength >= TpmHash.DigestSize(TpmAlgId.Sha1))
{
nonceSize = TpmHash.DigestSize(TpmAlgId.Sha1);
}
else
{
// 0 <= sessionLength < size of SHA1 digest
nonceSize = (ushort)sessionLength;
}
// marshal nonceSize
sessionArray[4] = (byte)(nonceSize >> 8);
sessionArray[5] = (byte)nonceSize;
// marshall session
int sessionOffset = sizeof(uint) + sizeof(ushort) + nonceSize;
sessionArray[sessionOffset] = 0;
// marshall authSize
ushort authSize = (ushort)(sessionLength - nonceSize);
sessionArray[sessionOffset + 1] = (byte)(authSize >> 8);
sessionArray[sessionOffset + 2] = (byte)authSize;
m.SetBytes(sessionArray, sessionStart);
}
m.SetGetPos(sessionStart);
var inSessions = new List<SessionIn>();
while (m.GetGetPos() < sessionEnd)
{
var s = m.Get<SessionIn>();
inSessions.Add(s);
}
sessions = inSessions.ToArray();
}
else
{
sessions = new SessionIn[0];
}
// And finally parameters
commandParms = m.GetArray<byte>((int)(m.GetValidLength() - m.GetGetPos()));
if (m.GetValidLength() != header.CommandSize)
{
Globs.Throw("Command length in header does not match input byte-stream");
return false;
}
return true;
}