Skip to content

Commit 3a66559

Browse files
committed
wip(rust/signed_doc): implement verification method
* verify signatures with public (verification) key * todo: verify UUIDs
1 parent 3d34e47 commit 3a66559

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

rust/signed_doc/src/lib.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub use builder::Builder;
1717
use catalyst_types::problem_report::ProblemReport;
1818
pub use content::Content;
1919
use coset::{CborSerializable, Header};
20+
use ed25519_dalek::VerifyingKey;
2021
use error::CatalystSignedDocError;
2122
pub use metadata::{DocumentRef, ExtraFields, Metadata, UuidV4, UuidV7};
2223
pub use minicbor::{decode, encode, Decode, Decoder, Encode};
@@ -105,6 +106,72 @@ impl CatalystSignedDocument {
105106
pub fn signatures(&self) -> &Signatures {
106107
&self.inner.signatures
107108
}
109+
110+
/// Verify document signatures and `UUID`s.
111+
///
112+
/// # Errors
113+
///
114+
/// Returns a report of verification failures and the source error.
115+
#[allow(clippy::indexing_slicing)]
116+
pub fn verify<P>(&self, pk_getter: P) -> Result<(), CatalystSignedDocError>
117+
where P: Fn(&KidUri) -> VerifyingKey {
118+
let error_report = ProblemReport::new("Catalyst Signed Document Verification");
119+
120+
match self.as_cose_sign() {
121+
Ok(cose_sign) => {
122+
let signatures = self.signatures().cose_signatures();
123+
for (idx, kid) in self.signatures().kids().iter().enumerate() {
124+
let pk = pk_getter(kid);
125+
let signature = &signatures[idx];
126+
let tbs_data = cose_sign.tbs_data(&[], signature);
127+
match signature.signature.as_slice().try_into() {
128+
Ok(signature_bytes) => {
129+
let signature = ed25519_dalek::Signature::from_bytes(signature_bytes);
130+
if let Err(e) = pk.verify_strict(&tbs_data, &signature) {
131+
error_report.functional_validation(
132+
&format!(
133+
"Verification failed for signature with Key ID {kid}: {e}"
134+
),
135+
"During signature validation with verifying key",
136+
);
137+
}
138+
},
139+
Err(_) => {
140+
error_report.invalid_value(
141+
"cose signature",
142+
&format!("{}", signature.signature.len()),
143+
&format!("must be {}", ed25519_dalek::Signature::BYTE_SIZE),
144+
"During encoding cose signature to bytes",
145+
);
146+
},
147+
}
148+
}
149+
},
150+
Err(e) => {
151+
error_report.other(
152+
&format!("{e}"),
153+
"During encoding signed document as COSE SIGN",
154+
);
155+
},
156+
}
157+
158+
if error_report.is_problematic() {
159+
return Err(CatalystSignedDocError::new(
160+
error_report,
161+
anyhow::anyhow!("Verification failed for Catalyst Signed Document"),
162+
));
163+
}
164+
165+
Ok(())
166+
}
167+
168+
/// Convert Catalyst Signed Document into `coset::CoseSign`
169+
fn as_cose_sign(&self) -> anyhow::Result<coset::CoseSign> {
170+
let mut cose_bytes: Vec<u8> = Vec::new();
171+
minicbor::encode(self, &mut cose_bytes)?;
172+
coset::CoseSign::from_slice(&cose_bytes)
173+
.map_err(|e| anyhow::anyhow!("encoding COSE SIGN failed: {e}"))
174+
}
108175
}
109176

110177
impl TryFrom<&[u8]> for CatalystSignedDocument {

0 commit comments

Comments
 (0)