Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ jobs:
run: |
node --check tools/nitro_attestation_input.js
node --check tools/hinted_attestation_calls.js
node --test tools/p384_hints.test.js
node tools/nitro_attestation_input.js fixture > /dev/null
node tools/hinted_attestation_calls.js fixture > /dev/null
id: tools
Expand Down
18 changes: 12 additions & 6 deletions tools/p384_hints.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const B = hexToBigInt("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5
const GX = hexToBigInt("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7");
const GY = hexToBigInt("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f");
const MASK_256 = (1n << 256n) - 1n;
const MAX_CBOR_NESTING_DEPTH = 128;

if (require.main === module) {
main();
Expand Down Expand Up @@ -612,7 +613,11 @@ function parseAttestationPayload(attestation) {
return result;
}

function readCborItem(bytes, start) {
function readCborItem(bytes, start, depth = 0) {
if (depth > MAX_CBOR_NESTING_DEPTH) {
throw new Error("CBOR nesting depth exceeded");
}

const initial = bytes[start];
if (initial === undefined) {
throw new Error("CBOR read out of bounds");
Expand All @@ -635,12 +640,12 @@ function readCborItem(bytes, start) {
if (end >= bytes.length) {
throw new Error("indefinite CBOR array missing break");
}
end = readCborItem(bytes, end).end;
end = readCborItem(bytes, end, depth + 1).end;
}
end++;
} else {
for (let i = 0n; i < value; ++i) {
end = readCborItem(bytes, end).end;
end = readCborItem(bytes, end, depth + 1).end;
}
}
} else if (major === 5) {
Expand All @@ -650,14 +655,14 @@ function readCborItem(bytes, start) {
if (end >= bytes.length) {
throw new Error("indefinite CBOR map missing break");
}
const key = readCborItem(bytes, end);
const mapValue = readCborItem(bytes, key.end);
const key = readCborItem(bytes, end, depth + 1);
const mapValue = readCborItem(bytes, key.end, depth + 1);
end = mapValue.end;
}
end++;
} else {
for (let i = 0n; i < value * 2n; ++i) {
end = readCborItem(bytes, end).end;
end = readCborItem(bytes, end, depth + 1).end;
}
}
} else if (major === 0 || major === 1 || major === 6 || major === 7) {
Expand Down Expand Up @@ -750,6 +755,7 @@ function hexToBigInt(hex) {
}

module.exports = {
MAX_CBOR_NESTING_DEPTH,
collectAttestationHintBytes,
collectCertSignatureHintBytes,
collectVerifyHintBytes,
Expand Down
26 changes: 26 additions & 0 deletions tools/p384_hints.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use strict";

const assert = require("assert");
const test = require("node:test");

const { MAX_CBOR_NESTING_DEPTH, parseAttestationSignature } = require("./p384_hints");

test("parseAttestationSignature rejects excessive CBOR nesting", () => {
const protectedHeader = Buffer.from([0x44, 0xa1, 0x01, 0x38, 0x22]);
const unprotectedHeaderPrefix = Buffer.from([0xa1, 0x00]);
const nestedArrays = Buffer.alloc(MAX_CBOR_NESTING_DEPTH + 1, 0x81);
const terminalItem = Buffer.from([0x00]);
const attestation = Buffer.concat([
Buffer.from([0x84]),
protectedHeader,
unprotectedHeaderPrefix,
nestedArrays,
terminalItem,
]);

assert.throws(
() => parseAttestationSignature(attestation),
(err) =>
err instanceof Error && !(err instanceof RangeError) && err.message === "CBOR nesting depth exceeded",
);
});
Loading