Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hostenv file storage #489

Merged
merged 10 commits into from
Jun 8, 2022
Merged

Hostenv file storage #489

merged 10 commits into from
Jun 8, 2022

Conversation

egor-duda
Copy link
Contributor

Part of implementation for #485

This PR implements a storage, backed by file on host OS, for persisting authenticator data between restarts of OpenSK application used for FIDO2 emulation for QEMU.

After changes to storage API there's no more need for double buffering of storage data.

Current read_slice() method signature declares storage object as immutable. This conflicts with File object being mutated by read operations (current file position is changed for and after read). To keep read_slice() signature unchanged, interior mutability via RefCell is used.

egor-duda added 2 commits June 5, 2022 15:08
This allows running ctap2 authenticator application on non-embedded host OS
to implement virtual FIDO2 authenticator for QEMU
read_slice(...) can return Cow::Owned buffer to the caller
@coveralls
Copy link

coveralls commented Jun 5, 2022

Coverage Status

Coverage increased (+0.1%) to 90.027% when pulling cc1fb25 on egor-duda:hostenv-file-storage into 12f6ed6 on google:develop.

Copy link
Member

@ia0 ia0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overall looks good to me. I made a first pass of high-level comments. I left the more style-related comments for later.

Copy link
Member

@ia0 ia0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!


if file_len == 0 {
file.seek(SeekFrom::Start(0))?;
let buf = vec![0xffu8; options.page_size];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have generally used 0xFF. Is the u8 annotation is required?

Other instances of this exist below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, for consistency with the rest of the library let's use 0xff if Rust is able to infer the type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -365,6 +365,8 @@ extern crate alloc;
mod buffer;
#[cfg(feature = "std")]
mod driver;
#[cfg(feature = "std")]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this std condition correctly interact with the rest of the code? We use std for tests and fuzzing only so far. Therefore, I was wondering if you can just compile the OpenSK library with std later for non-testing purposes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, std means that we compile with the standard library (and thus an OS). We use std for tests and fuzzing because that's the only reason we need to compile on an OS. And this example is another reason now.

Note that once CTAP is a library we will compile it with std for non-testing purposes too. This library is just one step ahead because it's already a library and doesn't depend on Tock.

@@ -36,6 +36,13 @@ pub enum StorageError {
CustomError,
}

#[cfg(feature = "std")]
impl From<std::io::Error> for StorageError {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, another use of std that is actually necessary outside of tests.

@kaczmarczyck
Copy link
Collaborator

I resolved all of @ia0 's comments since approved. I don't mind merging, just had a nit and an open question about `std``, and if you already tried using this PR in your QEMU project and it all worked.

ia0
ia0 previously approved these changes Jun 7, 2022
Copy link
Member

@ia0 ia0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not merging to first get a confirmation that this PR solves the problem of running with QEMU.


if file_len == 0 {
file.seek(SeekFrom::Start(0))?;
let buf = vec![0xffu8; options.page_size];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, for consistency with the rest of the library let's use 0xff if Rust is able to infer the type.

@@ -365,6 +365,8 @@ extern crate alloc;
mod buffer;
#[cfg(feature = "std")]
mod driver;
#[cfg(feature = "std")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, std means that we compile with the standard library (and thus an OS). We use std for tests and fuzzing because that's the only reason we need to compile on an OS. And this example is another reason now.

Note that once CTAP is a library we will compile it with std for non-testing purposes too. This library is just one step ahead because it's already a library and doesn't depend on Tock.

@egor-duda
Copy link
Contributor Author

egor-duda commented Jun 7, 2022

Regarding std, I've tested my prototype code:

I run cargo run --features=std on linux host system and ssh-keygen -t ecdsa-sk on QEMU guest, then restarted qemu virtual fido2 device and opensk application and connected via ssh using generated ecdsa-sk key. Everything worked fine.

However, I've encountered two problems:

  1. Current implementations of Store tries to convert max_page_erases and max_word_writes to Nat type, which fails in current implementation of this PR on 64-bit platform, trying to convert usize::MAX to u32
  2. Format::is_storage_supported function disallows storages with max_page_erases > 65535

Should I change FileStorage::max_word_writes and max_page_erases to return Nat::MAX and 65535 respectively, or change functions in Format to accommodate current FileStorage max values?

@ia0
Copy link
Member

ia0 commented Jun 7, 2022

Should I change FileStorage::max_word_writes and max_page_erases to return Nat::MAX and 65535 respectively, or change functions in Format to accommodate current FileStorage max values?

Oops my bad, I forgot about that. Yes, your suggestion sounds good. Let's also document for each of them why we use those values because I'm pretty I'm gonna forget again.

fn max_word_writes(&self) -> usize {
    // We can write an unlimited amount of times in a file, but the store arithmetic
    // uses `Nat` so the value should fit in a `Nat`.
    Nat::MAX as usize
}

fn max_page_erases(&self) -> usize {
    // We can "erase" an unlimited amount of times in a file, but the store format
    // encodes the number of erase cycles on 16 bits.
    u16::MAX as usize
}

@ia0 ia0 merged commit 4763c3a into google:develop Jun 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants