Repository: google/OpenSK
File: fuzz/fuzz_helper/src/lib.rs (Rust)

Code before:
fn is_type(data: &[u8], input_type: InputType) -> bool {
    if input_type.clone() == InputType::Ctap1 {
        return true;
    }
    match cbor::read(data) {
        Err(_) => false,
        Ok(decoded_cbor) => match input_type {
            InputType::CborMakeCredentialParameter => {
                AuthenticatorMakeCredentialParameters::try_from(decoded_cbor).is_ok()
            }
            InputType::CborGetAssertionParameter => {
                AuthenticatorGetAssertionParameters::try_from(decoded_cbor).is_ok()
            }
            InputType::CborClientPinParameter => {
                AuthenticatorClientPinParameters::try_from(decoded_cbor).is_ok()
            }
            _ => true,
        },
    }
}

// Interprets the raw data as of the given input type and
// invokes message splitting, assembling and packet processing at CTAP HID level.
pub fn process_input(data: &[u8], input_type: InputType) {
    if !is_type(data, input_type.clone()) {
        return ();
    }
    // Initialize ctap state and hid and get the allocated cid.
    let mut rng = ThreadRng256 {};
    let user_immediately_present = |_| Ok(());
    let mut ctap_state = CtapState::new(&mut rng, user_immediately_present);
    let mut ctap_hid = CtapHid::new();
    let cid = initialize(&mut ctap_state, &mut ctap_hid);
    // Wrap input as message with allocated cid and command type.
    let mut command = cid.to_vec();
    match input_type {
        InputType::CborMakeCredentialParameter => {
            command.extend(&[0x10, 0x01]);
        }
        InputType::CborGetAssertionParameter => {
            command.extend(&[0x10, 0x02]);
        }
        InputType::CborClientPinParameter => {
            command.extend(&[0x10, 0x06]);
        }
        InputType::Ctap1 => {
            command.extend(&[0x03]);
        }
    }
    command.extend(data);
    // Process message at HID level.

Review comment (performance):
Seems inefficient to throw away so many inputs. How slow is this fuzzer, and do you need to hand it some working examples?

Also, it seems splitting the fuzzing into three targets like that may benefit the corpus generation for the other tool, but not really necessary for OpenSK's sake. Is that correct? If so, it should at least be documented.

Code after:
    result_cid
}

// Checks whether the given data can be interpreted as the given type.
fn is_type(data: &[u8], input_type: InputType) -> bool {
    if input_type == InputType::Ctap1 {
        return true;
    }
    match cbor::read(data) {
        Err(_) => false,
        Ok(decoded_cbor) => match input_type {
            InputType::CborMakeCredentialParameter => {
                AuthenticatorMakeCredentialParameters::try_from(decoded_cbor).is_ok()
            }
            InputType::CborGetAssertionParameter => {
                AuthenticatorGetAssertionParameters::try_from(decoded_cbor).is_ok()
            }
            InputType::CborClientPinParameter => {
                AuthenticatorClientPinParameters::try_from(decoded_cbor).is_ok()
            }
            _ => true,
        },
    }
}

// Interprets the raw data as a complete message (with channel id, command type and payload) and
// invokes message splitting, packet processing at CTAP HID level and response assembling.
fn process_message<CheckUserPresence>(
    data: &[u8],
    ctap_state: &mut CtapState<ThreadRng256, CheckUserPresence>,
    ctap_hid: &mut CtapHid,
) where
    CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
{
    let message = raw_to_message(data);
    if let Some(hid_packet_iterator) = HidPacketIterator::new(message) {
        let mut assembler_reply = MessageAssembler::new();
        for pkt_request in hid_packet_iterator {
            for pkt_reply in
                ctap_hid.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE, ctap_state)
            {
                // Only checks for assembling crashes, not for semantics.
                let _ = assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP);
            }
        }
    }
}

// Interprets the raw data as any ctap command (including the command byte) and
// invokes message splitting, packet processing at CTAP HID level and response assembling
// using an initialized and allocated channel.