Repository: google/OpenSK
File: src/ctap/apdu.rs (Rust)

Code before:
                // Lc is possibly three-bytes long
                let extended_apdu_lc: usize = BigEndian::read_u16(&payload[1..]) as usize;
                let extended_apdu_le_len: usize = if payload.len() > extended_apdu_lc {
                    payload.len() - extended_apdu_lc - 3
                } else {
                    0
                };
                if byte_0 == 0 && extended_apdu_le_len <= 3 {
                    // If first byte is zero AND the next two bytes can be parsed as a big-endian
                    // length that covers the rest of the block (plus few additional bytes for Le), we
                    // have an extended-length APDU
                    apdu.case_type = ApduType::Extended(match extended_apdu_le_len {
                        0 => Case::Lc3Data,
                        1 => Case::Lc3DataLe1,
                        2 => Case::Lc3DataLe2,
                        3 => Case::Lc3DataLe3,
                        _ => Case::Unknown,
                    });
                    apdu.data = payload[3..(payload.len() - extended_apdu_le_len)].to_vec();
                    apdu.lc = extended_apdu_lc as u16;
                    apdu.le = match extended_apdu_le_len {
                        0 => 0,
                        1 => (*payload.last().unwrap()).into(),
                        2 => BigEndian::read_u16(&payload[payload.len() - extended_apdu_le_len..])
                            as u32,
                        3 => BigEndian::read_u32(&payload[payload.len() - extended_apdu_le_len..]),
                        _ => 0,
                    }
                }
            }
        }
        if apdu.case_type == ApduType::default() {
            return Err(ApduStatusCode::SW_COND_USE_NOT_SATISFIED);
        }
        Ok(apdu)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    fn pass_frame(frame: &[u8]) -> Result<APDU, ApduStatusCode> {
        APDU::try_from(frame)
    }

    #[test]
    fn test_case_type_1() {
        let frame: [u8; 4] = [0x00, 0x12, 0x00, 0x80];
        let response = pass_frame(&frame);
        assert!(response.is_ok());

Review comment (suggestion):
In case of `Le3` the first byte must be 0. Checking this byte would allow to read a `u16` instead and merge the code with `Le2` case for adjusting it.

Code after:
            // Lc is possibly three-bytes long
            let extended_apdu_lc: usize = BigEndian::read_u16(&payload[1..]) as usize;
            let extended_apdu_le_len: usize = if payload.len() > extended_apdu_lc {
                payload.len() - extended_apdu_lc - 3
            } else {
                0
            };
            if byte_0 == 0 && extended_apdu_le_len <= 3 {
                // If first byte is zero AND the next two bytes can be parsed as a big-endian
                // length that covers the rest of the block (plus few additional bytes for Le), we
                // have an extended-length APDU
                let last_byte: u32 = (*payload.last().unwrap()).into();
                return Ok(APDU {
                    header: array_ref!(header, 0, APDU_HEADER_LEN).into(),
                    lc: extended_apdu_lc as u16,
                    data: payload[3..(payload.len() - extended_apdu_le_len)].to_vec(),
                    le: match extended_apdu_le_len {
                        0 => 0,
                        1 => {
                            if last_byte == 0x00 {
                                0x100
                            } else {
                                last_byte
                            }
                        }
                        2 => {
                            let le_parsed = BigEndian::read_u16(&payload[payload.len() - 2..]);
                            if le_parsed == 0x00 {
                                0x10000
                            } else {
                                le_parsed as u32
                            }
                        }
                        3 => {
                            let le_first_byte: u32 =
                                (*payload.get(payload.len() - 3).unwrap()).into();
                            if le_first_byte != 0x00 {
                                return Err(ApduStatusCode::SW_INTERNAL_EXCEPTION);
                            }
                            let le_parsed = BigEndian::read_u16(&payload[payload.len() - 2..]);
                            if le_parsed == 0x00 {
                                0x10000
                            } else {
                                le_parsed as u32
                            }
                        }
                        _ => return Err(ApduStatusCode::SW_INTERNAL_EXCEPTION),
                    },
                    case_type: ApduType::Extended(match extended_apdu_le_len {
                        0 => Case::Lc3Data,
                        1 => Case::Lc3DataLe1,