[test] add fuzz targets for tbor part init/final commands - #662
[test] add fuzz targets for tbor part init/final commands#662David Zimmermann (zimmy87) wants to merge 12 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds new cargo-fuzz targets under fuzz/ intended to exercise the TBOR PartInit and PartFinal request paths in the DDI TBOR stack.
Changes:
- Introduces
fuzz_tbor_part_initandfuzz_tbor_part_finalfuzz binaries. - Adds a direct
zerocopydependency for decodingCertDescriptorbytes in thePartFinalfuzz target. - Registers the new fuzz targets in
fuzz/Cargo.toml.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs | New fuzz target that opens a session and issues TborPartInitReq with fuzzed inputs. |
| fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_final.rs | New fuzz target that opens a session and issues TborPartFinalReq using fuzzed descriptor bytes and backup buffer. |
| fuzz/Cargo.toml | Adds zerocopy dependency and registers the two new fuzz binaries. |
Suppressed comments (1)
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs:48
- After adding
sapota_present, use it to encode the optional SAPOTA thumbprint as empty when absent (the on-wire convention for this field).
pota_thumbprint: input.pota_thumbprint,
sata_thumbprint: input.sata_thumbprint,
sapota_thumbprint: input.sapota_thumbprint.to_vec(),
};
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs:50
sapota_presentis currently unused and the request always includes a 48-bytesapota_thumbprint, so the fuzz target never exercises the "absent" (empty) case described in the input docs. Buildsapota_thumbprintconditionally and pass an emptyVecwhensapota_presentis false.
let part_init_req = TborPartInitReq {
session_id: session.session_id(),
mach_seed_envelope: input.mach_seed_envelope.to_vec(),
part_policy: PartPolicy::zeroed(),
pota_thumbprint: input.pota_thumbprint,
sata_thumbprint: input.sata_thumbprint,
sapota_thumbprint: input.sapota_thumbprint.to_vec(),
};
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
fuzz/Cargo.toml:20
zerocopyis added as a direct dependency but isn’t used anywhere in the fuzz crate, so it increases build time / dependency surface unnecessarily. If it’s not needed for these targets, drop it; otherwise, please add the corresponding usage so the dependency is justified.
zerocopy = { version = "0.8.17" }
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs:32
sapota_present+sapota_thumbprintalways consumesSAPOTA_THUMBPRINT_LENbytes even when the thumbprint is absent, which reduces effective fuzz input for the rest of the request. UsingOption<[u8; SAPOTA_THUMBPRINT_LEN]>makes absence explicit and avoids consuming those bytes when not needed.
/// Whether to include a SAPOTA thumbprint (empty = absent).
sapota_present: bool,
/// Fixed-length fuzzed SAPOTA thumbprint (used when `sapota_present`).
sapota_thumbprint: [u8; SAPOTA_THUMBPRINT_LEN],
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (6)
Previously missed (3) — in code that hasn't changed since the last review.
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs:42
PartInitrequests are behind the dispatcher’s default-PSK gate; afterctx.erase()the CO PSK is default, so this target will consistently getDefaultPskMustRotateand never reach thePartInithandler. Rotate the CO PSK first, then open the CO session using the rotated PSK bytes.
let session = ctx
.open_session(CO, SessionType::Authenticated)
.expect("session open should succeed");
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs:56
PartPolicy::zeroed()produces an invalid policy forPartInit(version.major=0 and required POTA/SATA keys have len=0). The firmware-side policy parser rejects this withInvalidArgbefore any crypto work, so the target won’t meaningfully exercisePartInit. Build a minimally-valid policy (major=1 and required Ecc384 keys populated).
let part_init_req = TborPartInitReq {
session_id: session.session_id(),
mach_seed_envelope: input.mach_seed_envelope.to_vec(),
part_policy: PartPolicy::zeroed(),
pota_thumbprint: input.pota_thumbprint,
sata_thumbprint: input.sata_thumbprint,
sapota_thumbprint,
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_final.rs:30
- This fuzz target generates a fresh POTA CA key on every iteration (
CaKey::generate()), introducing per-run nondeterminism and extra overhead that can reduce fuzzing effectiveness. Cache the generated CA key in aOnceLockso the target is stable and faster.
This issue also appears in the following locations of the same file:
- line 114
- line 126
static CTX: std::sync::OnceLock<TestCtx> = std::sync::OnceLock::new();
fuzz/Cargo.toml:20
zerocopyis added as a direct dependency of the fuzz crate but is not used anywhere underfuzz/in this PR. Keeping unused direct dependencies increases build time and maintenance surface; please remove it unless a follow-up change will use it here.
zerocopy = { version = "0.8.17" }
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_final.rs:117
- Use the cached POTA CA key instead of generating a new one each iteration (and avoid taking a reference to the temporary returned by
raw_pub()).
// Generate a POTA trust anchor and embed its public key in the policy.
let pota = CaKey::generate();
let policy = part_policy_with_pota(&pota.raw_pub());
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_final.rs:126
- After switching
potato a cached reference, this call should passpotadirectly (not&pota) to avoid an&&CaKeytype mismatch.
let chain = make_pta_chain(&pota, &pta_pub);
…idz/add_tbor_part_fuzz
d956de0 to
4b0d1da
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
fuzz/Cargo.toml:21
zerocopyis added as a direct dependency here but is not used anywhere underfuzz/(only referenced in this Cargo.toml). This adds unnecessary build/dependency surface for the fuzz crate; please remove it unless a follow-up change will use it directly.
], path = "../crates/tbor_test_harness" }
azihsm_ddi_tbor_types = { path = "../ddi/tbor/types" }
zerocopy = { version = "0.8.17" }
| let ctx = CTX.get_or_init(TestCtx::new); | ||
| ctx.erase().expect("erase should succeed"); | ||
|
|
||
| let session = ctx | ||
| .open_session(CO, SessionType::Authenticated) | ||
| .expect("session open should succeed"); | ||
|
|
||
| let sapota_thumbprint = if input.sapota_present { | ||
| input.sapota_thumbprint.to_vec() | ||
| } else { | ||
| Vec::new() | ||
| }; | ||
|
|
||
| let part_init_req = TborPartInitReq { | ||
| session_id: session.session_id(), | ||
| mach_seed_envelope: input.mach_seed_envelope.to_vec(), | ||
| part_policy: PartPolicy::zeroed(), | ||
| pota_thumbprint: input.pota_thumbprint, | ||
| sata_thumbprint: input.sata_thumbprint, | ||
| sapota_thumbprint, | ||
| }; | ||
| let _ = ctx.tbor(&part_init_req); | ||
|
|
||
| session.close().expect("session close should succeed"); | ||
| }); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
4b0d1da to
d28d2c3
Compare
…/Azure/azihsm-sdk into user/v-davidz/add_tbor_part_fuzz
There was a problem hiding this comment.
🔵 Needs a closer look
The PartInit fuzz target currently won’t reach intended handler logic due to the default-PSK gate/invalid policy setup, and an unused direct dependency was added.
Review details
Suppressed comments (2)
fuzz/fuzz_targets/ddi/tbor/fuzz_tbor_part_init.rs:40
PartInitis gated by the dispatcher when the CO session is still using the default PSK (seeddi/tbor/types/tests/commands/part_init/fw_rejects.rs:196..210). In this fuzz target, the session is opened under the default CO PSK and the request usesPartPolicy::zeroed()(policy major=0), so the request will almost always be rejected before it reaches themach_seed_envelopehandler logic you’re trying to fuzz.
Rotate the CO PSK first, open the session under the rotated PSK, and supply a minimally valid policy (version major=1 with non-empty POTA/SATA pubkey slots) so fuzzing can reach the envelope-decrypt/validation paths.
let ctx = CTX.get_or_init(TestCtx::new);
ctx.erase().expect("erase should succeed");
let session = ctx
.open_session(CO, SessionType::Authenticated)
fuzz/Cargo.toml:20
zerocopyis added as a direct dependency of thefuzzcrate but isn’t referenced by any fuzz target in this PR (andPartPolicy::zeroed()is an inherent method, not azerocopytrait method). Keeping an unused direct dependency increases compile time and dependency surface for fuzz builds.
zerocopy = { version = "0.8.17" }
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Lite
No description provided.