Skip to main content

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