in TSS.Java/src/tss/TpmBase.java [221:445]
protected void DispatchCommand(TPM_CC cmdCode, ReqStructure req, RespStructure resp)
{ try {
TPM_HANDLE[] inHandles = req.getHandles();
int numAuthHandles = req.numAuthHandles();
boolean hasSessions = numAuthHandles != 0 || Sessions != null;
int sessTag = hasSessions ? TPM_ST.SESSIONS.toInt() : TPM_ST.NO_SESSIONS.toInt();
TpmBuffer cmdBuf = new TpmBuffer();
// Standard TPM command header {tag, length, commandCode}
cmdBuf.writeShort(sessTag);
cmdBuf.writeInt(0); // to be filled in later
cmdBuf.writeInt(cmdCode.toInt());
// Handles
int numHandles = inHandles == null ? 0 : inHandles.length;
for (int i=0; i < numHandles; i++)
inHandles[i].toTpm(cmdBuf);
// Marshal command params (without handles) to paramBuf
TpmBuffer paramBuf = new TpmBuffer();
req.toTpm(paramBuf);
paramBuf.trim();
byte[] cpHashData = null;
//
// Authorization sessions
//
if (hasSessions)
{
// We do not know the size of the authorization area yet.
// Remember the place to marshal it, ...
int authSizePos = cmdBuf.curPos();
// ... and marshal a placeholder 0 value for now.
cmdBuf.writeInt(0);
// todo: Make Sessions type Session[]
// If not all required sessions were provided explicitly, TSS.Java will create the necessary
// number of password sessions with auth values (if any) from the corresponding TPM_HANDLE objects.
int numExplicitSessions = 0;
if (Sessions == null)
Sessions = new TPM_HANDLE[numAuthHandles];
else
{
numExplicitSessions = Sessions.length;
if (numExplicitSessions < numAuthHandles)
Sessions = Arrays.copyOf(Sessions, numAuthHandles);
}
for (int i = numExplicitSessions; i < numAuthHandles; ++i)
Sessions[i] = TPM_HANDLE.PW;
TPMA_SESSION sessAttrs = TPMA_SESSION.continueSession;
for (int i=0; i < Sessions.length; i++)
{
// todo: Add support for policyc sessions with HMAC
boolean needAuth = i < numHandles && Sessions[i].getType() != TPM_HT.POLICY_SESSION;
WriteSession (cmdBuf, Sessions[i], null, sessAttrs,
needAuth ? inHandles[i].AuthValue : null);
}
Sessions = null;
cmdBuf.writeNumAtPos(cmdBuf.curPos() - authSizePos - 4, authSizePos);
}
// Write marshaled command params to the command buffer
cmdBuf.writeByteBuf(paramBuf.buffer());
// Finally, set the command buffer size
cmdBuf.writeNumAtPos(cmdBuf.curPos(), 2);
if (CpHash != null || AuditCommand)
{
if (cpHashData == null)
cpHashData = GetCpHashData(cmdCode, paramBuf.buffer());
if (CpHash != null)
{
CpHash.digest = Crypto.hash(CpHash.hashAlg, cpHashData);
clearInvocationState();
Sessions = null;
CpHash = null;
return;
}
AuditCpHash.digest = Crypto.hash(CommandAuditHash.hashAlg, cpHashData);
}
byte[] rawCmdBuf = cmdBuf.trim();
int nvRateRecoveryCount = 4;
TpmBuffer respBuf = null;
TPM_ST respTag = TPM_ST.NULL;
int respSize = 0;
int rawResponseCode = 0;
while (true)
{
device.dispatchCommand(rawCmdBuf);
byte[] rawRespBuf = device.getResponse();
respBuf = new TpmBuffer(rawRespBuf);
// get the standard header
respTag = TPM_ST.fromTpm(respBuf);
respSize = respBuf.readInt();
rawResponseCode = respBuf.readInt();
int actRespSize = respBuf.size();
if (respSize != actRespSize)
{
throw new TpmException(String.format(
"Inconsistent TPM response buffer: %d B reported, %d B received", respSize, actRespSize));
}
lastResponseCode = TpmHelpers.fromRawResponse(rawResponseCode);
if (callbackObject != null)
callbackObject.commandCompleteCallback(cmdCode, lastResponseCode, rawCmdBuf, rawRespBuf);
if (lastResponseCode == TPM_RC.RETRY)
continue;
if (lastResponseCode != TPM_RC.NV_RATE || ++nvRateRecoveryCount > 4)
break;
// todo: Enable TPM property retrieval and sleep below, and remove the following break
break;
//System.out.println(">>>> NV_RATE: Retrying... Attempt " + nvRateRecoveryCount.toString());
//Thread.Sleep((int)Tpm2.GetProperty(this, Pt.NvWriteRecovery) + 100);
}
// Interpretation of the response code depends on whether the programmer
// has indicated that an error is expected or allowed.
if (lastResponseCode != TPM_RC.SUCCESS)
{
// error - decode it
if (AllowErrors)
return; // Any error is allowed
if (Helpers.isOneOf(lastResponseCode, ExpectedResponses))
return; // The given error is expected
if (_isSuccessExpected())
{
System.out.println("TPM ERROR: " + lastResponseCode);
throw new TpmException(lastResponseCode, rawResponseCode);
}
String expected = ExpectedResponses.length > 1 ? Arrays.toString(ExpectedResponses)
: ExpectedResponses[0].toString();
throw new TpmException("Unexpected response {" + lastResponseCode + "} instead of {" + expected + "}",
lastResponseCode);
}
else if (ExpectedResponses != null)
{
String expected = ExpectedResponses.length > 1 ? "s " + Arrays.toString(ExpectedResponses) + " were"
: " " + ExpectedResponses.toString() + " was";
throw new TpmException("Error" + expected + " expected, " +
"but the TPM command " + cmdCode + " succeeded");
}
// Keep a copy of this before we clean out invocation state
boolean auditCommand = AuditCommand;
clearInvocationState();
// A check for the session tag consistency across the command invocation
// only makes sense when the command succeeds.
if (respTag.toInt() != sessTag)
throw new TpmException("Unexpected response tag " + respTag);
if (resp == null)
resp = new RespStructure(); // use a placeholder to avoid null checks
if (resp.numHandles() > 0)
{
assert(resp.numHandles() == 1);
resp.setHandle(TPM_HANDLE.fromTpm(respBuf));
}
boolean rpReady = false;
int respParamsPos = 0,
respParamsSize = 0;
// If there are no sessions then response parameters take up the remaining part
// of the response buffer. Otherwise the response parameters area is preceded with
// its size, and followed by the session area.
if (respTag == TPM_ST.SESSIONS)
{
respParamsSize = respBuf.readInt();
respParamsPos = respBuf.curPos();
rpReady = processRespSessions(respBuf, cmdCode, respParamsPos, respParamsSize);
}
else
{
respParamsPos = respBuf.curPos();
respParamsSize = respBuf.size() - respParamsPos;
}
if (auditCommand)
{
byte[] rpHash = getRpHash(CommandAuditHash.hashAlg, respBuf,
cmdCode, respParamsPos, respParamsSize, rpReady);
CommandAuditHash.extend(Helpers.concatenate(AuditCpHash.digest, rpHash));
}
// Now we can decrypt (if necessary) the first response parameter
doParmEncryption(resp, respBuf, respParamsPos, false);
// ... and unmarshall the whole response parameters area
respBuf.curPos(respParamsPos);
resp.initFromTpm(respBuf);
if (respBuf.curPos() != respParamsPos + respParamsSize)
throw new TpmException("Bad response parameters area");
// If there is a returned handle get a pointer to it. It is always the
// first element in the structure.
updateRespHandle(cmdCode, resp);
Sessions = null;
} finally {
clearInvocationState();
}} // DispatchCommand()