use new store fragments
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user