Repository: google/OpenSK
File: fuzz/fuzz_targets/fuzz_target_split_assemble.rs (Rust)

Code before:
extern crate arrayref;

use libfuzzer_sys::fuzz_target;
use ctap2::ctap::hid::receive::MessageAssembler;
use ctap2::ctap::hid::send::HidPacketIterator;
use ctap2::ctap::hid::{Message, HidPacket};
use libtock_drivers::timer::Timestamp;

const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
const PACKET_TYPE_MASK: u8 = 0x80;

// Converts a byte slice into Message
fn raw_to_message(data: &[u8], len: usize) -> Message{
    if len <= 4 {
        let mut cid = [0;4];
        cid[..len].copy_from_slice(data);
        Message{
            cid,
            cmd: 0,
            payload: vec![],
        }
    }
    else if len == 5{
        Message{
            cid: array_ref!(data,0,4).clone(),
            cmd: data[4],
            payload: vec![],
        }
    }
    else{
        Message {
            cid: array_ref!(data,0,4).clone(),
            cmd: data[4],
            payload: data[5..].to_vec(),
        }
    }
}

/* Fuzzing HID packets splitting and assembling functions*/
fuzz_target!(|data: &[u8]| {
    let Message{cid, mut cmd, payload} = raw_to_message(data, data.len());
    if let Some(hid_packet_iterator) = HidPacketIterator::new(Message{cid,cmd,payload:payload.clone()}){
        let packets: Vec<HidPacket> = hid_packet_iterator.collect();
        let mut assembler = MessageAssembler::new();
        for (i, packet) in packets.iter().enumerate(){
            if i != packets.len() - 1 {
                assert_eq!(
                    assembler.parse_packet(packet, DUMMY_TIMESTAMP),
                    Ok(None)
                );
            }

Review comment (suggestion):
[Documentation](https://doc.rust-lang.org/std/slice/trait.SliceIndex.html#panics) says you get an empty `Vec` if you start indexing from `len`. So you can remove the middle case.

Code after:
extern crate arrayref;

use ctap2::ctap::hid::receive::MessageAssembler;
use ctap2::ctap::hid::send::HidPacketIterator;
use ctap2::ctap::hid::{HidPacket, Message};
use libfuzzer_sys::fuzz_target;
use libtock_drivers::timer::Timestamp;

const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
const PACKET_TYPE_MASK: u8 = 0x80;

// Converts a byte slice into Message
fn raw_to_message(data: &[u8]) -> Message {
    if data.len() <= 4 {
        let mut cid = [0; 4];
        cid[..data.len()].copy_from_slice(data);
        Message {
            cid,
            cmd: 0,
            payload: vec![],
        }
    } else {
        Message {
            cid: array_ref!(data, 0, 4).clone(),
            cmd: data[4],
            payload: data[5..].to_vec(),
        }
    }
}

/* Fuzzing HID packets splitting and assembling functions*/
fuzz_target!(|data: &[u8]| {
    let mut message = raw_to_message(data);
    if let Some(hid_packet_iterator) = HidPacketIterator::new(message.clone()) {
        let mut assembler = MessageAssembler::new();
        let packets: Vec<HidPacket> = hid_packet_iterator.collect();
        if let Some((last_packet, first_packets)) = packets.split_last() {
            for packet in first_packets {
                assert_eq!(assembler.parse_packet(packet, DUMMY_TIMESTAMP), Ok(None));
            }
            message.cmd &= !PACKET_TYPE_MASK;
            assert_eq!(
                assembler.parse_packet(last_packet, DUMMY_TIMESTAMP),
                Ok(Some(message))
            );
        }
    }
});