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

Code before:
        let mut apdu = APDU {
            header: array_ref!(header, 0, 4).into(),
            lc: 0x00,
            data: Vec::new(),
            le: 0x00,
            case_type: ApduType::default(),
        };

        if payload.is_empty() {
            // Lc is zero-bytes in length
            apdu.case_type = ApduType::Instruction;
        } else {
            // Lc is not zero-bytes in length, let's figure out how long it is
            let byte_0 = payload[0];
            if payload.len() == 1 {
                // There is only one byte in the payload, that byte cannot be Lc because that would
                // entail at *least* one another byte in the payload (for the command data)
                apdu.case_type = ApduType::Short(Case::Le1);
                apdu.le = if byte_0 == 0x00 {
                    // Ne = 256
                    0x100
                } else {
                    byte_0.into()
                }
            }
            if payload.len() == (1 + byte_0) as usize && byte_0 != 0 {
                // Lc is one-byte long and since the size specified by Lc covers the rest of the
                // payload there's no Le at the end
                apdu.case_type = ApduType::Short(Case::Lc1Data);
                apdu.lc = byte_0.into();
                apdu.data = payload[1..].to_vec();
            }
            if payload.len() == (1 + byte_0 + 1) as usize && byte_0 != 0 {
                // Lc is one-byte long and since the size specified by Lc covers the rest of the
                // payload with ONE additional byte that byte must be Le
                apdu.case_type = ApduType::Short(Case::Lc1DataLe1);
                apdu.lc = byte_0.into();
                apdu.data = payload[1..(payload.len() - 1)].to_vec();
                apdu.le = (*payload.last().unwrap()).into();
                if apdu.le == 0x00 {
                    apdu.le = 0x100;
                }
            }
            if payload.len() > 2 {
                // 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
                };

Review comment (bug):
As @ia0 said, this can overflow as the addition is done before promoting to `usize`

Code after:
            });
        }
        // Lc is not zero-bytes in length, let's figure out how long it is
        let byte_0 = payload[0];
        if payload.len() == 1 {
            // There is only one byte in the payload, that byte cannot be Lc because that would
            // entail at *least* one another byte in the payload (for the command data)
            return Ok(APDU {
                header: array_ref!(header, 0, APDU_HEADER_LEN).into(),
                lc: 0x00,
                data: Vec::new(),
                le: if byte_0 == 0x00 {
                    // Ne = 256
                    0x100
                } else {
                    byte_0.into()
                },
                case_type: ApduType::Short(Case::Le1),
            });
        }
        if payload.len() == 1 + (byte_0 as usize) && byte_0 != 0 {
            // Lc is one-byte long and since the size specified by Lc covers the rest of the
            // payload there's no Le at the end
            return Ok(APDU {
                header: array_ref!(header, 0, APDU_HEADER_LEN).into(),
                lc: byte_0.into(),
                data: payload[1..].to_vec(),
                case_type: ApduType::Short(Case::Lc1Data),
                le: 0,
            });
        }
        if payload.len() == 2 + (byte_0 as usize) && byte_0 != 0 {
            // Lc is one-byte long and since the size specified by Lc covers the rest of the
            // payload with ONE additional byte that byte must be Le
            let last_byte: u32 = (*payload.last().unwrap()).into();
            return Ok(APDU {
                header: array_ref!(header, 0, APDU_HEADER_LEN).into(),
                lc: byte_0.into(),
                data: payload[1..(payload.len() - 1)].to_vec(),
                le: if last_byte == 0x00 { 0x100 } else { last_byte },
                case_type: ApduType::Short(Case::Lc1DataLe1),
            });
        }
        if payload.len() > 2 {
            // 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
            };