atlas_c2pa_lib/cose.rs
1//! # COSE Module
2//!
3//! This module provides functions for cryptographic operations on C2PA claims using the COSE
4//! (CBOR Object Signing and Encryption) standard. It enables signing and verification of claims
5//! to ensure their authenticity and integrity, with support for multiple hash algorithms.
6//!
7//! ## Supported Hash Algorithms
8//!
9//! The module supports the following hash algorithms as per C2PA specification:
10//! - SHA-256 (`sha256`)
11//! - SHA-384 (`sha384`)
12//! - SHA-512 (`sha512`)
13//!
14//! ## Functionality
15//!
16//! The module provides the following functions:
17//!
18//! - **sign_claim**: Signs a CBOR-encoded claim using SHA-384 (default)
19//! - **sign_claim_with_algorithm**: Signs a CBOR-encoded claim using a specified hash algorithm
20//! - **verify_signed_claim**: Verifies a signed claim using SHA-384 (default)
21//! - **verify_signed_claim_with_algorithm**: Verifies a signed claim using a specified hash algorithm
22//!
23//! ## Example: Signing a Claim with Default SHA-384
24//!
25//! ```rust,ignore
26//! use atlas_c2pa_lib::cbor::encode_claim_to_cbor;
27//! use atlas_c2pa_lib::cose::sign_claim;
28//! use openssl::pkey::PKey;
29//!
30//! // Create and encode a claim to CBOR
31//! let claim = create_claim(); // Your claim creation logic
32//! let cbor_data = encode_claim_to_cbor(&claim).unwrap();
33//!
34//! // Load a private key (key generation is the responsibility of the end user)
35//! let private_key_pem = std::fs::read("private_key.pem").unwrap();
36//! let private_key = PKey::private_key_from_pem(&private_key_pem).unwrap();
37//!
38//! // Sign the claim using default SHA-384
39//! let signed_data = sign_claim(&cbor_data, &private_key).unwrap();
40//! ```
41//!
42//! ## Example: Signing with Different Hash Algorithms
43//!
44//! ```rust,ignore
45//! use atlas_c2pa_lib::cbor::encode_claim_to_cbor;
46//! use atlas_c2pa_lib::cose::{sign_claim_with_algorithm, HashAlgorithm};
47//! use openssl::pkey::PKey;
48//!
49//! // Create and encode a claim to CBOR
50//! let claim = create_claim(); // Your claim creation logic
51//! let cbor_data = encode_claim_to_cbor(&claim).unwrap();
52//!
53//! // Load a private key (key generation is the responsibility of the end user)
54//! let private_key_pem = std::fs::read("private_key.pem").unwrap();
55//! let private_key = PKey::private_key_from_pem(&private_key_pem).unwrap();
56//!
57//! // Sign with SHA-384
58//! let signed_sha384 = sign_claim_with_algorithm(
59//! &cbor_data,
60//! &private_key,
61//! HashAlgorithm::Sha384
62//! ).unwrap();
63//!
64//! // Sign with SHA-512
65//! let signed_sha512 = sign_claim_with_algorithm(
66//! &cbor_data,
67//! &private_key,
68//! HashAlgorithm::Sha512
69//! ).unwrap();
70//! ```
71//!
72//! ## Example: Verifying a Signed Claim
73//!
74//! ```rust,ignore
75//! use atlas_c2pa_lib::cose::{verify_signed_claim, verify_signed_claim_with_algorithm, HashAlgorithm};
76//! use openssl::pkey::PKey;
77//!
78//! // Load a public key
79//! let public_key_pem = std::fs::read("public_key.pem").unwrap();
80//! let public_key = PKey::public_key_from_pem(&public_key_pem).unwrap();
81//!
82//! // Verify a claim signed with SHA-256 (default)
83//! let verification_result = verify_signed_claim(&signed_data, &public_key);
84//! assert!(verification_result.is_ok());
85//!
86//! // Verify a claim signed with SHA-384
87//! let verification_sha384 = verify_signed_claim_with_algorithm(
88//! &signed_sha384,
89//! &public_key,
90//! HashAlgorithm::Sha384
91//! );
92//! assert!(verification_sha384.is_ok());
93//! ```
94//!
95//! ## Example: Complete Signing and Verification Workflow
96//!
97//! ```rust,ignore
98//! use atlas_c2pa_lib::claim::ClaimV2;
99//! use atlas_c2pa_lib::cbor::encode_claim_to_cbor;
100//! use atlas_c2pa_lib::cose::{sign_claim_with_algorithm, verify_signed_claim_with_algorithm, HashAlgorithm};
101//! use atlas_c2pa_lib::datetime_wrapper::OffsetDateTimeWrapper;
102//! use openssl::pkey::PKey;
103//! use time::OffsetDateTime;
104//!
105//! // Create a claim
106//! let claim = ClaimV2 {
107//! instance_id: "xmp:iid:123456".to_string(),
108//! created_assertions: vec![],
109//! ingredients: vec![],
110//! signature: None,
111//! claim_generator_info: "atlas_c2pa_lib/0.1.4".to_string(),
112//! created_at: OffsetDateTimeWrapper(OffsetDateTime::now_utc()),
113//! };
114//!
115//! // Encode to CBOR
116//! let cbor_data = encode_claim_to_cbor(&claim).unwrap();
117//!
118//! // Load pre-generated keys (key generation is the responsibility of the end user)
119//! let private_key_pem = std::fs::read("private_key.pem").unwrap();
120//! let private_key = PKey::private_key_from_pem(&private_key_pem).unwrap();
121//!
122//! let public_key_pem = std::fs::read("public_key.pem").unwrap();
123//! let public_key = PKey::public_key_from_pem(&public_key_pem).unwrap();
124//!
125//! // Try all supported algorithms
126//! let algorithms = vec![
127//! HashAlgorithm::Sha256,
128//! HashAlgorithm::Sha384,
129//! HashAlgorithm::Sha512,
130//! ];
131//!
132//! for algo in algorithms {
133//! // Sign the claim
134//! let signed = sign_claim_with_algorithm(&cbor_data, &private_key, algo.clone()).unwrap();
135//!
136//! // Verify the signature
137//! let result = verify_signed_claim_with_algorithm(&signed, &public_key, algo);
138//! assert!(result.is_ok(), "Verification failed for {:?}", algo);
139//! }
140//! ```
141//!
142//! ## Security Considerations
143//!
144//! - **Key Generation**: The generation and management of cryptographic key pairs is the
145//! responsibility of the end user. This library does not provide key generation functionality.
146//! Users should follow cryptographic best practices for key generation, storage, and rotation.
147//! - Private keys should be securely stored and never exposed
148//! - Public keys should be distributed through secure channels
149//! - The signature verification process ensures the claim hasn't been tampered with
150//! - COSE provides a standardized way to represent signed data in CBOR format
151//! - Choose the appropriate hash algorithm based on your security requirements:
152//! - SHA-256: Good balance of security and performance
153//! - SHA-384: Higher security with moderate performance impact
154//! - SHA-512: Highest security but larger signatures
155
156use coset::{CborSerializable, CoseSign1, CoseSign1Builder, Header};
157use openssl::hash::MessageDigest;
158use openssl::pkey::PKey;
159use openssl::sign::{Signer, Verifier};
160use std::str::FromStr;
161
162/// Supported hash algorithms for COSE signing and verification
163#[derive(Debug, PartialEq, Clone)]
164pub enum HashAlgorithm {
165 /// SHA-256 hash algorithm (256-bit)
166 Sha256,
167 /// SHA-384 hash algorithm (384-bit)
168 Sha384,
169 /// SHA-512 hash algorithm (512-bit)
170 Sha512,
171}
172
173impl HashAlgorithm {
174 /// Convert the hash algorithm to OpenSSL MessageDigest
175 fn to_message_digest(&self) -> MessageDigest {
176 match self {
177 HashAlgorithm::Sha256 => MessageDigest::sha256(),
178 HashAlgorithm::Sha384 => MessageDigest::sha384(),
179 HashAlgorithm::Sha512 => MessageDigest::sha512(),
180 }
181 }
182
183 /// Get the string representation of the algorithm
184 pub fn as_str(&self) -> &'static str {
185 match self {
186 HashAlgorithm::Sha256 => "sha256",
187 HashAlgorithm::Sha384 => "sha384",
188 HashAlgorithm::Sha512 => "sha512",
189 }
190 }
191}
192// Implement the standard FromStr trait
193impl FromStr for HashAlgorithm {
194 type Err = String;
195
196 fn from_str(s: &str) -> Result<Self, Self::Err> {
197 match s {
198 "sha256" => Ok(HashAlgorithm::Sha256),
199 "sha384" => Ok(HashAlgorithm::Sha384),
200 "sha512" => Ok(HashAlgorithm::Sha512),
201 _ => Err(format!(
202 "Unsupported hash algorithm: {s}. Supported algorithms are: sha256, sha384, sha512"
203 )),
204 }
205 }
206}
207/// Signs a CBOR-encoded claim using the specified hash algorithm.
208///
209/// # Arguments
210///
211/// * `claim_cbor` - The CBOR-encoded claim data to sign
212/// * `private_key` - The private key used for signing
213/// * `algorithm` - The hash algorithm to use for signing
214///
215/// # Returns
216///
217/// * `Ok(Vec<u8>)` - The signed COSE structure as a byte array
218/// * `Err(String)` - Error message if signing fails
219///
220/// # Example
221///
222/// ```rust,ignore
223/// use atlas_c2pa_lib::cose::{sign_claim_with_algorithm, HashAlgorithm};
224/// use openssl::pkey::PKey;
225///
226/// let private_key = PKey::private_key_from_pem(&key_pem).unwrap();
227/// let signed = sign_claim_with_algorithm(
228/// &cbor_data,
229/// &private_key,
230/// HashAlgorithm::Sha384
231/// ).unwrap();
232/// ```
233pub fn sign_claim_with_algorithm(
234 claim_cbor: &[u8],
235 private_key: &PKey<openssl::pkey::Private>,
236 algorithm: HashAlgorithm,
237) -> Result<Vec<u8>, String> {
238 // Create a COSE Sign1 builder with the payload (claim_cbor)
239 let sign1_builder = CoseSign1Builder::new()
240 .payload(claim_cbor.to_vec()) // Set the payload to be signed
241 .protected(Header::default()); // Add a protected header
242
243 // Sign the payload using the provided private key and algorithm
244 let mut signer = Signer::new(algorithm.to_message_digest(), private_key).map_err(|e| {
245 format!(
246 "[COSE] Failed to create signer with {} algorithm: {} (check if private key is valid)",
247 algorithm.as_str(),
248 e
249 )
250 })?;
251
252 // Feed the payload into the signer
253 signer.update(claim_cbor).map_err(|e| {
254 format!(
255 "[COSE] Failed to update signer with payload: {} (payload size: {} bytes)",
256 e,
257 claim_cbor.len()
258 )
259 })?;
260
261 // Generate the signature
262 let signature = signer.sign_to_vec().map_err(|e| {
263 format!(
264 "[COSE] Failed to generate signature with {}: {}",
265 algorithm.as_str(),
266 e
267 )
268 })?;
269
270 // Add the signature to the COSE Sign1 structure
271 let sign1 = sign1_builder.signature(signature).build();
272
273 // Serialize the signed COSE structure to a byte array (CBOR format)
274 sign1
275 .to_vec()
276 .map_err(|e| format!("[COSE] Failed to serialize signed claim: {e}"))
277}
278
279/// Signs a CBOR-encoded claim using the default SHA-384 algorithm.
280///
281/// This function is provided for backward compatibility and convenience.
282/// It internally calls `sign_claim_with_algorithm` with SHA-384.
283///
284/// # Arguments
285///
286/// * `claim_cbor` - The CBOR-encoded claim data to sign
287/// * `private_key` - The private key used for signing
288///
289/// # Returns
290///
291/// * `Ok(Vec<u8>)` - The signed COSE structure as a byte array
292/// * `Err(String)` - Error message if signing fails
293///
294/// # Example
295///
296/// ```rust,ignore
297/// use atlas_c2pa_lib::cose::sign_claim;
298/// use openssl::pkey::PKey;
299///
300/// let private_key = PKey::private_key_from_pem(&key_pem).unwrap();
301/// let signed = sign_claim(&cbor_data, &private_key).unwrap();
302/// ```
303pub fn sign_claim(
304 claim_cbor: &[u8],
305 private_key: &PKey<openssl::pkey::Private>,
306) -> Result<Vec<u8>, String> {
307 sign_claim_with_algorithm(claim_cbor, private_key, HashAlgorithm::Sha384)
308}
309
310/// Verifies a signed claim using the specified hash algorithm.
311///
312/// # Arguments
313///
314/// * `signed_claim` - The signed COSE structure to verify
315/// * `public_key` - The public key used for verification
316/// * `algorithm` - The hash algorithm that was used for signing
317///
318/// # Returns
319///
320/// * `Ok(())` - If the signature is valid
321/// * `Err(String)` - Error message if verification fails
322///
323/// # Example
324///
325/// ```rust,ignore
326/// use atlas_c2pa_lib::cose::{verify_signed_claim_with_algorithm, HashAlgorithm};
327/// use openssl::pkey::PKey;
328///
329/// let public_key = PKey::public_key_from_pem(&key_pem).unwrap();
330/// let result = verify_signed_claim_with_algorithm(
331/// &signed_data,
332/// &public_key,
333/// HashAlgorithm::Sha384
334/// );
335/// assert!(result.is_ok());
336/// ```
337pub fn verify_signed_claim_with_algorithm(
338 signed_claim: &[u8],
339 public_key: &PKey<openssl::pkey::Public>,
340 algorithm: HashAlgorithm,
341) -> Result<(), String> {
342 // Parse the COSE-encoded signed claim
343 let sign1 = CoseSign1::from_slice(signed_claim)
344 .map_err(|e| format!("Failed to parse signed claim: {e}"))?;
345
346 // Get the payload (the signed data)
347 let payload = sign1
348 .payload
349 .as_ref()
350 .ok_or("No payload found in signed claim")?;
351
352 // Extract the signature from the COSE structure
353 let signature: &[u8] = &sign1.signature;
354
355 // Initialize the verifier with the public key and the specified algorithm
356 let mut verifier = Verifier::new(algorithm.to_message_digest(), public_key).map_err(|e| {
357 format!(
358 "Failed to create verifier with {} algorithm: {}",
359 algorithm.as_str(),
360 e
361 )
362 })?;
363
364 // Feed the payload (the data that was signed) into the verifier
365 verifier
366 .update(payload)
367 .map_err(|e| format!("Failed to update verifier with payload: {e}"))?;
368
369 // Verify the signature using the public key
370 if verifier
371 .verify(signature)
372 .map_err(|e| format!("Verification failed with {}: {}", algorithm.as_str(), e))?
373 {
374 Ok(()) // Signature is valid
375 } else {
376 Err(format!(
377 "Invalid signature for {} algorithm",
378 algorithm.as_str()
379 )) // Signature is invalid
380 }
381}
382
383/// Verifies a signed claim using the default SHA-384 algorithm.
384///
385/// This function is provided for backward compatibility and convenience.
386/// It internally calls `verify_signed_claim_with_algorithm` with SHA-384.
387///
388/// # Arguments
389///
390/// * `signed_claim` - The signed COSE structure to verify
391/// * `public_key` - The public key used for verification
392///
393/// # Returns
394///
395/// * `Ok(())` - If the signature is valid
396/// * `Err(String)` - Error message if verification fails
397///
398/// # Example
399///
400/// ```rust,ignore
401/// use atlas_c2pa_lib::cose::verify_signed_claim;
402/// use openssl::pkey::PKey;
403///
404/// let public_key = PKey::public_key_from_pem(&key_pem).unwrap();
405/// let result = verify_signed_claim(&signed_data, &public_key);
406/// assert!(result.is_ok());
407/// ```
408pub fn verify_signed_claim(
409 signed_claim: &[u8],
410 public_key: &PKey<openssl::pkey::Public>,
411) -> Result<(), String> {
412 verify_signed_claim_with_algorithm(signed_claim, public_key, HashAlgorithm::Sha384)
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418 use openssl::pkey::PKey;
419 use openssl::rsa::Rsa;
420
421 // Helper function to generate a test key pair
422 fn generate_test_keypair() -> (PKey<openssl::pkey::Private>, PKey<openssl::pkey::Public>) {
423 let rsa = Rsa::generate(2048).expect("Failed to generate RSA key");
424 let private_key = PKey::from_rsa(rsa.clone()).expect("Failed to create private key");
425 let public_key_rsa = rsa
426 .public_key_to_pem()
427 .expect("Failed to export public key");
428 let public_key =
429 PKey::public_key_from_pem(&public_key_rsa).expect("Failed to create public key");
430 (private_key, public_key)
431 }
432
433 #[test]
434 fn test_hash_algorithm_conversions() {
435 use std::str::FromStr;
436
437 // Test as_str()
438 assert_eq!(HashAlgorithm::Sha256.as_str(), "sha256");
439 assert_eq!(HashAlgorithm::Sha384.as_str(), "sha384");
440 assert_eq!(HashAlgorithm::Sha512.as_str(), "sha512");
441
442 // Test from_str() - valid cases
443 assert!(matches!(
444 HashAlgorithm::from_str("sha256").unwrap(),
445 HashAlgorithm::Sha256
446 ));
447 assert!(matches!(
448 HashAlgorithm::from_str("sha384").unwrap(),
449 HashAlgorithm::Sha384
450 ));
451 assert!(matches!(
452 HashAlgorithm::from_str("sha512").unwrap(),
453 HashAlgorithm::Sha512
454 ));
455
456 // Can also use the parse method that comes with FromStr
457 assert!(matches!(
458 "sha256".parse::<HashAlgorithm>().unwrap(),
459 HashAlgorithm::Sha256
460 ));
461
462 // Test from_str() - invalid cases
463 assert!(HashAlgorithm::from_str("sha1").is_err());
464 assert!(HashAlgorithm::from_str("md5").is_err());
465 assert!(HashAlgorithm::from_str("SHA256").is_err()); // Case sensitive
466 assert!(HashAlgorithm::from_str("").is_err());
467 }
468
469 #[test]
470 fn test_sign_and_verify_with_sha256() {
471 let (private_key, public_key) = generate_test_keypair();
472 let test_data = b"Test claim data for SHA-256";
473
474 // Sign with SHA-256
475 let signed = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha256)
476 .expect("Failed to sign with SHA-256");
477
478 // Verify with SHA-256
479 assert!(
480 verify_signed_claim_with_algorithm(&signed, &public_key, HashAlgorithm::Sha256).is_ok(),
481 "Failed to verify SHA-256 signature"
482 );
483
484 // Verify with wrong algorithm should fail
485 assert!(
486 verify_signed_claim_with_algorithm(&signed, &public_key, HashAlgorithm::Sha384)
487 .is_err(),
488 "Verification should fail with wrong algorithm"
489 );
490 }
491
492 #[test]
493 fn test_sign_and_verify_with_sha384() {
494 let (private_key, public_key) = generate_test_keypair();
495 let test_data = b"Test claim data for SHA-384";
496
497 // Sign with SHA-384
498 let signed = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha384)
499 .expect("Failed to sign with SHA-384");
500
501 // Verify with SHA-384
502 assert!(
503 verify_signed_claim_with_algorithm(&signed, &public_key, HashAlgorithm::Sha384).is_ok(),
504 "Failed to verify SHA-384 signature"
505 );
506
507 // Verify with wrong algorithm should fail
508 assert!(
509 verify_signed_claim_with_algorithm(&signed, &public_key, HashAlgorithm::Sha512)
510 .is_err(),
511 "Verification should fail with wrong algorithm"
512 );
513 }
514
515 #[test]
516 fn test_sign_and_verify_with_sha512() {
517 let (private_key, public_key) = generate_test_keypair();
518 let test_data = b"Test claim data for SHA-512";
519
520 // Sign with SHA-512
521 let signed = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha512)
522 .expect("Failed to sign with SHA-512");
523
524 // Verify with SHA-512
525 assert!(
526 verify_signed_claim_with_algorithm(&signed, &public_key, HashAlgorithm::Sha512).is_ok(),
527 "Failed to verify SHA-512 signature"
528 );
529
530 // Verify with wrong algorithm should fail
531 assert!(
532 verify_signed_claim_with_algorithm(&signed, &public_key, HashAlgorithm::Sha256)
533 .is_err(),
534 "Verification should fail with wrong algorithm"
535 );
536 }
537
538 #[test]
539 fn test_default_functions_use_sha384() {
540 let (private_key, public_key) = generate_test_keypair();
541 let test_data = b"Test claim data for default algorithm";
542
543 // Sign with default function (should use SHA-384)
544 let signed_default =
545 sign_claim(test_data, &private_key).expect("Failed to sign with default algorithm");
546
547 // Sign explicitly with SHA-384
548 let signed_explicit =
549 sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha384)
550 .expect("Failed to sign with explicit SHA-384");
551
552 // Verify default signed data with SHA-384
553 assert!(
554 verify_signed_claim_with_algorithm(&signed_default, &public_key, HashAlgorithm::Sha384)
555 .is_ok(),
556 "Default sign_claim should use SHA-384"
557 );
558
559 // Verify default function can verify SHA-384 signatures
560 assert!(
561 verify_signed_claim(&signed_explicit, &public_key).is_ok(),
562 "Default verify_signed_claim should use SHA-384"
563 );
564
565 // Default verify should work with default sign
566 assert!(
567 verify_signed_claim(&signed_default, &public_key).is_ok(),
568 "Default functions should be compatible"
569 );
570 }
571
572 #[test]
573 fn test_signature_uniqueness() {
574 let (private_key, public_key) = generate_test_keypair();
575 let test_data = b"Test data for signature uniqueness";
576
577 // Sign the same data multiple times with the same algorithm
578 let sig1 = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha384)
579 .expect("Failed to sign 1");
580 let sig2 = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha384)
581 .expect("Failed to sign 2");
582
583 // Signatures might be different due to randomness in signing process
584 // But both should be valid
585 assert!(
586 verify_signed_claim_with_algorithm(&sig1, &public_key, HashAlgorithm::Sha384).is_ok(),
587 "First signature should be valid"
588 );
589 assert!(
590 verify_signed_claim_with_algorithm(&sig2, &public_key, HashAlgorithm::Sha384).is_ok(),
591 "Second signature should be valid"
592 );
593
594 // Sign with different algorithms
595 let sig_256 = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha256)
596 .expect("Failed to sign with SHA-256");
597 let sig_384 = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha384)
598 .expect("Failed to sign with SHA-384");
599 let sig_512 = sign_claim_with_algorithm(test_data, &private_key, HashAlgorithm::Sha512)
600 .expect("Failed to sign with SHA-512");
601
602 // Signatures with different algorithms should produce different results
603 assert_ne!(
604 sig_256, sig_384,
605 "SHA-256 and SHA-384 signatures should differ"
606 );
607 assert_ne!(
608 sig_384, sig_512,
609 "SHA-384 and SHA-512 signatures should differ"
610 );
611 assert_ne!(
612 sig_256, sig_512,
613 "SHA-256 and SHA-512 signatures should differ"
614 );
615 }
616
617 #[test]
618 fn test_empty_data_signing() {
619 let (private_key, public_key) = generate_test_keypair();
620 let empty_data = b"";
621
622 // Test all algorithms with empty data
623 for algo in [
624 HashAlgorithm::Sha256,
625 HashAlgorithm::Sha384,
626 HashAlgorithm::Sha512,
627 ] {
628 let signed = sign_claim_with_algorithm(empty_data, &private_key, algo.clone())
629 .unwrap_or_else(|_| panic!("Failed to sign empty data with {algo:?}"));
630
631 assert!(
632 verify_signed_claim_with_algorithm(&signed, &public_key, algo.clone()).is_ok(),
633 "Failed to verify empty data signature with {algo:?}"
634 );
635 }
636 }
637
638 #[test]
639 fn test_large_data_signing() {
640 let (private_key, public_key) = generate_test_keypair();
641 // Create 1MB of test data
642 let large_data = vec![0x42u8; 1024 * 1024];
643
644 // Test with SHA-384 (default)
645 let signed = sign_claim(&large_data, &private_key).expect("Failed to sign large data");
646
647 assert!(
648 verify_signed_claim(&signed, &public_key).is_ok(),
649 "Failed to verify large data signature"
650 );
651 }
652
653 #[test]
654 fn test_verification_with_wrong_key() {
655 let (private_key1, _) = generate_test_keypair();
656 let (_, public_key2) = generate_test_keypair();
657 let test_data = b"Test data for wrong key verification";
658
659 // Sign with key1
660 let signed = sign_claim_with_algorithm(test_data, &private_key1, HashAlgorithm::Sha384)
661 .expect("Failed to sign");
662
663 // Verify with key2 should fail
664 assert!(
665 verify_signed_claim_with_algorithm(&signed, &public_key2, HashAlgorithm::Sha384)
666 .is_err(),
667 "Verification should fail with wrong public key"
668 );
669 }
670}