Files
chimera-Public/test/server/ch-1401-ps5-fpkg-content-auth-trace.test.js

184 lines
9.1 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const test = require('node:test');
const {
classifyPs5FpkgSyslogEvidence,
createPs5FpkgContentAuthTrace,
parseKstuffSemanticSnapshot,
} = require('../../src/services/ps5-fpkg-content-auth-trace');
const OPERATION_ID = '123e4567-e89b-42d3-a456-426614174000';
const REVISION = '3b2ab4a16ba43c8ab38daf7ec83cc297014e0e47';
const PAYLOAD_SHA256 = '1'.repeat(64);
const LOADER_SHA256 = '9'.repeat(64);
const FINGERPRINT = 'a'.repeat(64);
function runtime(overrides = {}) {
return {
product: 'EchoStretch/kstuff-lite', version: '1.10', revision: REVISION,
payloadSha256: PAYLOAD_SHA256, loaderSha256: LOADER_SHA256,
observabilityProfile: 'KSTUFF_OBS-v1.10-semantic-counters',
identityStatus: 'exact', traceEligible: true, firmware: '9.60',
fingerprint: FINGERPRINT,
...overrides,
};
}
function snapshot(sequence, metrics, overrides = {}) {
return { sequence, sampledAt: 1000 + sequence, runtimeFingerprint: FINGERPRINT, metrics, ...overrides };
}
function zeroMetrics() {
return {
nmountArmed: 0, nmountTrap: 0, nmountEmulated: 0, mailboxFpkg: 0,
verifySuperBlockMailbox: 0, verifySuperBlockEmulated: 0,
fakeKeyDerivationCalls: 0, fakeKeyDerivationSuccesses: 0, fakeKeyDerivationFailures: 0, fakeKeyRegisters: 0,
cryptoRequests: 0, cryptoRequestsEmulated: 0, cryptoRequestsFallback: 0, cryptoRequestsFailed: 0,
cryptoHmacMessages: 0, cryptoXtsMessages: 0, cryptoOtherMessages: 0, cryptoEmulatedMessages: 0,
rejectXtsNonFake: 0, rejectHmacNonFake: 0, rejectHmacBadShape: 0, rejectOtherMessage: 0,
requestNoEmulation: 0, requestFpuEnterFail: 0,
};
}
test('A6 network 0x8041013d stays separate from content authentication', () => {
const evidence = classifyPs5FpkgSyslogEvidence([
'[SceShellUI] ResourceArbitrator returned 0x8041013d',
'ERROR: verifyImage(989) ret -1',
'verify error=0xffffffff -> EICV',
'PfsMountGameData_PPR() ret = 0x80020060',
].join('\n'), 'FAKE00000');
assert.equal(evidence.events[0].subsystem, 'network');
assert.equal(evidence.events[0].category, 'connection_refused');
assert.equal(evidence.events[0].causalStatus, 'unknown');
assert.equal(evidence.firstContentAuthFailure.stage, 'verifyImage');
assert.equal(evidence.firstContentAuthFailure.code, 'PS5_FPKG_VERIFY_IMAGE_FAILED');
assert.notEqual(evidence.firstContentAuthFailure.code, 'PS5_FPKG_CONTENT_AUTH_AND_PFS_MOUNT_FAILED');
});
test('A6 parser accepts only the strict semantic-reader schema', () => {
const parsed = parseKstuffSemanticSnapshot([
'schema=chimera.p15-a6-semantic-metrics.v1',
'status=attached',
'sample=7',
'core mailbox_fpkg=4',
'fakekeys reg=2 derive=1 derive_ok=1 derive_fail=0',
'crypto req=3 emu=2 fallback=1 fail=0 xts_msg=1 hmac_msg=1 other_msg=1 emu_msg=2',
'fpkg verify=1 verify_emu=1',
'fpkg_rejects xts_non_fake=0 hmac_non_fake=0 hmac_shape=0 other=1 no_emu=1 fpu_fail=0',
'syscall[nmount] armed=5 trap=1 emu=1',
].join('\n'), { sequence: 7, sampledAt: 1007, runtimeFingerprint: FINGERPRINT });
assert.equal(parsed.metrics.nmountArmed, 5);
assert.equal(parsed.metrics.verifySuperBlockMailbox, 1);
assert.equal(parsed.metrics.cryptoHmacMessages, 1);
assert.equal(parsed.metrics.cryptoXtsMessages, 1);
assert.equal(parsed.metrics.rejectOtherMessage, 1);
});
test('A6 parser rejects unknown lines and extra fields before normalization', () => {
const base = [
'schema=chimera.p15-a6-semantic-metrics.v1',
'status=attached',
'sample=7',
'core mailbox_fpkg=4',
];
for (const unsafe of [
'log-word[0]=0xffff800012345678',
'mailbox-capture[0] request=0x1234 req0=0xdeadbeef',
'core mailbox_fpkg=4 mailbox_unhandled=9',
'fakekeys reg=2 derive=1 derive_ok=1 derive_fail=0 key=forbidden',
'crypto req=3 emu=2 fallback=1 fail=0 xts_msg=1 hmac_msg=1 other_msg=1 emu_msg=2 raw_key=forbidden',
]) {
assert.throws(
() => parseKstuffSemanticSnapshot([...base, unsafe].join('\n'), { sequence: 7, sampledAt: 1007, runtimeFingerprint: FINGERPRINT }),
error => error.code === 'PS5_FPKG_CONTENT_AUTH_TRACE_UNSAFE_LINE',
);
}
});
test('A6 launch delta excludes stale counters and preserves zero versus nonzero', () => {
const pre = snapshot(10, {
nmountArmed: 32, nmountTrap: 4, nmountEmulated: 4, mailboxFpkg: 8,
verifySuperBlockMailbox: 5, verifySuperBlockEmulated: 5,
fakeKeyDerivationCalls: 5, fakeKeyDerivationSuccesses: 5, fakeKeyDerivationFailures: 0, fakeKeyRegisters: 10,
cryptoRequests: 20, cryptoRequestsEmulated: 20, cryptoRequestsFallback: 0, cryptoRequestsFailed: 0,
cryptoHmacMessages: 10, cryptoXtsMessages: 10, cryptoOtherMessages: 0, cryptoEmulatedMessages: 20,
rejectXtsNonFake: 0, rejectHmacNonFake: 0, rejectHmacBadShape: 0, rejectOtherMessage: 0, requestNoEmulation: 0, requestFpuEnterFail: 0,
});
const post = snapshot(11, { ...pre.metrics, nmountArmed: 33 });
const trace = createPs5FpkgContentAuthTrace({
operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime(), pre, post,
syslog: 'verifyImage ret -1\nEICV\nPfsMountGameData_PPR() ret = 0x80020060',
});
assert.equal(trace.delta.nmountArmed, 1);
assert.equal(trace.delta.verifySuperBlockMailbox, 0);
assert.equal(trace.verifySuperBlock.reached, false);
assert.equal(trace.fakeKey.derivationAttempted, false);
assert.equal(trace.crypto.requests, 0);
assert.equal(trace.firstFailedStage, 'verify_superblock_mailbox_not_reached');
assert.equal(trace.decisionCase, 'A');
assert.equal(trace.productionRestorable, false);
});
test('A6 trace retains unknown values as null and rejects counter reset', () => {
const pre = snapshot(10, { nmountArmed: 4, nmountTrap: null });
const post = snapshot(11, { nmountArmed: 3, nmountTrap: null });
const trace = createPs5FpkgContentAuthTrace({ operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime(), pre, post, syslog: '' });
assert.equal(trace.delta.nmountArmed, null);
assert.equal(trace.delta.nmountTrap, null);
assert.equal(trace.metricContinuity, 'counter-reset-or-drift');
assert.equal(trace.status, 'outcome_unknown');
assert.equal(trace.verifyImage.reached, null);
assert.equal(trace.firstFailedStage, 'unknown');
});
test('A6 fake-key and crypto outcomes are semantic only', () => {
const pre = snapshot(1, zeroMetrics());
const post = snapshot(2, {
nmountArmed: 1, nmountTrap: 1, nmountEmulated: 1, mailboxFpkg: 1,
verifySuperBlockMailbox: 1, verifySuperBlockEmulated: 1,
fakeKeyDerivationCalls: 1, fakeKeyDerivationSuccesses: 1, fakeKeyDerivationFailures: 0, fakeKeyRegisters: 2,
cryptoRequests: 2, cryptoRequestsEmulated: 1, cryptoRequestsFallback: 1, cryptoRequestsFailed: 0,
cryptoHmacMessages: 1, cryptoXtsMessages: 1, cryptoOtherMessages: 0, cryptoEmulatedMessages: 1,
rejectXtsNonFake: 1, rejectHmacNonFake: 0, rejectHmacBadShape: 0, rejectOtherMessage: 0, requestNoEmulation: 1, requestFpuEnterFail: 0,
});
const trace = createPs5FpkgContentAuthTrace({ operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime(), pre, post, syslog: 'verifyImage ret -1\nEICV\nPFS mount 0x80020060' });
assert.equal(trace.fakeKey.derivationSucceeded, true);
assert.equal(trace.fakeKey.encryptionHandleValid, true);
assert.equal(trace.fakeKey.signingHandleValid, true);
assert.equal(trace.crypto.hmac, 1);
assert.equal(trace.crypto.xts, 1);
assert.equal(trace.crypto.fallback, 1);
assert.equal(trace.crypto.rejections.xtsNonFake, 1);
assert.equal(trace.firstFailedStage, 'crypto_request_rejected_or_not_emulated');
const serialized = JSON.stringify(trace);
for (const forbidden of ['keyBytes', 'eekpfs', 'ekpfs', 'dmem', 'mailboxBuffer']) assert.doesNotMatch(serialized, new RegExp(forbidden, 'i'));
});
test('A6 runtime revision and hashes are mandatory and snapshots bind to it', () => {
const pre = snapshot(1, {}); const post = snapshot(2, {});
assert.throws(
() => createPs5FpkgContentAuthTrace({ operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime({ identityStatus: 'unproven' }), pre, post, syslog: '' }),
error => error.code === 'PS5_FPKG_KSTUFF_RUNTIME_IDENTITY_UNPROVEN',
);
assert.throws(
() => createPs5FpkgContentAuthTrace({ operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime({ traceEligible: false }), pre, post, syslog: '' }),
error => error.code === 'PS5_FPKG_KSTUFF_RUNTIME_IDENTITY_UNPROVEN',
);
assert.throws(
() => createPs5FpkgContentAuthTrace({ operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime(), pre, post: { ...post, runtimeFingerprint: 'b'.repeat(64) }, syslog: '' }),
error => error.code === 'PS5_FPKG_CONTENT_AUTH_TRACE_RUNTIME_DRIFT',
);
});
test('A6 diagnostic profile remains distinct and interrupted result is outcome_unknown', () => {
const trace = createPs5FpkgContentAuthTrace({
operationId: OPERATION_ID, titleId: 'FAKE00000', runtime: runtime({ observabilityProfile: 'chimera-p15-fpkg-observe-v1' }),
pre: snapshot(1, {}), post: null, syslog: '', interrupted: true,
});
assert.equal(trace.status, 'outcome_unknown');
assert.equal(trace.runtime.observabilityProfile, 'chimera-p15-fpkg-observe-v1');
assert.equal(trace.launchRequests, 1);
assert.equal(trace.productionRestorable, false);
});