1use std::fmt;
10
11use sha2::{Digest, Sha384};
12
13use crate::cbor::{self, Value};
14use crate::node_key::{carried_key_well_formed, verify, KeyError, NodeKey};
15use crate::profile::Profile;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum ObjectError {
21 Malformed,
25 SignatureInvalid,
28 AlgMismatch,
30 AlgUnsupported(String),
33 FieldKeyNotText,
35 DuplicateField(String),
37 Key(KeyError),
39}
40
41impl fmt::Display for ObjectError {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 ObjectError::Malformed => f.write_str("malformed signed object"),
45 ObjectError::SignatureInvalid => {
46 f.write_str("the signed object's signature does not verify")
47 }
48 ObjectError::AlgMismatch => {
49 f.write_str("the signed object names another profile's algorithm")
50 }
51 ObjectError::AlgUnsupported(alg) => {
52 write!(f, "an alg the verifier does not take: {alg:?}")
53 }
54 ObjectError::FieldKeyNotText => f.write_str("a field key that is not text"),
55 ObjectError::DuplicateField(name) => write!(f, "two fields named {name:?}"),
56 ObjectError::Key(e) => write!(f, "{e}"),
57 }
58 }
59}
60
61impl std::error::Error for ObjectError {}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
65pub struct Object {
66 pub key: Vec<u8>,
67 pub tbs: Vec<u8>,
68 pub signature: Vec<u8>,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct HeldObject {
74 pub tbs: Vec<u8>,
75 pub signature: Vec<u8>,
76}
77
78#[derive(Debug, Clone, PartialEq)]
81pub struct VerifiedObject {
82 pub key: Vec<u8>,
83 pub tbs: Vec<u8>,
84 pub fields: Value,
85}
86
87impl Object {
88 pub fn to_value(&self) -> Value {
90 Value::Map(vec![
91 (Value::text("key"), Value::Bytes(self.key.clone())),
92 (Value::text("tbs"), Value::Bytes(self.tbs.clone())),
93 (
94 Value::text("signature"),
95 Value::Bytes(self.signature.clone()),
96 ),
97 ])
98 }
99
100 pub fn from_value(value: &Value) -> Result<Object, ObjectError> {
103 let [key, tbs, signature] = exact_byte_fields(value, ["key", "tbs", "signature"])?;
104 Ok(Object {
105 key,
106 tbs,
107 signature,
108 })
109 }
110}
111
112impl HeldObject {
113 pub fn to_value(&self) -> Value {
115 Value::Map(vec![
116 (Value::text("tbs"), Value::Bytes(self.tbs.clone())),
117 (
118 Value::text("signature"),
119 Value::Bytes(self.signature.clone()),
120 ),
121 ])
122 }
123
124 pub fn from_value(value: &Value) -> Result<HeldObject, ObjectError> {
127 let [tbs, signature] = exact_byte_fields(value, ["tbs", "signature"])?;
128 Ok(HeldObject { tbs, signature })
129 }
130}
131
132pub fn sign_object(
135 label: &str,
136 fields: &[(Value, Value)],
137 key: &NodeKey,
138) -> Result<Object, ObjectError> {
139 let carried = key.public_key();
140 let tbs = object_tbs(fields, key.profile())?;
141 let signature = key
142 .sign(&object_signed_bytes(label, &carried, &tbs))
143 .map_err(ObjectError::Key)?;
144 Ok(Object {
145 key: carried,
146 tbs,
147 signature,
148 })
149}
150
151pub fn sign_held_object(
153 label: &str,
154 fields: &[(Value, Value)],
155 key: &NodeKey,
156) -> Result<HeldObject, ObjectError> {
157 let object = sign_object(label, fields, key)?;
158 Ok(HeldObject {
159 tbs: object.tbs,
160 signature: object.signature,
161 })
162}
163
164pub fn verify_object(
170 label: &str,
171 value: &Value,
172 profile: Profile,
173) -> Result<VerifiedObject, ObjectError> {
174 let object = Object::from_value(value)?;
175 if !carried_key_well_formed(&object.key, profile) {
176 return Err(ObjectError::Malformed);
177 }
178 verified(label, object.key, object.tbs, &object.signature, profile)
179}
180
181pub fn verify_object_by_alg(
190 label: &str,
191 value: &Value,
192 profile: Profile,
193) -> Result<VerifiedObject, ObjectError> {
194 let object = Object::from_value(value)?;
195 let fields = cbor::decode(&object.tbs).map_err(|_| ObjectError::Malformed)?;
196 let alg = match (&fields, fields.get("alg")) {
197 (Value::Map(_), Some(Value::Text(alg))) => alg.clone(),
198 _ => return Err(ObjectError::Malformed),
199 };
200 if alg != profile.sig_alg() {
201 return Err(ObjectError::AlgUnsupported(alg));
202 }
203 if !carried_key_well_formed(&object.key, profile) {
204 return Err(ObjectError::Malformed);
205 }
206 let signed = object_signed_bytes(label, &object.key, &object.tbs);
207 if !verify(&signed, &object.signature, &object.key, profile) {
208 return Err(ObjectError::SignatureInvalid);
209 }
210 Ok(VerifiedObject {
211 key: object.key,
212 tbs: object.tbs,
213 fields,
214 })
215}
216
217pub fn verify_held_object(
220 label: &str,
221 value: &Value,
222 key: &[u8],
223 profile: Profile,
224) -> Result<VerifiedObject, ObjectError> {
225 let held = HeldObject::from_value(value)?;
226 verified(label, key.to_vec(), held.tbs, &held.signature, profile)
227}
228
229fn verified(
230 label: &str,
231 key: Vec<u8>,
232 tbs: Vec<u8>,
233 signature: &[u8],
234 profile: Profile,
235) -> Result<VerifiedObject, ObjectError> {
236 if !verify(
237 &object_signed_bytes(label, &key, &tbs),
238 signature,
239 &key,
240 profile,
241 ) {
242 return Err(ObjectError::SignatureInvalid);
243 }
244 let fields = cbor::decode(&tbs).map_err(|_| ObjectError::Malformed)?;
245 let alg = match (&fields, fields.get("alg")) {
246 (Value::Map(_), Some(Value::Text(alg))) => alg.clone(),
247 _ => return Err(ObjectError::Malformed),
248 };
249 if alg != profile.sig_alg() {
250 return Err(ObjectError::AlgMismatch);
251 }
252 Ok(VerifiedObject { key, tbs, fields })
253}
254
255fn object_tbs(fields: &[(Value, Value)], profile: Profile) -> Result<Vec<u8>, ObjectError> {
257 let mut seen = std::collections::HashSet::with_capacity(fields.len());
258 let mut with_alg = Vec::with_capacity(fields.len() + 1);
259 for (key, value) in fields {
260 let Value::Text(name) = key else {
261 return Err(ObjectError::FieldKeyNotText);
262 };
263 if seen.contains(name.as_str()) {
264 return Err(ObjectError::DuplicateField(name.clone()));
265 }
266 if name == "alg" {
267 continue;
268 }
269 seen.insert(name.as_str());
270 with_alg.push((key.clone(), value.clone()));
271 }
272 with_alg.push((Value::text("alg"), Value::text(profile.sig_alg())));
273 cbor::encode(&Value::Map(with_alg)).map_err(|_| ObjectError::Malformed)
274}
275
276fn object_signed_bytes(label: &str, key: &[u8], tbs: &[u8]) -> Vec<u8> {
279 let mut out = Vec::with_capacity(label.len() + 1 + 48 + tbs.len());
280 out.extend_from_slice(label.as_bytes());
281 out.push(0);
282 out.extend_from_slice(&Sha384::digest(key));
283 out.extend_from_slice(tbs);
284 out
285}
286
287fn exact_byte_fields<const N: usize>(
290 value: &Value,
291 names: [&str; N],
292) -> Result<[Vec<u8>; N], ObjectError> {
293 let Value::Map(pairs) = value else {
294 return Err(ObjectError::Malformed);
295 };
296 if pairs.len() != N {
297 return Err(ObjectError::Malformed);
298 }
299 let mut out: [Vec<u8>; N] = std::array::from_fn(|_| Vec::new());
300 for (slot, name) in out.iter_mut().zip(names) {
301 match value.get(name) {
302 Some(Value::Bytes(b)) => *slot = b.clone(),
303 _ => return Err(ObjectError::Malformed),
304 }
305 }
306 Ok(out)
307}
308
309#[cfg(test)]
310mod wire_1_0_tests {
311 use super::*;
318 use crate::wire_vectors::{self, hex_of, typed};
319
320 #[test]
321 fn the_wire_1_0_tbs_vectors() {
322 let file = wire_vectors::load("tbs");
323 for c in &file.cases {
324 let profile = Profile::parse(&c.profile).unwrap();
325 let key = wire_vectors::key(&c.profile, c.text("signer"));
326 let tbs = cbor::encode(&typed(&c.input["fields"])).unwrap();
327 assert_eq!(hex::encode(&tbs), c.expect_text("tbs"), "{}: the tbs", c.id);
328 let input = match c.text("form") {
329 "keyed" => object_signed_bytes(c.text("label"), &key, &tbs),
330 _ => crate::binding::labelled(c.text("label"), &tbs),
331 };
332 assert_eq!(
333 hex::encode(&input),
334 c.expect_text("signing_input"),
335 "{}",
336 c.id
337 );
338 let signature = hex_of(&c.expect["signature"]);
339 assert!(
340 verify(&input, &signature, &key, profile),
341 "{}: the signature",
342 c.id
343 );
344 }
345 assert_eq!(file.cases.len(), 30);
346 }
347}