Some checks failed
CI / lint (push) Successful in 1m37s
CI / test-python (push) Successful in 1m49s
CI / test-zig (push) Successful in 1m39s
CI / test-wasm (push) Successful in 1m54s
CI / test (push) Successful in 14m44s
CI / miri (push) Successful in 14m18s
CI / build (push) Successful in 1m9s
CI / fuzz-regression (push) Successful in 9m9s
CI / publish (push) Failing after 1m10s
CI / publish-python (push) Failing after 1m46s
CI / publish-wasm (push) Has been cancelled
Signed-off-by: Kamal Tufekcic <kamal@lo.sh>
101 lines
3.4 KiB
Rust
101 lines
3.4 KiB
Rust
#![no_main]
|
|
use libfuzzer_sys::fuzz_target;
|
|
use soliton::{
|
|
identity::{generate_identity, GeneratedIdentity, HybridSignature, IdentityPublicKey, IdentitySecretKey},
|
|
kex::{receive_session, SessionInit},
|
|
primitives::xwing,
|
|
};
|
|
use std::sync::LazyLock;
|
|
|
|
struct BobKeys {
|
|
ik_pk: IdentityPublicKey,
|
|
ik_sk: IdentitySecretKey,
|
|
spk_sk: xwing::SecretKey,
|
|
}
|
|
|
|
// Fixed Bob identity + SPK keypair — keygen is expensive, amortise across runs.
|
|
static BOB: LazyLock<BobKeys> = LazyLock::new(|| {
|
|
let GeneratedIdentity { public_key: ik_pk, secret_key: ik_sk, .. } = generate_identity().unwrap();
|
|
let (_spk_pk, spk_sk) = xwing::keygen().unwrap();
|
|
BobKeys { ik_pk, ik_sk, spk_sk }
|
|
});
|
|
|
|
// Fixed Alice identity (the "known sender" Bob trusts).
|
|
static ALICE_PK: LazyLock<IdentityPublicKey> = LazyLock::new(|| generate_identity().unwrap().public_key);
|
|
|
|
const SIG: usize = 3373;
|
|
const FP: usize = 32;
|
|
const XPK: usize = 1216;
|
|
const XCT: usize = 1120;
|
|
|
|
// Wire layout:
|
|
// sig (3373) | sender_fp (32) | recipient_fp (32) | sender_ek (1216)
|
|
// | ct_ik (1120) | ct_spk (1120) | spk_id (4 BE) | has_opk (1)
|
|
// | [ct_opk (1120) | opk_id (4 BE)] ← only if has_opk & 0x01
|
|
// | crypto_version (rest, strict UTF-8; bail if invalid)
|
|
const MIN: usize = SIG + FP + FP + XPK + XCT + XCT + 4 + 1;
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
if data.len() < MIN {
|
|
return;
|
|
}
|
|
let mut off = 0;
|
|
|
|
let Ok(sig) = HybridSignature::from_bytes(data[off..off + SIG].to_vec()) else { return; };
|
|
off += SIG;
|
|
|
|
let sender_ik_fingerprint: [u8; FP] = data[off..off + FP].try_into().unwrap();
|
|
off += FP;
|
|
let recipient_ik_fingerprint: [u8; FP] = data[off..off + FP].try_into().unwrap();
|
|
off += FP;
|
|
|
|
let Ok(sender_ek) = xwing::PublicKey::from_bytes(data[off..off + XPK].to_vec()) else { return; };
|
|
off += XPK;
|
|
|
|
let Ok(ct_ik) = xwing::Ciphertext::from_bytes(data[off..off + XCT].to_vec()) else { return; };
|
|
off += XCT;
|
|
let Ok(ct_spk) = xwing::Ciphertext::from_bytes(data[off..off + XCT].to_vec()) else { return; };
|
|
off += XCT;
|
|
|
|
let spk_id = u32::from_be_bytes(data[off..off + 4].try_into().unwrap());
|
|
off += 4;
|
|
|
|
let has_opk = data[off] & 0x01 != 0;
|
|
off += 1;
|
|
|
|
let (ct_opk, opk_id) = if has_opk {
|
|
if data.len() < off + XCT + 4 {
|
|
return;
|
|
}
|
|
let Ok(ct) = xwing::Ciphertext::from_bytes(data[off..off + XCT].to_vec()) else { return; };
|
|
off += XCT;
|
|
let id = u32::from_be_bytes(data[off..off + 4].try_into().unwrap());
|
|
off += 4;
|
|
(Some(ct), Some(id))
|
|
} else {
|
|
(None, None)
|
|
};
|
|
|
|
// Use strict from_utf8 to match decode_session_init, which rejects
|
|
// non-UTF-8 bytes with Error::InvalidData. Lossy decoding would allow
|
|
// replacement-character strings that can never reach receive_session in
|
|
// real protocol flow (the wire parser rejects them first).
|
|
let Ok(crypto_version) = String::from_utf8(data[off..].to_vec()) else { return; };
|
|
|
|
let si = SessionInit {
|
|
crypto_version,
|
|
sender_ik_fingerprint,
|
|
recipient_ik_fingerprint,
|
|
sender_ek,
|
|
ct_ik,
|
|
ct_spk,
|
|
spk_id,
|
|
ct_opk,
|
|
opk_id,
|
|
};
|
|
|
|
// receive_session must never panic regardless of input.
|
|
// Exercises: crypto_version check, fingerprint checks, hybrid signature
|
|
// verification, KEM decapsulation, HKDF, and rollback on failure.
|
|
let _ = receive_session(&BOB.ik_pk, &BOB.ik_sk, &ALICE_PK, &si, &sig, &BOB.spk_sk, None);
|
|
});
|