blob: 4519a9619d17e1868c1fa77624d8f1b469d8a895 [file] [edit]
<!doctype html><!-- webkit-test-runner [ IPCTestingAPIEnabled=true IgnoreInvalidMessageWhenIPCTestingAPIEnabled=true ] -->
<html>
<head>
<script>
// CoreIPCSecTrust::createSecTrust() turns the decoded CoreIPCSecTrustData back into the
// property list that SecTrustCreateFromPropertyListRepresentation() expects. A CoreIPCData
// decoded from a disengaged std::optional<std::span<const uint8_t>> has no bytes, so its
// toID() is nil, and inserting nil into an NSMutableDictionary raises an uncaught
// NSInvalidArgumentException. Every field below is attacker controlled, so the receiving
// process has to reject such a trust object instead of crashing.
const nullData = { dataReference: { } };
function secTrustData(overrides)
{
return Object.assign({
result: 0,
anchorsOnly: false,
keychainsAllowed: false,
certificates: [],
chain: [],
details: [],
policies: [],
info: { },
verifyDate: { },
responses: { },
scts: { },
anchors: { },
trustedLogs: { },
exceptions: { },
}, overrides);
}
// Each entry puts a null CoreIPCData at a different spot in the trust data.
const cases = [
{ certificates: [nullData] },
{ chain: [nullData] },
{ policies: [{ alias: [
[{ m_string: 'policy' }, { alias: { variantType: 'WebKit::CoreIPCSecTrustData::PolicyOption', variant: { alias: [
[{ m_string: 'data' }, { alias: { variantType: 'WebKit::CoreIPCSecTrustData::PolicyArrayOfData', variant: { alias: [nullData] } } }],
] } } }],
] }] },
{ info: { optionalValue: { alias: [
[{ m_string: 'revocation' }, { alias: { variantType: 'WebKit::CoreIPCSecTrustData::RevocationInfoArray', variant: { alias: [
{ alias: [
[{ m_string: 'entry' }, { alias: [
[{ m_string: 'value' }, { alias: { variantType: 'WebKit::CoreIPCData', variant: nullData } }],
] }],
] },
] } } }],
] } } },
{ responses: { optionalValue: [nullData] } },
{ scts: { optionalValue: [nullData] } },
{ anchors: { optionalValue: [nullData] } },
{ trustedLogs: { optionalValue: [nullData] } },
{ exceptions: { optionalValue: [{ alias: [
[{ m_string: 'exception' }, { variantType: 'WebKit::CoreIPCData', variant: nullData }],
] }] } },
];
async function runTest()
{
if (window.testRunner)
testRunner.dumpAsText();
if (!window.IPC) {
result.textContent = window.testRunner ? 'PASS' : 'This test requires IPC testing API';
return;
}
if (window.testRunner)
testRunner.waitUntilDone();
const { CoreIPC, IPCWireTap } = await import('../coreipc.js');
// Registering an outgoing message listener makes WebKit decode each message we send
// with the real argument coders, so CoreIPCSecTrust::createSecTrust() runs over this
// attacker controlled data exactly as it would in the receiving process.
const uiOutgoingTap = new IPCWireTap('UI', 'Outgoing');
for (const overrides of cases) {
CoreIPC.UI.WebInspectorUIProxy.ShowCertificate(IPC.pageID, { certificateInfo: { trust: { optionalValue: {
m_data: { optionalValue: secTrustData(overrides) },
} } } });
}
// The decoding above happens on a later run loop turn, so give it a chance to run
// before declaring the test finished.
setTimeout(() => {
result.textContent = 'PASS';
if (window.testRunner)
testRunner.notifyDone();
}, 500);
}
</script>
</head>
<body onload="runTest()">
This test passes if WebKit does not crash.
<div id="result"></div>
</body>
</html>