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}