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

LargeBlob trait supports buffering choice #682

Merged
merged 3 commits into from
Apr 8, 2024

Conversation

kaczmarczyck
Copy link
Collaborator

Also makes LargeBlob a proper stateful command that loses state when interleaved.

To make sure the API does indeed support buffering in both memory and flash, see the following diff for reference:

diff --git a/libraries/opensk/src/api/persist.rs b/libraries/opensk/src/api/persist.rs
index 6caaec9..b9e3543 100644
--- a/libraries/opensk/src/api/persist.rs
+++ b/libraries/opensk/src/api/persist.rs
@@ -236,7 +236,11 @@ pub trait Persist {
     ///
     /// Returns a buffer that is returned to other API calls for potential usage.
     fn init_large_blob(&mut self, expected_length: usize) -> CtapResult<Vec<u8>> {
-        Ok(Vec::with_capacity(expected_length))
+        debug_assert!(expected_length <= keys::LARGE_BLOB_SHARDS.len() * VALUE_LENGTH);
+        for key in keys::LARGE_BLOB_SHARDS {
+            self.remove(key)?;
+        }
+        Ok(Vec::new())
     }
 
     /// Writes a large blob chunk to the buffer.
@@ -246,13 +250,22 @@ pub trait Persist {
         &mut self,
         offset: usize,
         chunk: &mut Vec<u8>,
-        buffer: &mut Vec<u8>,
+        _buffer: &mut Vec<u8>,
     ) -> CtapResult<()> {
-        if buffer.len() != offset {
-            // This should be caught on CTAP level.
-            return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
+        for (i, key) in keys::LARGE_BLOB_SHARDS.enumerate() {
+            let start = cmp::max(i * VALUE_LENGTH, offset);
+            let end = cmp::min((i + 1) * VALUE_LENGTH, offset.saturating_add(chunk.len()));
+            if start >= end {
+                continue;
+            }
+            let mut stored = self.find(key)?.unwrap_or_default();
+            let shard_offset = start - i * VALUE_LENGTH;
+            if stored.len() != shard_offset {
+                return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
+            }
+            stored.extend_from_slice(&chunk[start - offset..][..end - start]);
+            self.insert(key, &stored)?;
         }
-        buffer.append(chunk);
         Ok(())
     }
 
@@ -266,14 +279,8 @@ pub trait Persist {
         &self,
         mut offset: usize,
         byte_count: usize,
-        buffer: Option<&Vec<u8>>,
+        _buffer: Option<&Vec<u8>>,
     ) -> CtapResult<Option<Vec<u8>>> {
-        if let Some(buffer) = buffer {
-            let start = cmp::min(offset, buffer.len());
-            let end = offset.saturating_add(byte_count);
-            let end = cmp::min(end, buffer.len());
-            return Ok(Some(buffer[start..end].to_vec()));
-        }
         let mut result = Vec::with_capacity(byte_count);
         for key in keys::LARGE_BLOB_SHARDS {
             if offset >= VALUE_LENGTH {
@@ -297,19 +304,8 @@ pub trait Persist {
     }
 
     /// Sets a byte vector as the serialized large blobs array.
-    fn commit_large_blob_array(&mut self, buffer: &Vec<u8>) -> CtapResult<()> {
-        debug_assert!(buffer.len() <= keys::LARGE_BLOB_SHARDS.len() * VALUE_LENGTH);
-        let mut offset = 0;
-        for key in keys::LARGE_BLOB_SHARDS {
-            let cur_len = cmp::min(buffer.len().saturating_sub(offset), VALUE_LENGTH);
-            let slice = &buffer[offset..][..cur_len];
-            if slice.is_empty() {
-                self.remove(key)?;
-            } else {
-                self.insert(key, slice)?;
-            }
-            offset += cur_len;
-        }
+    #[allow(clippy::ptr_arg)]
+    fn commit_large_blob_array(&mut self, _buffer: &Vec<u8>) -> CtapResult<()> {
         Ok(())
     }

Also makes LargeBlob a proper stateful command that loses state when
interleaved.
@kaczmarczyck kaczmarczyck requested a review from ia0 April 5, 2024 19:04
@coveralls
Copy link

coveralls commented Apr 5, 2024

Coverage Status

coverage: 97.14% (+0.1%) from 97.026%
when pulling 85a06db on kaczmarczyck:stateful-large-blob
into 3faea59 on google:develop.

libraries/opensk/src/api/persist.rs Outdated Show resolved Hide resolved
libraries/opensk/src/api/persist.rs Outdated Show resolved Hide resolved
libraries/opensk/src/api/persist.rs Outdated Show resolved Hide resolved
libraries/opensk/src/ctap/mod.rs Outdated Show resolved Hide resolved
@kaczmarczyck kaczmarczyck requested a review from ia0 April 8, 2024 13:30
libraries/opensk/src/api/persist.rs Outdated Show resolved Hide resolved
libraries/opensk/src/api/persist.rs Outdated Show resolved Hide resolved
@kaczmarczyck kaczmarczyck requested a review from ia0 April 8, 2024 14:47
@kaczmarczyck kaczmarczyck merged commit 119cc21 into google:develop Apr 8, 2024
9 checks passed
@kaczmarczyck kaczmarczyck deleted the stateful-large-blob branch April 8, 2024 16:06
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.

3 participants