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

Code before:
        options_map.insert(
            String::from("clientPin"),
            self.persistent_store.pin_hash().is_some(),
        );
        Ok(ResponseData::AuthenticatorGetInfo(
            #[cfg(feature = "with_ctap2_1")]
            AuthenticatorGetInfoResponse {
                versions: vec![
                    #[cfg(feature = "with_ctap1")]
                    String::from(U2F_VERSION_STRING),
                    String::from(FIDO2_VERSION_STRING),
                ],
                extensions: Some(vec![String::from("hmac-secret")]),
                aaguid: *AAGUID,
                options: Some(options_map),
                max_msg_size: Some(1024),
                pin_protocols: Some(vec![
                    CtapState::<R, CheckUserPresence>::PIN_PROTOCOL_VERSION,
                ]),
                max_credential_count_in_list: MAX_CREDENTIAL_COUNT_IN_LIST.map(|c| c as u64),
                // You can use ENCRYPTED_CREDENTIAL_ID_SIZE here, but if your
                // browser passes that value, it might be used to fingerprint.
                max_credential_id_length: None,
                transports: Some(vec![AuthenticatorTransport::Usb]),
                algorithms: Some(vec![ES256_CRED_PARAM]),
                firmware_version: None,
            },
            #[cfg(not(feature = "with_ctap2_1"))]
            AuthenticatorGetInfoResponse {
                versions: vec![
                    #[cfg(feature = "with_ctap1")]
                    String::from(U2F_VERSION_STRING),
                    String::from(FIDO2_VERSION_STRING),
                ],
                extensions: Some(vec![String::from("hmac-secret")]),
                aaguid: *AAGUID,
                options: Some(options_map),
                max_msg_size: Some(1024),
                pin_protocols: Some(vec![
                    CtapState::<R, CheckUserPresence>::PIN_PROTOCOL_VERSION,
                ]),
            },
        ))
    }

    fn check_and_store_new_pin(
        &mut self,
        aes_dec_key: &crypto::aes256::DecryptionKey,
        new_pin_enc: Vec<u8>,
    ) -> bool {
        if new_pin_enc.len() != PIN_PADDED_LENGTH {

Review comment (suggestion):
As an alternative to duplicating all the other fields, these ones could be individually enabled by `cfg`. This would also be consistent with the definition of the struct in the other file.

Code after:
        options_map.insert(
            String::from("clientPin"),
            self.persistent_store.pin_hash().is_some(),
        );
        Ok(ResponseData::AuthenticatorGetInfo(
            AuthenticatorGetInfoResponse {
                versions: vec![
                    #[cfg(feature = "with_ctap1")]
                    String::from(U2F_VERSION_STRING),
                    String::from(FIDO2_VERSION_STRING),
                ],
                extensions: Some(vec![String::from("hmac-secret")]),
                aaguid: *AAGUID,
                options: Some(options_map),
                max_msg_size: Some(1024),
                pin_protocols: Some(vec![
                    CtapState::<R, CheckUserPresence>::PIN_PROTOCOL_VERSION,
                ]),
                #[cfg(feature = "with_ctap2_1")]
                max_credential_count_in_list: MAX_CREDENTIAL_COUNT_IN_LIST.map(|c| c as u64),
                // You can use ENCRYPTED_CREDENTIAL_ID_SIZE here, but if your
                // browser passes that value, it might be used to fingerprint.
                #[cfg(feature = "with_ctap2_1")]
                max_credential_id_length: None,
                #[cfg(feature = "with_ctap2_1")]
                transports: Some(vec![AuthenticatorTransport::Usb]),
                #[cfg(feature = "with_ctap2_1")]
                algorithms: Some(vec![ES256_CRED_PARAM]),
                #[cfg(feature = "with_ctap2_1")]
                firmware_version: None,
            },
        ))
    }

    fn check_and_store_new_pin(
        &mut self,
        aes_dec_key: &crypto::aes256::DecryptionKey,
        new_pin_enc: Vec<u8>,
    ) -> bool {
        if new_pin_enc.len() != PIN_PADDED_LENGTH {
            return false;
        }
        let iv = [0; 16];
        // Assuming PIN_PADDED_LENGTH % block_size == 0 here.
        let mut blocks = [[0u8; 16]; PIN_PADDED_LENGTH / 16];
        for i in 0..PIN_PADDED_LENGTH / 16 {
            blocks[i].copy_from_slice(&new_pin_enc[i * 16..(i + 1) * 16]);
        }
        cbc_decrypt(aes_dec_key, iv, &mut blocks);
        let mut pin = vec![];
        'pin_block_loop: for block in blocks.iter().take(PIN_PADDED_LENGTH / 16) {