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

Code before:
    let cbor_credential_source = cbor_read(plaintext.as_slice())?;
    destructure_cbor_map! {
      let {
          CredentialSourceField::PrivateKey => private_key,
          CredentialSourceField::RpIdHash=> rp_id_hash,
          CredentialSourceField::CredProtectPolicy => cred_protect_policy,
          CredentialSourceField::CredBlob => cred_blob,
      } = extract_map(cbor_credential_source)?;
    }
    Ok(match (private_key, rp_id_hash) {
        (Some(private_key), Some(rp_id_hash)) => {
            let private_key = PrivateKey::try_from(private_key)?;
            let rp_id_hash = extract_byte_string(rp_id_hash)?;
            if rp_id_hash.len() != 32 {
                return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
            }
            let cred_protect_policy = if let Some(policy) = cred_protect_policy {
                Some(CredentialProtectionPolicy::try_from(policy)?)
            } else {
                None
            };
            let cred_blob = if let Some(blob) = cred_blob {
                Some(extract_byte_string(blob)?)
            } else {
                None
            };
            Some(CredentialSource {
                private_key,
                rp_id_hash: rp_id_hash.try_into().unwrap(),
                cred_protect_policy,
                cred_blob,
            })
        }
        _ => None,
    })
}

/// Pad data to MAX_PADDING_LENGTH+1 (192) bytes using PKCS padding scheme.
/// Let N = 192 - data.len(), the PKCS padding scheme would pad N bytes of N after the data.
fn add_padding(data: &mut Vec<u8>) -> Result<(), Ctap2StatusCode> {
    // The data should be between 1 to MAX_PADDING_LENGTH bytes for the padding scheme to be valid.
    if data.is_empty() || data.len() > MAX_PADDING_LENGTH as usize {
        return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
    }
    let pad_length = MAX_PADDING_LENGTH - (data.len() as u8 - 1);
    data.extend(core::iter::repeat(pad_length).take(pad_length as usize));
    Ok(())
}

fn remove_padding(data: &mut Vec<u8>) -> Result<(), Ctap2StatusCode> {
    if data.len() != MAX_PADDING_LENGTH as usize + 1 {

Review comment (refactor):
Here and with the above `cred_protect_policy`, a shorter way to write this is:
```
let cred_blob = cred_blob.map(extract_byte_string).transpose()?;
```

Code after:
    let cbor_credential_source = cbor_read(plaintext.as_slice())?;
    destructure_cbor_map! {
      let {
          CredentialSourceField::PrivateKey => private_key,
          CredentialSourceField::RpIdHash=> rp_id_hash,
          CredentialSourceField::CredProtectPolicy => cred_protect_policy,
          CredentialSourceField::CredBlob => cred_blob,
      } = extract_map(cbor_credential_source)?;
    }
    Ok(match (private_key, rp_id_hash) {
        (Some(private_key), Some(rp_id_hash)) => {
            let private_key = PrivateKey::try_from(private_key)?;
            let rp_id_hash = extract_byte_string(rp_id_hash)?;
            if rp_id_hash.len() != 32 {
                return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
            }
            let cred_protect_policy = cred_protect_policy
                .map(CredentialProtectionPolicy::try_from)
                .transpose()?;
            let cred_blob = cred_blob.map(extract_byte_string).transpose()?;
            Some(CredentialSource {
                private_key,
                rp_id_hash: rp_id_hash.try_into().unwrap(),
                cred_protect_policy,
                cred_blob,
            })
        }
        _ => None,
    })
}

/// Pad data to MAX_PADDING_LENGTH+1 (192) bytes using PKCS padding scheme.
/// Let N = 192 - data.len(), the PKCS padding scheme would pad N bytes of N after the data.
fn add_padding(data: &mut Vec<u8>) -> Result<(), Ctap2StatusCode> {
    // The data should be between 1 to MAX_PADDING_LENGTH bytes for the padding scheme to be valid.
    if data.is_empty() || data.len() > MAX_PADDING_LENGTH as usize {
        return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
    }
    let pad_length = MAX_PADDING_LENGTH - (data.len() as u8 - 1);
    data.extend(core::iter::repeat(pad_length).take(pad_length as usize));
    Ok(())
}

fn remove_padding(data: &mut Vec<u8>) -> Result<(), Ctap2StatusCode> {
    if data.len() != MAX_PADDING_LENGTH as usize + 1 {
        // This is an internal error instead of corrupted credential ID which we should just ignore because
        // we've already checked that the HMAC matched.
        return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
    }
    let pad_length = *data.last().unwrap();
    if pad_length == 0 || pad_length > MAX_PADDING_LENGTH {