Read Idunn identity envelope format
This commit is contained in:
parent
5697802dbf
commit
5dd25718af
2 changed files with 34 additions and 7 deletions
|
|
@ -543,8 +543,7 @@ function decodeRoute(value: unknown): ExpectedIncarnation["route"] {
|
|||
}
|
||||
|
||||
function openProviderHealthIdentity(credentialBytes: Buffer): crypto.KeyObject {
|
||||
const record = readAuthorityRecordBytes(credentialBytes, "gamecult.provider_health_identity", "gamecult.provider_health_identity.private.v1");
|
||||
const fields = decodeArray(record, 10, "provider-health identity");
|
||||
const fields = decodeArray(readProviderHealthIdentityCredential(credentialBytes), 10, "provider-health identity");
|
||||
const [schema, identityId, publicKeyValue, protectedSeedValue, protectorKind, binding, version, assurance, createdAt, enrollmentNonceValue] = fields;
|
||||
if (schema !== "gamecult.provider_health_identity.private.v1" || version !== "v1") throw new Error("Provider-health identity schema is unsupported.");
|
||||
string(createdAt, "Provider-health identity creation time");
|
||||
|
|
@ -573,6 +572,21 @@ function openProviderHealthIdentity(credentialBytes: Buffer): crypto.KeyObject {
|
|||
return key;
|
||||
}
|
||||
|
||||
function readProviderHealthIdentityCredential(bytes: Buffer): Uint8Array {
|
||||
const decoded = decode(bytes);
|
||||
if (!Array.isArray(decoded) || decoded.length !== 1) {
|
||||
throw new Error("Provider-health identity credential must contain exactly one envelope.");
|
||||
}
|
||||
const envelope = array(decoded[0], 5, "Provider-health identity envelope");
|
||||
if (envelope[0] !== "gamecult-provider-health-identity"
|
||||
|| envelope[1] !== "gamecult.provider_health_identity.private.v1"
|
||||
|| envelope[4] !== "gamecult.provider_health_identity.private.v1") {
|
||||
throw new Error("Provider-health identity credential belongs to a different profile or schema.");
|
||||
}
|
||||
string(envelope[3], "Provider-health identity stored-at time");
|
||||
return bytesValue(envelope[2], "Provider-health identity payload");
|
||||
}
|
||||
|
||||
function readAuthorityRecordBytes(bytes: Buffer, type: string, schemaId: string): Uint8Array {
|
||||
const decoded = decode(bytes);
|
||||
if (!Array.isArray(decoded) || decoded[0] !== CULTCACHE_STORE_FORMAT || !Array.isArray(decoded[1]) || !Array.isArray(decoded[2])) {
|
||||
|
|
|
|||
|
|
@ -78,14 +78,18 @@ test("opens Idunn's machine-bound identity and signs the exact Expected incarnat
|
|||
Buffer.from(binding, "utf8"),
|
||||
])).digest();
|
||||
const protectedSeed = Buffer.from(providerSeed.map((value, index) => value ^ mask[index]!));
|
||||
const providerCredential = cultCacheStore(
|
||||
"gamecult.provider_health_identity", "gamecult.provider_health_identity.private.v1",
|
||||
"gamecult-provider-health-identity", Buffer.from(encode([
|
||||
const providerCredential = Buffer.from(encode([[
|
||||
"gamecult-provider-health-identity",
|
||||
"gamecult.provider_health_identity.private.v1",
|
||||
Buffer.from(encode([
|
||||
"gamecult.provider_health_identity.private.v1", providerIdentity, providerPublic, protectedSeed,
|
||||
"linux_file_mode_machine_id_binding", binding, "v1", "os_installation_file_bound_cloneable_baseline",
|
||||
"2026-01-01T00:00:00Z", new Uint8Array(32).fill(0x2a),
|
||||
])),
|
||||
);
|
||||
"2026-01-01T00:00:00Z",
|
||||
"gamecult.provider_health_identity.private.v1",
|
||||
]]));
|
||||
let descriptorProviderCredential = providerCredential;
|
||||
|
||||
const originalEnvironment = { ...process.env };
|
||||
context.after(() => {
|
||||
|
|
@ -101,7 +105,7 @@ test("opens Idunn's machine-bound identity and signs the exact Expected incarnat
|
|||
const realReadFileSync = fs.readFileSync.bind(fs);
|
||||
mock.method(fs, "readFileSync", (filePath: fs.PathOrFileDescriptor, ...args: unknown[]) => {
|
||||
if (filePath === 3) return activationSeed;
|
||||
if (filePath === 4) return providerCredential;
|
||||
if (filePath === 4) return descriptorProviderCredential;
|
||||
if (filePath === "/etc/machine-id") return machineId;
|
||||
return realReadFileSync(filePath as never, ...args as never[]);
|
||||
});
|
||||
|
|
@ -121,6 +125,15 @@ test("opens Idunn's machine-bound identity and signs the exact Expected incarnat
|
|||
const signedRecord = decode(signed.payload) as unknown[];
|
||||
assert.equal(crypto.verify(null, runtimePresenceProviderSigningMessage(proof), crypto.createPublicKey(providerKey), Buffer.from(signedRecord[21] as Uint8Array)), true);
|
||||
assert.equal(crypto.verify(null, runtimePresenceActivationSigningMessage(proof), crypto.createPublicKey(activationKey), Buffer.from(signedRecord[23] as Uint8Array)), true);
|
||||
|
||||
descriptorProviderCredential = Buffer.from(encode([
|
||||
...(decode(providerCredential) as unknown[][]),
|
||||
...(decode(providerCredential) as unknown[][]),
|
||||
]));
|
||||
assert.throws(
|
||||
() => loadIdunnRuntimeAuthorityFromEnvironment(target, contract, "127.0.0.1:17871"),
|
||||
/exactly one envelope/,
|
||||
);
|
||||
});
|
||||
|
||||
function cultCacheStore(type: string, schemaId: string, key: string, payload: Uint8Array): Buffer {
|
||||
|
|
|
|||
Loading…
Reference in a new issue