use new store fragments

This commit is contained in:
Fabian Kaczmarczyck
2021-01-25 17:50:01 +01:00
parent b2c6ae8f82
commit 563f35184a

View File

@@ -32,6 +32,7 @@ use core::cmp;
use core::convert::TryInto; use core::convert::TryInto;
use crypto::rng256::Rng256; use crypto::rng256::Rng256;
use persistent_store::StoreUpdate; use persistent_store::StoreUpdate;
use persistent_store::fragment::{read_range, write};
// Those constants may be modified before compilation to tune the behavior of the key. // Those constants may be modified before compilation to tune the behavior of the key.
// //
@@ -469,13 +470,6 @@ impl PersistentStore {
)?) )?)
} }
/// The size used for shards of large blobs.
///
/// This value is constant during the lifetime of the device.
fn shard_size(&self) -> usize {
self.store.max_value_length()
}
/// Reads the byte vector stored as the serialized large blobs array. /// Reads the byte vector stored as the serialized large blobs array.
/// ///
/// If too few bytes exist at that offset, return the maximum number /// If too few bytes exist at that offset, return the maximum number
@@ -483,45 +477,23 @@ impl PersistentStore {
/// ///
/// If no large blob is committed to the store, get responds as if an empty /// If no large blob is committed to the store, get responds as if an empty
/// CBOR array (0x80) was written, together with the 16 byte prefix of its /// CBOR array (0x80) was written, together with the 16 byte prefix of its
/// SHA256, to a total length of 17 byte (which is the shortest legitemate /// SHA256, to a total length of 17 byte (which is the shortest legitimate
/// large blob entry possible). /// large blob entry possible).
pub fn get_large_blob_array( pub fn get_large_blob_array(
&self, &self,
mut offset: usize, offset: usize,
mut byte_count: usize, byte_count: usize,
) -> Result<Vec<u8>, Ctap2StatusCode> { ) -> Result<Vec<u8>, Ctap2StatusCode> {
let mut output = Vec::with_capacity(byte_count); let byte_range = offset..offset + byte_count;
while byte_count > 0 { let output = read_range(&self.store, &key::LARGE_BLOB_SHARDS, byte_range)?;
let shard_key = key::LARGE_BLOB_SHARDS.start + offset / self.shard_size(); Ok(output.unwrap_or_else(|| {
if !key::LARGE_BLOB_SHARDS.contains(&shard_key) { let empty_large_blob = vec![
// This request should have been caught at application level. 0x80, 0x76, 0xBE, 0x8B, 0x52, 0x8D, 0x00, 0x75, 0xF7, 0xAA, 0xE9, 0x8D, 0x6F, 0xA5,
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR); 0x7A, 0x6D, 0x3C,
} ];
let shard_entry = self.store.find(shard_key)?; let last_index = cmp::min(empty_large_blob.len(), offset + byte_count);
let shard_entry = if shard_key == key::LARGE_BLOB_SHARDS.start { empty_large_blob.get(offset..last_index).unwrap_or_default().to_vec()
shard_entry.unwrap_or_else(|| { }))
vec![
0x80, 0x76, 0xBE, 0x8B, 0x52, 0x8D, 0x00, 0x75, 0xF7, 0xAA, 0xE9, 0x8D,
0x6F, 0xA5, 0x7A, 0x6D, 0x3C,
]
})
} else {
shard_entry.unwrap_or_default()
};
let shard_offset = offset % self.shard_size();
if shard_entry.len() < shard_offset {
break;
}
let shard_length = cmp::min(shard_entry.len() - shard_offset, byte_count);
output.extend(&shard_entry[shard_offset..][..shard_length]);
if shard_entry.len() < self.shard_size() {
break;
}
offset += shard_length;
byte_count -= shard_length;
}
Ok(output)
} }
/// Sets a byte vector as the serialized large blobs array. /// Sets a byte vector as the serialized large blobs array.
@@ -529,21 +501,11 @@ impl PersistentStore {
&mut self, &mut self,
large_blob_array: &[u8], large_blob_array: &[u8],
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
// This input should have been caught at caller level.
if large_blob_array.len() > MAX_LARGE_BLOB_ARRAY_SIZE { if large_blob_array.len() > MAX_LARGE_BLOB_ARRAY_SIZE {
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR); return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
} }
Ok(write(&mut self.store, &key::LARGE_BLOB_SHARDS, large_blob_array)?)
let mut shards = large_blob_array.chunks(self.shard_size());
let mut updates = Vec::with_capacity(shards.len());
for key in key::LARGE_BLOB_SHARDS {
let update = match shards.next() {
Some(value) => StoreUpdate::Insert { key, value },
None if self.store.find(key)?.is_some() => StoreUpdate::Remove { key },
_ => break,
};
updates.push(update);
}
Ok(self.store.transaction(&updates)?)
} }
/// Returns the attestation private key if defined. /// Returns the attestation private key if defined.
@@ -642,6 +604,15 @@ impl PersistentStore {
pub fn force_pin_change(&mut self) -> Result<(), Ctap2StatusCode> { pub fn force_pin_change(&mut self) -> Result<(), Ctap2StatusCode> {
Ok(self.store.insert(key::FORCE_PIN_CHANGE, &[])?) Ok(self.store.insert(key::FORCE_PIN_CHANGE, &[])?)
} }
/// The size used for shards of large blobs.
///
/// This value is constant during the lifetime of the device.
#[cfg(test)]
fn shard_size(&self) -> usize {
self.store.max_value_length()
}
} }
impl From<persistent_store::StoreError> for Ctap2StatusCode { impl From<persistent_store::StoreError> for Ctap2StatusCode {