atlas_cli/in_toto/dsse.rs
1//! # Dead Simple Signing Envelope (DSSE) Implementation
2//!
3//! This module provides a Rust implementation of the [Dead Simple Signing Envelope (DSSE)
4//! specification](https://github.com/secure-systems-lab/dsse/blob/master/envelope.md),
5//! which is a standard format for signing arbitrary payloads. DSSE is commonly
6//! used in software supply chain security frameworks, including in-toto and Sigstore.
7//!
8//! ## Overview
9//!
10//! DSSE defines a simple envelope format that contains:
11//! - A payload (the actual data being signed)
12//! - A payload type (describing the format of the payload)
13//! - One or more signatures over the payload
14//!
15//! The signing process follows a specific algorithm where the signature is computed over
16//! the concatenation of the payload type and the payload itself.
17//!
18//! ## Key Components
19//!
20//! - [`Envelope`] - The main DSSE container structure
21//! - [`Signature`] - Individual cryptographic signatures with optional key identifiers
22//!
23//! ## Examples
24//!
25//! ### Creating and Signing a DSSE Envelope with in-toto payload
26//!
27//! ```no_run
28//! use atlas_cli::in_toto::dsse::Envelope;
29//! use atlas_cli::signing::signable::Signable;
30//! use atlas_c2pa_lib::cose::HashAlgorithm;
31//! use std::path::PathBuf;
32//!
33//! // Create a new envelope with JSON-encoded in-toto payload
34//! let payload = br#"{"statement": "example"}"#.to_vec();
35//! let mut envelope = Envelope::new(&payload, "application/vnd.in-toto+json".to_string());
36//!
37//! // Sign the envelope (requires a valid private key file)
38//! envelope.sign(PathBuf::from("private_key.pem"), HashAlgorithm::Sha384).unwrap();
39//!
40//! // Validate the envelope structure
41//! assert!(envelope.validate());
42//! ```
43//!
44//! ### Manual Signature Management
45//!
46//! ```rust
47//! use atlas_cli::in_toto::dsse::Envelope;
48//!
49//! // Create a new envelope with arbitrary payload
50//! let mut envelope = Envelope::new(&vec![1,2,3], "text/plain".to_string());
51//!
52//! // Add signatures manually
53//! let signature_bytes = vec![0xab, 0xcd, 0xef, 0x01, 0x23];
54//! envelope.add_signature(signature_bytes, "key-identifier".to_string()).unwrap();
55//!
56//! assert!(envelope.validate());
57//! ```
58//!
59//! ## DSSE Specification Compliance
60//!
61//! This implementation follows the DSSE specification as defined at:
62//! <https://github.com/secure-systems-lab/dsse>
63//!
64//! The key aspects of DSSE compliance include:
65//! - Proper payload and payload type concatenation for signing
66//! - Base64 encoding of binary data in JSON serialization
67//! - Support for multiple signatures per envelope
68//! - Validation of required fields and signature integrity
69
70use crate::error::{Error, Result};
71use crate::signing;
72use crate::signing::signable::Signable;
73
74use atlas_c2pa_lib::cose::HashAlgorithm;
75use std::path::PathBuf;
76
77use serde::{Deserialize, Serialize};
78use serde_with::serde_as;
79
80/// A cryptographic signature with optional key identifier for DSSE envelopes.
81///
82/// This struct represents a single signature within a DSSE (Dead Simple Signing Envelope).
83/// It contains the base64-encoded signature bytes and an optional key identifier that
84/// can be used to identify which key was used for signing.
85///
86/// # Fields
87///
88/// * `sig` - The cryptographic signature bytes (base64-encoded in JSON)
89/// * `keyid` - Optional identifier for the signing key (can be empty)
90///
91/// # Examples
92///
93/// ```no_run
94/// use atlas_cli::in_toto::dsse::Signature;
95///
96/// // Create a new signature with some example bytes and a key identifier
97/// let signature_bytes = vec![0xde, 0xad, 0xbe, 0xef, 0x13, 0xe7, 0x1e, 0x37];
98/// let key_id = "signing-key-2024".to_string();
99/// let signature = Signature::new(signature_bytes.clone(), key_id.clone());
100///
101/// // Access the signature data
102/// assert_eq!(signature.sig(), &signature_bytes);
103/// assert_eq!(signature.keyid(), &key_id);
104///
105/// // Create a signature without a key identifier
106/// let anonymous_sig = Signature::new(vec![0x12, 0x34, 0x56], "".to_string());
107/// assert_eq!(anonymous_sig.keyid(), "");
108/// assert!(!anonymous_sig.sig().is_empty());
109/// ```
110#[serde_as]
111#[derive(Clone, Debug, Serialize, Deserialize)]
112pub struct Signature {
113 #[serde_as(as = "serde_with::base64::Base64")]
114 sig: Vec<u8>,
115 keyid: String,
116}
117
118impl Signature {
119 /// Creates a new signature with the provided signature bytes and key identifier.
120 ///
121 /// # Arguments
122 ///
123 /// * `sig` - The cryptographic signature as a byte vector
124 /// * `keyid` - String identifier for the key used to create the signature
125 ///
126 /// # Returns
127 ///
128 /// A new `Signature` instance.
129 pub fn new(sig: Vec<u8>, keyid: String) -> Self {
130 Self {
131 sig: sig,
132 keyid: keyid,
133 }
134 }
135
136 /// Returns a reference to the signature bytes.
137 ///
138 /// # Returns
139 ///
140 /// A slice containing the cryptographic signature bytes.
141 ///
142 /// # Examples
143 ///
144 /// ```
145 /// use atlas_cli::in_toto::dsse::Signature;
146 ///
147 /// let sig_bytes = vec![0xab, 0xcd, 0xef];
148 /// let signature = Signature::new(sig_bytes.clone(), "key1".to_string());
149 /// assert_eq!(signature.sig(), &sig_bytes);
150 /// ```
151 pub fn sig(&self) -> &[u8] {
152 &self.sig
153 }
154
155 /// Returns a reference to the key identifier.
156 ///
157 /// # Returns
158 ///
159 /// A string slice containing the key identifier.
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// use atlas_cli::in_toto::dsse::Signature;
165 ///
166 /// let signature = Signature::new(vec![0xab, 0xcd], "test-key".to_string());
167 /// assert_eq!(signature.keyid(), "test-key");
168 /// ```
169 pub fn keyid(&self) -> &str {
170 &self.keyid
171 }
172}
173
174/// A DSSE (Dead Simple Signing Envelope) structure for signed payloads.
175///
176/// The Envelope represents a complete DSSE structure containing a payload, its type,
177/// and one or more cryptographic signatures. This structure follows the DSSE specification
178/// for creating tamper-evident, authenticated containers for arbitrary payloads.
179///
180/// # Fields
181///
182/// * `payload` - The actual data being signed (base64-encoded in JSON)
183/// * `payload_type` - MIME type or identifier describing the payload format
184/// * `signatures` - Vector of cryptographic signatures over the payload
185///
186/// # Examples
187///
188/// ```no_run
189/// use atlas_cli::in_toto::dsse::Envelope;
190///
191/// let payload = b"Hello, world!".to_vec();
192/// let mut envelope = Envelope::new(&payload, "text/plain".to_string());
193///
194/// // Add signatures using the sign() method from Signable trait
195/// // envelope.sign(key_path, hash_algorithm)?;
196///
197/// assert!(envelope.validate());
198/// ```
199#[serde_as]
200#[derive(Clone, Debug, Serialize, Deserialize)]
201pub struct Envelope {
202 #[serde_as(as = "serde_with::base64::Base64")]
203 payload: Vec<u8>,
204 payload_type: String,
205 signatures: Vec<Signature>,
206}
207
208impl Envelope {
209 /// Creates a new DSSE envelope with the specified payload and type.
210 ///
211 /// The envelope is created without any signatures. Signatures must be added
212 /// separately using the `add_signature` method or the `sign` method from
213 /// the `Signable` trait.
214 ///
215 /// # Arguments
216 ///
217 /// * `payload` - The data to be contained in the envelope
218 /// * `payload_type` - String describing the payload format (e.g., MIME type)
219 ///
220 /// # Returns
221 ///
222 /// A new `Envelope` instance with an empty signatures vector.
223 ///
224 /// # Examples
225 ///
226 /// ```
227 /// use atlas_cli::in_toto::dsse::Envelope;
228 ///
229 /// let data = b"test payload".to_vec();
230 /// let envelope = Envelope::new(&data, "application/json".to_string());
231 /// assert_eq!(envelope.payload_type(), "application/json");
232 /// assert!(envelope.signatures().is_empty());
233 /// ```
234 pub fn new(payload: &Vec<u8>, payload_type: String) -> Self {
235 Self {
236 payload: payload.to_vec(),
237 payload_type: payload_type,
238 signatures: vec![],
239 }
240 }
241
242 /// Adds a signature to the envelope.
243 ///
244 /// This method appends a new signature to the envelope's signature list.
245 /// Each signature includes the signature bytes and an optional key identifier.
246 ///
247 /// # Arguments
248 ///
249 /// * `sig` - The cryptographic signature as a byte vector
250 /// * `keyid` - String identifier for the signing key (can be empty)
251 ///
252 /// # Returns
253 ///
254 /// `Ok(())` on success, or an error if the signature is invalid.
255 ///
256 /// # Errors
257 ///
258 /// Returns a `Signing` error if the signature bytes are empty.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use atlas_cli::in_toto::dsse::Envelope;
264 ///
265 /// let mut envelope = Envelope::new(&vec![1,2,3], "test".to_string());
266 /// let signature_bytes = vec![0xab, 0xcd, 0xef];
267 ///
268 /// envelope.add_signature(signature_bytes, "key-1".to_string()).unwrap();
269 /// assert_eq!(envelope.signatures().len(), 1);
270 /// ```
271 pub fn add_signature(&mut self, sig: Vec<u8>, keyid: String) -> Result<()> {
272 if sig.is_empty() {
273 return Err(Error::Signing("DSSE signature cannot be empty".to_string()));
274 }
275
276 let sig_struct = Signature::new(sig, keyid);
277 self.signatures.push(sig_struct);
278
279 Ok(())
280 }
281
282 /// Validates the envelope structure and contents.
283 ///
284 /// This method performs basic validation to ensure the envelope contains
285 /// all required fields and that signatures are properly formatted. It checks:
286 /// - Payload is not empty
287 /// - Payload type is specified
288 /// - At least one signature is present
289 /// - All signatures contain non-empty signature bytes
290 ///
291 /// # Returns
292 ///
293 /// `true` if the envelope is valid, `false` otherwise.
294 ///
295 /// # Examples
296 ///
297 /// ```
298 /// use atlas_cli::in_toto::dsse::Envelope;
299 ///
300 /// let mut envelope = Envelope::new(&vec![1,2,3], "test".to_string());
301 /// assert!(!envelope.validate()); // No signatures yet
302 ///
303 /// envelope.add_signature(vec![0xab, 0xcd], "key".to_string()).unwrap();
304 /// assert!(envelope.validate()); // Now valid
305 /// ```
306 pub fn validate(&self) -> bool {
307 // check for required envelope fields
308 if self.payload.is_empty() || self.payload_type.is_empty() || self.signatures.is_empty() {
309 return false;
310 }
311
312 // check required signature fields
313 for signature in &self.signatures {
314 if signature.sig.is_empty() {
315 return false;
316 }
317 }
318
319 true
320 }
321
322 /// Returns a reference to the payload bytes.
323 ///
324 /// # Returns
325 ///
326 /// A slice containing the raw payload data.
327 ///
328 /// # Examples
329 ///
330 /// ```
331 /// use atlas_cli::in_toto::dsse::Envelope;
332 ///
333 /// let payload = b"test data".to_vec();
334 /// let envelope = Envelope::new(&payload, "text/plain".to_string());
335 /// assert_eq!(envelope.payload(), &payload);
336 /// ```
337 pub fn payload(&self) -> &[u8] {
338 &self.payload
339 }
340
341 /// Returns a reference to the payload type.
342 ///
343 /// # Returns
344 ///
345 /// A string slice containing the payload type/MIME type.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// use atlas_cli::in_toto::dsse::Envelope;
351 ///
352 /// let envelope = Envelope::new(&vec![1,2,3], "application/json".to_string());
353 /// assert_eq!(envelope.payload_type(), "application/json");
354 /// ```
355 pub fn payload_type(&self) -> &str {
356 &self.payload_type
357 }
358
359 /// Returns a reference to the signatures vector.
360 ///
361 /// # Returns
362 ///
363 /// A slice containing all signatures in the envelope.
364 ///
365 /// # Examples
366 ///
367 /// ```
368 /// use atlas_cli::in_toto::dsse::Envelope;
369 ///
370 /// let mut envelope = Envelope::new(&vec![1,2,3], "test".to_string());
371 /// assert_eq!(envelope.signatures().len(), 0);
372 ///
373 /// envelope.add_signature(vec![0xab, 0xcd], "key1".to_string()).unwrap();
374 /// assert_eq!(envelope.signatures().len(), 1);
375 /// assert_eq!(envelope.signatures()[0].keyid(), "key1");
376 /// ```
377 pub fn signatures(&self) -> &[Signature] {
378 &self.signatures
379 }
380}
381
382/// Implementation of the `Signable` trait for DSSE envelopes.
383///
384/// This implementation allows envelopes to be signed using private keys and
385/// specified hash algorithms. The signing process follows the DSSE specification,
386/// which requires signing the concatenation of the payload type and payload.
387impl Signable for Envelope {
388 /// Signs the envelope using the provided private key and hash algorithm.
389 ///
390 /// This method implements the DSSE signing specification by:
391 /// 1. Loading the private key from the specified path
392 /// 2. Concatenating the payload type and payload bytes
393 /// 3. Creating a cryptographic signature over the concatenated data
394 /// 4. Adding the signature to the envelope
395 ///
396 /// # Arguments
397 ///
398 /// * `key_path` - Path to the private key file
399 /// * `hash_alg` - Hash algorithm to use for signing
400 ///
401 /// # Returns
402 ///
403 /// `Ok(())` on successful signing, or an error if signing fails.
404 ///
405 /// # Errors
406 ///
407 /// Returns an error if:
408 /// - Private key cannot be loaded
409 /// - Signing operation fails
410 /// - Signature cannot be added to the envelope
411 ///
412 /// # Examples
413 ///
414 /// ```no_run
415 /// use atlas_cli::in_toto::dsse::Envelope;
416 /// use atlas_cli::signing::signable::Signable;
417 /// use atlas_c2pa_lib::cose::HashAlgorithm;
418 /// use std::path::PathBuf;
419 ///
420 /// let mut envelope = Envelope::new(&vec![1,2,3], "test".to_string());
421 /// envelope.sign(PathBuf::from("private_key.pem"), HashAlgorithm::Sha384).unwrap();
422 /// assert!(envelope.validate());
423 /// ```
424 fn sign(&mut self, key_path: PathBuf, hash_alg: HashAlgorithm) -> Result<()> {
425 let private_key = signing::load_private_key(&key_path)?;
426
427 // DSSE requires that payload_type and payload be signed
428 // We assume the payload is public
429 let mut data_to_sign: Vec<u8> = Vec::new();
430 data_to_sign.extend_from_slice(&self.payload_type.clone().into_bytes());
431
432 // DSSE requires payload to be JSON bytes
433 data_to_sign.extend_from_slice(&self.payload);
434
435 // Use the signing module with the specified algorithm
436 let signature = signing::sign_data_with_algorithm(&data_to_sign, &private_key, &hash_alg)?;
437
438 self.add_signature(signature, "".to_string()) // keyid is optional
439 }
440}
441
442#[cfg(test)]
443mod tests {
444 use super::*;
445 use base64::Engine;
446 use base64::prelude::BASE64_STANDARD;
447 use serde_json::{from_slice, from_str, json, to_string, to_vec};
448
449 #[test]
450 fn test_signature_new() {
451 let sig_bytes = vec![0xde, 0xad, 0xbe, 0xef];
452 let keyid = "test-key".to_string();
453
454 let signature = Signature::new(sig_bytes.clone(), keyid.clone());
455
456 assert_eq!(signature.sig(), &sig_bytes);
457 assert_eq!(signature.keyid(), &keyid);
458 }
459
460 #[test]
461 fn test_signature_empty_keyid() {
462 let sig_bytes = vec![0x12, 0x34];
463 let signature = Signature::new(sig_bytes.clone(), "".to_string());
464
465 assert_eq!(signature.sig(), &sig_bytes);
466 assert_eq!(signature.keyid(), "");
467 }
468
469 #[test]
470 fn test_signature_getters() {
471 let sig_bytes = vec![0xab, 0xcd, 0xef, 0x01, 0x23];
472 let keyid = "signing-key-2024".to_string();
473 let signature = Signature::new(sig_bytes.clone(), keyid.clone());
474
475 assert_eq!(signature.sig().len(), 5);
476 assert_eq!(signature.sig()[0], 0xab);
477 assert_eq!(signature.keyid().len(), 16);
478 assert!(signature.keyid().contains("2024"));
479 }
480
481 #[test]
482 fn test_envelope_new() {
483 let payload = b"test payload".to_vec();
484 let payload_type = "text/plain".to_string();
485
486 let envelope = Envelope::new(&payload, payload_type.clone());
487
488 assert_eq!(envelope.payload(), &payload);
489 assert_eq!(envelope.payload_type(), &payload_type);
490 assert!(envelope.signatures().is_empty());
491 }
492
493 #[test]
494 fn test_envelope_add_signature_success() {
495 let mut envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
496 let sig_bytes = vec![0xab, 0xcd, 0xef];
497 let keyid = "key-1".to_string();
498
499 let result = envelope.add_signature(sig_bytes.clone(), keyid.clone());
500
501 assert!(result.is_ok());
502 assert_eq!(envelope.signatures().len(), 1);
503 assert_eq!(envelope.signatures()[0].sig(), &sig_bytes);
504 assert_eq!(envelope.signatures()[0].keyid(), &keyid);
505 }
506
507 #[test]
508 fn test_envelope_add_signature_empty_fails() {
509 let mut envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
510
511 let result = envelope.add_signature(vec![], "key-1".to_string());
512
513 assert!(result.is_err());
514 if let Err(Error::Signing(msg)) = result {
515 assert_eq!(msg, "DSSE signature cannot be empty");
516 }
517 assert_eq!(envelope.signatures().len(), 0);
518 }
519
520 #[test]
521 fn test_envelope_add_multiple_signatures() {
522 let mut envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
523
524 envelope
525 .add_signature(vec![0x01, 0x02], "key-1".to_string())
526 .unwrap();
527 envelope
528 .add_signature(vec![0x03, 0x04], "key-2".to_string())
529 .unwrap();
530 envelope
531 .add_signature(vec![0x05, 0x06], "".to_string())
532 .unwrap();
533
534 assert_eq!(envelope.signatures().len(), 3);
535 assert_eq!(envelope.signatures()[0].keyid(), "key-1");
536 assert_eq!(envelope.signatures()[1].keyid(), "key-2");
537 assert_eq!(envelope.signatures()[2].keyid(), "");
538 }
539
540 #[test]
541 fn test_envelope_validate_valid() {
542 let mut envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
543 envelope
544 .add_signature(vec![0xab, 0xcd], "key".to_string())
545 .unwrap();
546
547 assert!(envelope.validate());
548 }
549
550 #[test]
551 fn test_envelope_validate_no_signatures() {
552 let envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
553
554 assert!(!envelope.validate());
555 }
556
557 #[test]
558 fn test_envelope_validate_empty_payload() {
559 let mut envelope = Envelope::new(&vec![], "test".to_string());
560 envelope
561 .add_signature(vec![0xab, 0xcd], "key".to_string())
562 .unwrap();
563
564 assert!(!envelope.validate());
565 }
566
567 #[test]
568 fn test_envelope_validate_empty_payload_type() {
569 let mut envelope = Envelope::new(&vec![1, 2, 3], "".to_string());
570 envelope
571 .add_signature(vec![0xab, 0xcd], "key".to_string())
572 .unwrap();
573
574 assert!(!envelope.validate());
575 }
576
577 #[test]
578 fn test_envelope_validate_empty_signature_bytes() {
579 let mut envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
580 // Force add a signature with empty bytes by creating it directly
581 let empty_sig = Signature::new(vec![], "key".to_string());
582 envelope.signatures.push(empty_sig);
583
584 assert!(!envelope.validate());
585 }
586
587 #[test]
588 fn test_envelope_validate_mixed_signatures() {
589 let mut envelope = Envelope::new(&vec![1, 2, 3], "test".to_string());
590 envelope
591 .add_signature(vec![0xab, 0xcd], "key1".to_string())
592 .unwrap();
593 // Force add an empty signature
594 let empty_sig = Signature::new(vec![], "key2".to_string());
595 envelope.signatures.push(empty_sig);
596
597 assert!(!envelope.validate()); // Should fail due to empty signature
598 }
599
600 #[test]
601 fn test_envelope_getters() {
602 let payload = b"Hello, DSSE world!".to_vec();
603 let payload_type = "text/plain".to_string();
604 let mut envelope = Envelope::new(&payload, payload_type.clone());
605
606 // Test initial state
607 assert_eq!(envelope.payload(), &payload);
608 assert_eq!(envelope.payload_type(), &payload_type);
609 assert_eq!(envelope.signatures().len(), 0);
610
611 // Add signatures and test
612 envelope
613 .add_signature(vec![0x01, 0x02, 0x03], "key1".to_string())
614 .unwrap();
615 envelope
616 .add_signature(vec![0x04, 0x05, 0x06], "key2".to_string())
617 .unwrap();
618
619 assert_eq!(envelope.signatures().len(), 2);
620 assert_eq!(envelope.signatures()[0].keyid(), "key1");
621 assert_eq!(envelope.signatures()[1].keyid(), "key2");
622 }
623
624 #[test]
625 fn test_envelope_json_payload_type() {
626 let json_payload = json!({"field1": "hello", "field2": "world"});
627 let envelope = Envelope::new(
628 &to_vec(&json_payload).unwrap(),
629 "application/json".to_string(),
630 );
631
632 let deserialized_payload: serde_json::Value = from_slice(envelope.payload()).unwrap();
633
634 assert_eq!(envelope.payload_type(), "application/json");
635 assert_eq!(deserialized_payload["field1"], "hello");
636 }
637
638 #[test]
639 fn test_signature_serialization_fields() {
640 // Test that the signature has the expected structure for serialization
641 let sig_bytes = vec![0xde, 0xad, 0xbe, 0xef];
642 let keyid = "test-key-id".to_string();
643 let signature = Signature::new(sig_bytes.clone(), keyid.clone());
644
645 // Verify the signature maintains its data correctly
646 assert_eq!(signature.sig().len(), 4);
647 assert_eq!(signature.keyid().len(), 11);
648 assert_eq!(signature.sig(), &sig_bytes);
649 assert_eq!(signature.keyid(), &keyid);
650 }
651
652 #[test]
653 fn test_envelope_large_payload() {
654 // Test with a larger payload to ensure there are no size-related issues
655 let large_payload = vec![0x42; 10000]; // 10KB of 0x42 bytes
656 let envelope = Envelope::new(&large_payload, "application/test".to_string());
657
658 assert_eq!(envelope.payload().len(), 10000);
659 assert_eq!(envelope.payload()[0], 0x42);
660 assert_eq!(envelope.payload()[9999], 0x42);
661 assert_eq!(envelope.payload_type(), "application/test");
662 }
663
664 #[test]
665 fn test_envelope_json_serialization() {
666 let payload = json!({"field1": "hello", "field2": "world"});
667 let mut envelope =
668 Envelope::new(&to_vec(&payload).unwrap(), "application/json".to_string());
669 envelope
670 .add_signature(vec![0x01, 0x02, 0x03], "key1".to_string())
671 .unwrap();
672
673 // Serialize to JSON
674 let json_str = to_string(&envelope).unwrap();
675
676 // Check that the payload is valid base64 in the JSON
677 BASE64_STANDARD
678 .decode(
679 &from_str::<serde_json::Value>(&json_str).unwrap()["payload"]
680 .as_str()
681 .unwrap(),
682 )
683 .unwrap();
684
685 // Deserialize back
686 let deserialized: Envelope = serde_json::from_str(&json_str).unwrap();
687 let deserialized_payload: serde_json::Value = from_slice(deserialized.payload()).unwrap();
688
689 // Verify fields match
690 assert_eq!(deserialized_payload["field1"], "hello");
691 assert_eq!(deserialized.payload_type(), "application/json");
692 assert_eq!(deserialized.signatures().len(), 1);
693 assert_eq!(deserialized.signatures()[0].keyid(), "key1");
694 assert_eq!(deserialized.signatures()[0].sig(), &[0x01, 0x02, 0x03]);
695 }
696}