Skip to content

Commit 4a12132

Browse files
committed
fix: Limit the maximum number of assertions allowed for C2PA Manifest
1 parent 8efe78c commit 4a12132

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

sdk/src/builder.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,12 @@ impl Builder {
779779
S: Into<String>,
780780
T: Serialize,
781781
{
782+
let max_assertions = self.context.settings().builder.max_assertions;
783+
if self.definition.assertions.len() >= max_assertions {
784+
return Err(Error::TooManyAssertions {
785+
max: max_assertions,
786+
});
787+
}
782788
let created = false;
783789
self.definition.assertions.push(AssertionDefinition {
784790
label: label.into(),
@@ -804,6 +810,12 @@ impl Builder {
804810
S: Into<String>,
805811
T: Serialize,
806812
{
813+
let max_assertions = self.context.settings().builder.max_assertions;
814+
if self.definition.assertions.len() >= max_assertions {
815+
return Err(Error::TooManyAssertions {
816+
max: max_assertions,
817+
});
818+
}
807819
let created = false;
808820
self.definition.assertions.push(AssertionDefinition {
809821
label: label.into(),
@@ -5773,6 +5785,47 @@ mod tests {
57735785
assert!(reader.active_manifest().is_some());
57745786
}
57755787

5788+
#[test]
5789+
fn test_add_assertion_limit() {
5790+
use crate::settings::Settings;
5791+
5792+
// Default limit is 100; verify the 100th assertion succeeds and the 101st is rejected.
5793+
let mut builder = Builder::new();
5794+
let data = serde_json::json!({"value": 1});
5795+
for i in 0..100 {
5796+
builder
5797+
.add_assertion_json(format!("org.test.assertion.{i}"), &data)
5798+
.expect("should succeed within limit");
5799+
}
5800+
let err = builder
5801+
.add_assertion_json("org.test.assertion.overflow", &data)
5802+
.expect_err("101st assertion should be rejected");
5803+
assert!(matches!(err, Error::TooManyAssertions { max: 100 }));
5804+
5805+
// Verify the limit is configurable: set max_assertions=2 via settings.
5806+
let settings = Settings {
5807+
builder: crate::settings::builder::BuilderSettings {
5808+
max_assertions: 2,
5809+
..Default::default()
5810+
},
5811+
..Default::default()
5812+
};
5813+
let context = Context::new()
5814+
.with_settings(settings)
5815+
.expect("valid settings");
5816+
let mut builder = Builder::from_context(context);
5817+
builder
5818+
.add_assertion_json("org.test.a1", &data)
5819+
.expect("first assertion should succeed");
5820+
builder
5821+
.add_assertion_json("org.test.a2", &data)
5822+
.expect("second assertion should succeed");
5823+
let err = builder
5824+
.add_assertion_json("org.test.a3", &data)
5825+
.expect_err("third assertion should exceed limit of 2");
5826+
assert!(matches!(err, Error::TooManyAssertions { max: 2 }));
5827+
}
5828+
57765829
// Ensures that the future returned by `Builder::sign_async` implements `Send`, thus making it
57775830
// possible to spawn on a Tokio runtime.
57785831
#[test]

sdk/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ pub enum Error {
115115
#[error("more than one manifest store detected")]
116116
TooManyManifestStores,
117117

118+
#[error("assertion limit exceeded: maximum allowed is {max}")]
119+
TooManyAssertions { max: usize },
120+
118121
#[error("manifest is not refernced by any ingredient")]
119122
UnreferencedManifest,
120123

sdk/src/settings/builder.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,18 @@ pub struct BuilderSettings {
583583
///
584584
/// [`TimeStamp`]: crate::assertions::TimeStamp
585585
pub auto_timestamp_assertion: TimeStampSettings,
586+
/// Maximum number of assertions that can be added to a single manifest.
587+
///
588+
/// Limits resource consumption when processing untrusted manifests with a large number
589+
/// of assertions. Calls to [`Builder::add_assertion`] or [`Builder::add_assertion_json`]
590+
/// that would exceed this limit return [`Error::TooManyAssertions`].
591+
///
592+
/// The default value is 100.
593+
///
594+
/// [`Builder::add_assertion`]: crate::Builder::add_assertion
595+
/// [`Builder::add_assertion_json`]: crate::Builder::add_assertion_json
596+
/// [`Error::TooManyAssertions`]: crate::Error::TooManyAssertions
597+
pub max_assertions: usize,
586598
}
587599

588600
impl Default for BuilderSettings {
@@ -599,6 +611,7 @@ impl Default for BuilderSettings {
599611
prefer_box_hash: false,
600612
generate_c2pa_archive: Some(true),
601613
auto_timestamp_assertion: TimeStampSettings::default(),
614+
max_assertions: 100,
602615
}
603616
}
604617
}

0 commit comments

Comments
 (0)