Initial Commit
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import type { TpmsAttest } from "../attest/attest.types.js";
|
||||
import type { TpmtPublic } from "../public/public.types.js";
|
||||
|
||||
/**
|
||||
* Render a parsed `TpmsAttest` or `TpmtPublic` as a human-readable multi-line
|
||||
* dump for debugging.
|
||||
*
|
||||
* Telemetry is NEVER emitted from this function — the diagnostic dumper is
|
||||
* for human consumption only and SHOULD NOT be invoked from production hot
|
||||
* paths. Symbolic `TPM_ALG_*` and `TPM_ECC_*` names appear inline so the
|
||||
* output is grep-friendly.
|
||||
*/
|
||||
export function toDiagnostic(value: TpmsAttest | TpmtPublic): string {
|
||||
if (isAttest(value)) {
|
||||
return renderAttest(value);
|
||||
}
|
||||
return renderPublic(value);
|
||||
}
|
||||
|
||||
function isAttest(v: TpmsAttest | TpmtPublic): v is TpmsAttest {
|
||||
return (
|
||||
typeof (v as { type?: string }).type === "string" &&
|
||||
(v as { type: string }).type.startsWith("TPM_ST_ATTEST_")
|
||||
);
|
||||
}
|
||||
|
||||
function renderAttest(a: TpmsAttest): string {
|
||||
const lines: string[] = [];
|
||||
lines.push("TPMS_ATTEST {");
|
||||
lines.push(` magic: 0x${a.magic.toString(16)}`);
|
||||
lines.push(` type: ${a.type}`);
|
||||
lines.push(` qualifiedSigner: ${hex(a.qualifiedSigner)}`);
|
||||
lines.push(` extraData: ${hex(a.extraData)}`);
|
||||
lines.push(
|
||||
` clockInfo: { clock: ${a.clockInfo.clock}n, resetCount: ${a.clockInfo.resetCount}, restartCount: ${a.clockInfo.restartCount}, safe: ${a.clockInfo.safe} }`
|
||||
);
|
||||
lines.push(` firmwareVersion: ${a.firmwareVersion}n`);
|
||||
lines.push(` attested: ${renderAttested(a)}`);
|
||||
lines.push("}");
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function renderAttested(a: TpmsAttest): string {
|
||||
switch (a.type) {
|
||||
case "TPM_ST_ATTEST_CERTIFY":
|
||||
return `TPMS_CERTIFY_INFO { name: ${hex(a.attested.name)}, qualifiedName: ${hex(a.attested.qualifiedName)} }`;
|
||||
case "TPM_ST_ATTEST_QUOTE":
|
||||
return `TPMS_QUOTE_INFO { banks: ${a.attested.pcrSelect.length}, pcrDigest: ${hex(a.attested.pcrDigest)} }`;
|
||||
case "TPM_ST_ATTEST_SESSION_AUDIT":
|
||||
return `TPMS_SESSION_AUDIT_INFO { exclusive: ${a.attested.exclusiveSession}, sessionDigest: ${hex(a.attested.sessionDigest)} }`;
|
||||
case "TPM_ST_ATTEST_COMMAND_AUDIT":
|
||||
return `TPMS_COMMAND_AUDIT_INFO { counter: ${a.attested.auditCounter}n, digestAlg: ${a.attested.digestAlg}, auditDigest: ${hex(a.attested.auditDigest)} }`;
|
||||
case "TPM_ST_ATTEST_TIME":
|
||||
return `TPMS_TIME_ATTEST_INFO { time: ${a.attested.time.time}n, firmwareVersion: ${a.attested.firmwareVersion}n }`;
|
||||
case "TPM_ST_ATTEST_CREATION":
|
||||
return `TPMS_CREATION_INFO { objectName: ${hex(a.attested.objectName)}, creationHash: ${hex(a.attested.creationHash)} }`;
|
||||
case "TPM_ST_ATTEST_NV":
|
||||
return `TPMS_NV_CERTIFY_INFO { indexName: ${hex(a.attested.indexName)}, offset: ${a.attested.offset}, contents: ${hex(a.attested.nvContents)} }`;
|
||||
case "TPM_ST_ATTEST_NV_DIGEST":
|
||||
return `TPMS_NV_DIGEST_CERTIFY_INFO { indexName: ${hex(a.attested.indexName)}, nvDigest: ${hex(a.attested.nvDigest)} }`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderPublic(p: TpmtPublic): string {
|
||||
const lines: string[] = [];
|
||||
lines.push("TPMT_PUBLIC {");
|
||||
lines.push(` type: ${p.type}`);
|
||||
lines.push(` nameAlg: ${p.nameAlg}`);
|
||||
lines.push(
|
||||
` objectAttributes: { raw: 0x${p.objectAttributes.raw.toString(16).padStart(8, "0")}, flags: ${flagSummary(p.objectAttributes.flags)} }`
|
||||
);
|
||||
lines.push(` authPolicy: ${hex(p.authPolicy)}`);
|
||||
if (p.type === "TPM_ALG_RSA") {
|
||||
lines.push(
|
||||
` parameters: TPMS_RSA_PARMS { keyBits: ${p.parameters.keyBits}, exponent: ${p.parameters.exponent}, scheme: ${p.parameters.scheme.scheme} }`
|
||||
);
|
||||
lines.push(
|
||||
` unique: TPM2B_PUBLIC_KEY_RSA(${p.unique.modulus.length} bytes)`
|
||||
);
|
||||
} else if (p.type === "TPM_ALG_ECC") {
|
||||
lines.push(
|
||||
` parameters: TPMS_ECC_PARMS { curve: ${p.parameters.curveID}, scheme: ${p.parameters.scheme.scheme}, kdf: ${p.parameters.kdf.scheme} }`
|
||||
);
|
||||
lines.push(
|
||||
` unique: TPMS_ECC_POINT { x: ${p.unique.x.length} bytes, y: ${p.unique.y.length} bytes }`
|
||||
);
|
||||
} else if (p.type === "TPM_ALG_KEYEDHASH") {
|
||||
lines.push(
|
||||
` parameters: TPMS_KEYEDHASH_PARMS { scheme: ${p.parameters.scheme} }`
|
||||
);
|
||||
lines.push(` unique: TPM2B_DIGEST(${p.unique.length} bytes)`);
|
||||
} else {
|
||||
lines.push(
|
||||
` parameters: TPMS_SYMCIPHER_PARMS { algorithm: ${p.parameters.sym.algorithm} }`
|
||||
);
|
||||
lines.push(` unique: TPM2B_DIGEST(${p.unique.length} bytes)`);
|
||||
}
|
||||
lines.push("}");
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function flagSummary(flags: object): string {
|
||||
const enabled = Object.entries(flags)
|
||||
.filter(([, v]) => v === true)
|
||||
.map(([k]) => k);
|
||||
return enabled.length === 0 ? "{}" : `{${enabled.join(", ")}}`;
|
||||
}
|
||||
|
||||
function hex(b: Uint8Array): string {
|
||||
if (b.length === 0) return "0x";
|
||||
let s = "0x";
|
||||
for (let i = 0; i < b.length; i++) {
|
||||
s += (b[i] as number).toString(16).padStart(2, "0");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
Reference in New Issue
Block a user