Skip to content

Commit bec8829

Browse files
committed
Supply data_decryption_key and aad for StorableBuilder
Previously, we the `vss-client` didn't allow to set `ChaCha20Poly1305RFC`'s `aad` field, which had the `tag` not commit to any particular key. This would allow a malicious VSS provider to substitute blobs stored under a different key without the client noticing. Here, we now set the `aad` field to the key under which the `Storable` will be stored, ensuring that the retrieved data was originally stored under the key we expected. We also account for `StorableBuilder` now taking `data_decryption_key` by reference on `build`/`deconstruct`.
1 parent b316009 commit bec8829

File tree

1 file changed

+29
-22
lines changed

1 file changed

+29
-22
lines changed

src/io/vss_store.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ impl Drop for VssStore {
316316
struct VssStoreInner {
317317
client: VssClient<CustomRetryPolicy>,
318318
store_id: String,
319-
storable_builder: StorableBuilder<RandEntropySource>,
319+
data_encryption_key: [u8; 32],
320320
key_obfuscator: KeyObfuscator,
321321
// Per-key locks that ensures that we don't have concurrent writes to the same namespace/key.
322322
// The lock also encapsulates the latest written version per key.
@@ -331,7 +331,6 @@ impl VssStoreInner {
331331
let (data_encryption_key, obfuscation_master_key) =
332332
derive_data_encryption_and_obfuscation_keys(&vss_seed);
333333
let key_obfuscator = KeyObfuscator::new(obfuscation_master_key);
334-
let storable_builder = StorableBuilder::new(data_encryption_key, RandEntropySource);
335334
let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(10))
336335
.with_max_attempts(10)
337336
.with_max_total_delay(Duration::from_secs(15))
@@ -347,7 +346,7 @@ impl VssStoreInner {
347346

348347
let client = VssClient::new_with_headers(base_url, retry_policy, header_provider);
349348
let locks = Mutex::new(HashMap::new());
350-
Self { client, store_id, storable_builder, key_obfuscator, locks }
349+
Self { client, store_id, data_encryption_key, key_obfuscator, locks }
351350
}
352351

353352
fn get_inner_lock_ref(&self, locking_key: String) -> Arc<tokio::sync::Mutex<u64>> {
@@ -413,9 +412,8 @@ impl VssStoreInner {
413412
) -> io::Result<Vec<u8>> {
414413
check_namespace_key_validity(&primary_namespace, &secondary_namespace, Some(&key), "read")?;
415414

416-
let obfuscated_key =
417-
self.build_obfuscated_key(&primary_namespace, &secondary_namespace, &key);
418-
let request = GetObjectRequest { store_id: self.store_id.clone(), key: obfuscated_key };
415+
let store_key = self.build_obfuscated_key(&primary_namespace, &secondary_namespace, &key);
416+
let request = GetObjectRequest { store_id: self.store_id.clone(), key: store_key.clone() };
419417
let resp = self.client.get_object(&request).await.map_err(|e| {
420418
let msg = format!(
421419
"Failed to read from key {}/{}/{}: {}",
@@ -437,7 +435,11 @@ impl VssStoreInner {
437435
Error::new(ErrorKind::Other, msg)
438436
})?;
439437

440-
Ok(self.storable_builder.deconstruct(storable)?.0)
438+
let storable_builder = StorableBuilder::new(RandEntropySource);
439+
let decrypted = storable_builder
440+
.deconstruct(storable, &self.data_encryption_key, store_key.as_bytes())?
441+
.0;
442+
Ok(decrypted)
441443
}
442444

443445
async fn write_internal(
@@ -451,22 +453,27 @@ impl VssStoreInner {
451453
"write",
452454
)?;
453455

454-
self.execute_locked_write(inner_lock_ref, locking_key, version, async move || {
455-
let obfuscated_key =
456-
self.build_obfuscated_key(&primary_namespace, &secondary_namespace, &key);
457-
let vss_version = -1;
458-
let storable = self.storable_builder.build(buf, vss_version);
459-
let request = PutObjectRequest {
460-
store_id: self.store_id.clone(),
461-
global_version: None,
462-
transaction_items: vec![KeyValue {
463-
key: obfuscated_key,
464-
version: vss_version,
465-
value: storable.encode_to_vec(),
466-
}],
467-
delete_items: vec![],
468-
};
456+
let store_key = self.build_obfuscated_key(&primary_namespace, &secondary_namespace, &key);
457+
let vss_version = -1;
458+
let storable_builder = StorableBuilder::new(RandEntropySource);
459+
let storable = storable_builder.build(
460+
buf.to_vec(),
461+
vss_version,
462+
&&self.data_encryption_key,
463+
store_key.as_bytes(),
464+
);
465+
let request = PutObjectRequest {
466+
store_id: self.store_id.clone(),
467+
global_version: None,
468+
transaction_items: vec![KeyValue {
469+
key: store_key,
470+
version: vss_version,
471+
value: storable.encode_to_vec(),
472+
}],
473+
delete_items: vec![],
474+
};
469475

476+
self.execute_locked_write(inner_lock_ref, locking_key, version, async move || {
470477
self.client.put_object(&request).await.map_err(|e| {
471478
let msg = format!(
472479
"Failed to write to key {}/{}/{}: {}",

0 commit comments

Comments
 (0)