Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions keep-cli/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use crate::bunker::generate_bunker_url;
use crate::signer::{AuditLog, FrostSigner, NetworkFrostSigner, PermissionManager, SignerHandler};
use crate::tui::{LogEntry, TuiEvent};

const MAX_EVENT_JSON_SIZE: usize = 64 * 1024;

pub struct Server {
keys: Keys,
relay_url: String,
Expand Down Expand Up @@ -288,6 +290,10 @@ impl Server {
None => return Nip46Response::error(id, "Missing event parameter"),
};

if event_json.len() > MAX_EVENT_JSON_SIZE {
return Nip46Response::error(id, "Event JSON too large");
}

let partial: PartialEvent = match serde_json::from_str(event_json) {
Ok(p) => p,
Err(e) => return Nip46Response::error(id, &format!("Invalid event: {}", e)),
Expand All @@ -308,10 +314,10 @@ impl Server {
);

match handler.handle_sign_event(app_pubkey, unsigned).await {
Ok(event) => {
let json = serde_json::to_string(&event).unwrap();
Nip46Response::ok(id, &json)
}
Ok(event) => match serde_json::to_string(&event) {
Ok(json) => Nip46Response::ok(id, &json),
Err(e) => Nip46Response::error(id, &format!("Serialization failed: {}", e)),
},
Err(e) => Nip46Response::error(id, &e.to_string()),
}
}
Expand Down
25 changes: 25 additions & 0 deletions keep-core/src/frost/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::error::{KeepError, Result};
use super::share::SharePackage;

const SHARE_HRP: &str = "kshare";
const MAX_FRAME_COUNT: usize = 100;
const MAX_ASSEMBLED_SIZE: usize = 64 * 1024;

#[derive(Serialize, Deserialize)]
pub struct ShareExport {
Expand Down Expand Up @@ -248,13 +250,19 @@ impl ShareExport {
return Err(KeepError::Frost("No frames provided".into()));
}

if frames.len() > MAX_FRAME_COUNT {
return Err(KeepError::Frost("Too many frames".into()));
}

if frames.len() == 1 {
if let Ok(export) = Self::from_json(&frames[0]) {
return Ok(export);
}
}

let mut sorted: Vec<(usize, Vec<u8>)> = Vec::new();
let mut total_size = 0usize;
let mut seen_indices = std::collections::HashSet::new();

for frame in frames {
let parsed: serde_json::Value = serde_json::from_str(frame)
Expand All @@ -264,12 +272,29 @@ impl ShareExport {
.as_u64()
.ok_or_else(|| KeepError::Frost("Missing frame index".into()))?
as usize;

if idx >= MAX_FRAME_COUNT {
return Err(KeepError::Frost("Frame index out of range".into()));
}

if !seen_indices.insert(idx) {
return Err(KeepError::Frost("Duplicate frame index".into()));
}

let data_hex = parsed["d"]
.as_str()
.ok_or_else(|| KeepError::Frost("Missing frame data".into()))?;
let data = hex::decode(data_hex)
.map_err(|_| KeepError::Frost("Invalid frame data hex".into()))?;

total_size = total_size
.checked_add(data.len())
.ok_or_else(|| KeepError::Frost("Total size overflow".into()))?;

if total_size > MAX_ASSEMBLED_SIZE {
return Err(KeepError::Frost("Assembled data too large".into()));
}

sorted.push((idx, data));
}

Expand Down
25 changes: 21 additions & 4 deletions keep-core/src/hidden/volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ use crate::error::{KeepError, Result};
use crate::keys::KeyRecord;
use crate::rate_limit;

use bincode::Options;

use super::header::{
HiddenHeader, OuterHeader, DATA_START_OFFSET, HEADER_SIZE, HIDDEN_HEADER_OFFSET,
};

const KEYS_TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("keys");

const MAX_RECORD_SIZE: u64 = 1024 * 1024;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VolumeType {
Outer,
Expand Down Expand Up @@ -451,7 +455,9 @@ impl HiddenStorage {
let data_key = self.outer_key.as_ref().ok_or(KeepError::Locked)?;
let db = self.outer_db.as_ref().ok_or(KeepError::Locked)?;

let serialized = bincode::serialize(record)?;
let serialized = bincode::options()
.with_fixint_encoding()
.serialize(record)?;

let encrypted = crypto::encrypt(&serialized, data_key)?;
let encrypted_bytes = encrypted.to_bytes();
Expand Down Expand Up @@ -512,7 +518,12 @@ impl HiddenStorage {
Ok(d) => d,
Err(_) => return Ok(Vec::new()),
};
let records: Vec<KeyRecord> = match bincode::deserialize(&decrypted_bytes) {
let records: Vec<KeyRecord> = match bincode::options()
.with_fixint_encoding()
.allow_trailing_bytes()
.with_limit(MAX_RECORD_SIZE)
.deserialize(&decrypted_bytes)
{
Ok(r) => r,
Err(e) => {
tracing::warn!(
Expand All @@ -531,7 +542,9 @@ impl HiddenStorage {
data_key: &SecretKey,
hidden_header: &HiddenHeader,
) -> Result<()> {
let serialized = bincode::serialize(records)?;
let serialized = bincode::options()
.with_fixint_encoding()
.serialize(records)?;

let encrypted = crypto::encrypt(&serialized, data_key)?;
let encrypted_bytes = encrypted.to_bytes();
Expand Down Expand Up @@ -584,7 +597,11 @@ impl HiddenStorage {
let decrypted = crypto::decrypt(&encrypted, data_key)?;

let decrypted_bytes = decrypted.as_slice()?;
let record: KeyRecord = bincode::deserialize(&decrypted_bytes)?;
let record: KeyRecord = bincode::options()
.with_fixint_encoding()
.allow_trailing_bytes()
.with_limit(MAX_RECORD_SIZE)
.deserialize(&decrypted_bytes)?;

records.push(record);
}
Expand Down
22 changes: 19 additions & 3 deletions keep-core/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ use crate::frost::StoredShare;
use crate::keys::KeyRecord;
use crate::rate_limit;

use bincode::Options;

const KEYS_TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("keys");
const SHARES_TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("shares");

const MAX_RECORD_SIZE: u64 = 1024 * 1024;

const HEADER_MAGIC: &[u8; 8] = b"KEEPVALT";
const HEADER_VERSION: u16 = 1;
const HEADER_SIZE: usize = 256;
Expand Down Expand Up @@ -285,7 +289,11 @@ impl Storage {
let decrypted = crypto::decrypt(&encrypted, data_key)?;

let decrypted_bytes = decrypted.as_slice()?;
Ok(bincode::deserialize(&decrypted_bytes)?)
Ok(bincode::options()
.with_fixint_encoding()
.allow_trailing_bytes()
.with_limit(MAX_RECORD_SIZE)
.deserialize(&decrypted_bytes)?)
}

pub fn list_keys(&self) -> Result<Vec<KeyRecord>> {
Expand All @@ -304,7 +312,11 @@ impl Storage {
let decrypted = crypto::decrypt(&encrypted, data_key)?;

let decrypted_bytes = decrypted.as_slice()?;
let record: KeyRecord = bincode::deserialize(&decrypted_bytes)?;
let record: KeyRecord = bincode::options()
.with_fixint_encoding()
.allow_trailing_bytes()
.with_limit(MAX_RECORD_SIZE)
.deserialize(&decrypted_bytes)?;

records.push(record);
}
Expand Down Expand Up @@ -373,7 +385,11 @@ impl Storage {
let decrypted = crypto::decrypt(&encrypted, data_key)?;

let decrypted_bytes = decrypted.as_slice()?;
let share: StoredShare = bincode::deserialize(&decrypted_bytes)?;
let share: StoredShare = bincode::options()
.with_fixint_encoding()
.allow_trailing_bytes()
.with_limit(MAX_RECORD_SIZE)
.deserialize(&decrypted_bytes)?;

shares.push(share);
}
Expand Down