1pub mod audit;
23pub mod pkcs11;
24
25use crate::{DidDocument, DidError, DidResult, VerificationMethod};
26#[cfg(feature = "insecure-mock-kms")]
27use hmac::{Hmac, Mac};
28#[cfg(feature = "insecure-mock-kms")]
29use sha2::Sha256;
30#[cfg(feature = "insecure-mock-kms")]
31use std::collections::HashMap;
32#[cfg(feature = "insecure-mock-kms")]
33use std::sync::RwLock;
34
35#[cfg(feature = "insecure-mock-kms")]
36type HmacSha256 = Hmac<Sha256>;
37
38#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum KmsAlgorithm {
45 Ed25519,
46 EcP256,
47 EcP384,
48 Rsa2048,
49 Rsa4096,
50}
51
52impl KmsAlgorithm {
53 pub fn as_str(&self) -> &'static str {
55 match self {
56 Self::Ed25519 => "Ed25519",
57 Self::EcP256 => "EC_P256",
58 Self::EcP384 => "EC_P384",
59 Self::Rsa2048 => "RSA_2048",
60 Self::Rsa4096 => "RSA_4096",
61 }
62 }
63
64 pub fn key_size_bytes(&self) -> usize {
66 match self {
67 Self::Ed25519 => 32,
68 Self::EcP256 => 32,
69 Self::EcP384 => 48,
70 Self::Rsa2048 => 256,
71 Self::Rsa4096 => 512,
72 }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum KeyUsage {
79 SignVerify,
80 EncryptDecrypt,
81}
82
83#[derive(Debug, Clone)]
85pub struct KmsKeyMetadata {
86 pub key_id: String,
87 pub algorithm: KmsAlgorithm,
88 pub created_at: i64,
90 pub enabled: bool,
91 pub key_usage: KeyUsage,
92}
93
94#[cfg(feature = "insecure-mock-kms")]
99struct KmsKeyEntry {
100 metadata: KmsKeyMetadata,
101 private_key_bytes: Vec<u8>,
103}
104
105pub trait KmsBackend: Send + Sync {
111 fn create_key(&self, key_id: &str, algorithm: KmsAlgorithm) -> DidResult<KmsKeyMetadata>;
112
113 fn sign(&self, key_id: &str, data: &[u8]) -> DidResult<Vec<u8>>;
114
115 fn verify(&self, key_id: &str, data: &[u8], signature: &[u8]) -> DidResult<bool>;
116
117 fn get_public_key(&self, key_id: &str) -> DidResult<Vec<u8>>;
118
119 fn delete_key(&self, key_id: &str) -> DidResult<()>;
120
121 fn list_keys(&self) -> DidResult<Vec<KmsKeyMetadata>>;
122}
123
124#[cfg(feature = "insecure-mock-kms")]
131fn hmac_sign(private_key_bytes: &[u8], key_id: &str, data: &[u8]) -> Vec<u8> {
132 let mut mac =
133 HmacSha256::new_from_slice(private_key_bytes).expect("HMAC accepts any key length");
134 mac.update(key_id.as_bytes());
135 mac.update(data);
136 mac.finalize().into_bytes().to_vec()
137}
138
139#[cfg(feature = "insecure-mock-kms")]
144fn derive_key_bytes(key_id: &str, algorithm: &KmsAlgorithm) -> Vec<u8> {
145 use sha2::Digest;
146 let mut hasher = sha2::Sha256::new();
147 hasher.update(key_id.as_bytes());
148 hasher.update(algorithm.as_str().as_bytes());
149 let base = hasher.finalize().to_vec();
150 let mut key = Vec::with_capacity(algorithm.key_size_bytes());
152 let mut counter: u8 = 0;
153 while key.len() < algorithm.key_size_bytes() {
154 let mut h2 = sha2::Sha256::new();
155 h2.update(&base);
156 h2.update([counter]);
157 key.extend_from_slice(&h2.finalize());
158 counter = counter.wrapping_add(1);
159 }
160 key.truncate(algorithm.key_size_bytes());
161 key
162}
163
164#[cfg(feature = "insecure-mock-kms")]
166fn derive_public_key(private_key_bytes: &[u8]) -> Vec<u8> {
167 let half = private_key_bytes.len() / 2;
168 let mut pub_key = private_key_bytes[..half.max(1)].to_vec();
169 pub_key.reverse();
170 pub_key
171}
172
173#[cfg(feature = "insecure-mock-kms")]
174fn now_unix() -> i64 {
175 std::time::SystemTime::now()
176 .duration_since(std::time::UNIX_EPOCH)
177 .map(|d| d.as_secs() as i64)
178 .unwrap_or(0)
179}
180
181#[cfg(feature = "insecure-mock-kms")]
191#[derive(Debug, Clone, Copy)]
192pub struct InsecureAck(());
193
194#[cfg(feature = "insecure-mock-kms")]
195impl InsecureAck {
196 pub fn acknowledge_insecure() -> Self {
199 InsecureAck(())
200 }
201}
202
203#[cfg(feature = "insecure-mock-kms")]
204macro_rules! impl_mock_kms {
205 ($name:ident, $display:literal) => {
206 #[doc = concat!("INSECURE in-memory mock ", $display, " KMS backend (TEST ONLY).")]
207 pub struct $name {
211 keys: RwLock<HashMap<String, KmsKeyEntry>>,
212 }
213
214 impl $name {
215 pub fn new(_ack: InsecureAck) -> Self {
218 Self {
219 keys: RwLock::new(HashMap::new()),
220 }
221 }
222 }
223
224 impl KmsBackend for $name {
225 fn create_key(
226 &self,
227 key_id: &str,
228 algorithm: KmsAlgorithm,
229 ) -> DidResult<KmsKeyMetadata> {
230 let mut store = self
231 .keys
232 .write()
233 .map_err(|e| DidError::InternalError(format!("KMS lock poisoned: {}", e)))?;
234
235 if store.contains_key(key_id) {
236 return Err(DidError::InvalidKey(format!(
237 "Key '{}' already exists in {} KMS",
238 key_id, $display
239 )));
240 }
241
242 let private_key_bytes = derive_key_bytes(key_id, &algorithm);
243 let metadata = KmsKeyMetadata {
244 key_id: key_id.to_string(),
245 algorithm,
246 created_at: now_unix(),
247 enabled: true,
248 key_usage: KeyUsage::SignVerify,
249 };
250
251 let entry = KmsKeyEntry {
252 metadata: metadata.clone(),
253 private_key_bytes,
254 };
255 store.insert(key_id.to_string(), entry);
256 Ok(metadata)
257 }
258
259 fn sign(&self, key_id: &str, data: &[u8]) -> DidResult<Vec<u8>> {
260 let store = self
261 .keys
262 .read()
263 .map_err(|e| DidError::InternalError(format!("KMS lock poisoned: {}", e)))?;
264 let entry = store.get(key_id).ok_or_else(|| {
265 DidError::KeyNotFound(format!("Key '{}' not found in {} KMS", key_id, $display))
266 })?;
267 if !entry.metadata.enabled {
268 return Err(DidError::SigningFailed(format!(
269 "Key '{}' is disabled",
270 key_id
271 )));
272 }
273 Ok(hmac_sign(&entry.private_key_bytes, key_id, data))
274 }
275
276 fn verify(&self, key_id: &str, data: &[u8], signature: &[u8]) -> DidResult<bool> {
277 let expected = self.sign(key_id, data)?;
278 Ok(expected == signature)
279 }
280
281 fn get_public_key(&self, key_id: &str) -> DidResult<Vec<u8>> {
282 let store = self
283 .keys
284 .read()
285 .map_err(|e| DidError::InternalError(format!("KMS lock poisoned: {}", e)))?;
286 let entry = store.get(key_id).ok_or_else(|| {
287 DidError::KeyNotFound(format!("Key '{}' not found in {} KMS", key_id, $display))
288 })?;
289 Ok(derive_public_key(&entry.private_key_bytes))
290 }
291
292 fn delete_key(&self, key_id: &str) -> DidResult<()> {
293 let mut store = self
294 .keys
295 .write()
296 .map_err(|e| DidError::InternalError(format!("KMS lock poisoned: {}", e)))?;
297 store
298 .remove(key_id)
299 .ok_or_else(|| {
300 DidError::KeyNotFound(format!(
301 "Key '{}' not found in {} KMS",
302 key_id, $display
303 ))
304 })
305 .map(|_| ())
306 }
307
308 fn list_keys(&self) -> DidResult<Vec<KmsKeyMetadata>> {
309 let store = self
310 .keys
311 .read()
312 .map_err(|e| DidError::InternalError(format!("KMS lock poisoned: {}", e)))?;
313 let mut list: Vec<KmsKeyMetadata> =
314 store.values().map(|e| e.metadata.clone()).collect();
315 list.sort_by(|a, b| a.key_id.cmp(&b.key_id));
317 Ok(list)
318 }
319 }
320 };
321}
322
323#[cfg(feature = "insecure-mock-kms")]
324impl_mock_kms!(InsecureMockAwsKms, "AWS");
325#[cfg(feature = "insecure-mock-kms")]
326impl_mock_kms!(InsecureMockGcpKms, "GCP");
327#[cfg(feature = "insecure-mock-kms")]
328impl_mock_kms!(InsecureMockAzureKms, "Azure");
329
330#[cfg(feature = "insecure-mock-kms")]
336pub enum KmsProvider {
337 InsecureMockAws,
338 InsecureMockGcp,
339 InsecureMockAzure,
340}
341
342#[cfg(feature = "insecure-mock-kms")]
347pub fn create_insecure_mock_kms(provider: KmsProvider, ack: InsecureAck) -> Box<dyn KmsBackend> {
348 match provider {
349 KmsProvider::InsecureMockAws => Box::new(InsecureMockAwsKms::new(ack)),
350 KmsProvider::InsecureMockGcp => Box::new(InsecureMockGcpKms::new(ack)),
351 KmsProvider::InsecureMockAzure => Box::new(InsecureMockAzureKms::new(ack)),
352 }
353}
354
355pub struct KmsDidSigner {
361 backend: Box<dyn KmsBackend>,
362 key_id: String,
363}
364
365impl KmsDidSigner {
366 pub fn new(backend: Box<dyn KmsBackend>, key_id: &str) -> Self {
367 Self {
368 backend,
369 key_id: key_id.to_string(),
370 }
371 }
372
373 pub fn create_did_document(&self, did: &str) -> DidResult<DidDocument> {
376 let public_key = self.backend.get_public_key(&self.key_id)?;
377 let key_fragment = format!("{}#kms-key-0", did);
378
379 let vm = VerificationMethod::ed25519(&key_fragment, did, &public_key);
380
381 use crate::did::document::{DidDocument as DocType, VerificationRelationship};
382 use crate::Did;
383
384 let did_obj = Did::new(did)?;
385 let mut doc = DocType::new(did_obj);
386 doc.verification_method.push(vm);
387 doc.authentication
388 .push(VerificationRelationship::Reference(key_fragment.clone()));
389 doc.assertion_method
390 .push(VerificationRelationship::Reference(key_fragment));
391
392 Ok(doc)
393 }
394
395 pub fn sign_credential(&self, credential: &serde_json::Value) -> DidResult<serde_json::Value> {
398 let serialized = serde_json::to_vec(credential)
399 .map_err(|e| DidError::SerializationError(e.to_string()))?;
400
401 let sig = self.backend.sign(&self.key_id, &serialized)?;
402 use base64::engine::general_purpose::URL_SAFE_NO_PAD;
403 use base64::Engine;
404 let sig_b64 = URL_SAFE_NO_PAD.encode(&sig);
405
406 let mut signed = credential.clone();
407 if let Some(obj) = signed.as_object_mut() {
408 obj.insert(
409 "proof".to_string(),
410 serde_json::json!({
411 "type": "KmsHmacSignature2024",
412 "verificationMethod": self.key_id,
413 "signatureValue": sig_b64
414 }),
415 );
416 }
417 Ok(signed)
418 }
419
420 pub fn verify_credential(&self, signed_credential: &serde_json::Value) -> DidResult<bool> {
422 use base64::engine::general_purpose::URL_SAFE_NO_PAD;
423 use base64::Engine;
424
425 let proof = signed_credential
427 .get("proof")
428 .ok_or_else(|| DidError::InvalidProof("Missing proof field".to_string()))?;
429
430 let sig_b64 = proof
431 .get("signatureValue")
432 .and_then(|v| v.as_str())
433 .ok_or_else(|| DidError::InvalidProof("Missing signatureValue".to_string()))?;
434
435 let signature = URL_SAFE_NO_PAD
436 .decode(sig_b64)
437 .map_err(|e| DidError::InvalidProof(format!("Invalid base64: {}", e)))?;
438
439 let mut without_proof = signed_credential.clone();
441 if let Some(obj) = without_proof.as_object_mut() {
442 obj.remove("proof");
443 }
444 let serialized = serde_json::to_vec(&without_proof)
445 .map_err(|e| DidError::SerializationError(e.to_string()))?;
446
447 self.backend.verify(&self.key_id, &serialized, &signature)
448 }
449}
450
451#[cfg(all(test, feature = "insecure-mock-kms"))]
456mod tests {
457 use super::*;
458
459 fn ack() -> InsecureAck {
460 InsecureAck::acknowledge_insecure()
461 }
462
463 #[test]
466 fn test_aws_create_ed25519_key() {
467 let kms = InsecureMockAwsKms::new(ack());
468 let meta = kms.create_key("my-key", KmsAlgorithm::Ed25519).unwrap();
469 assert_eq!(meta.key_id, "my-key");
470 assert_eq!(meta.algorithm.as_str(), "Ed25519");
471 assert!(meta.enabled);
472 }
473
474 #[test]
475 fn test_aws_create_duplicate_key_fails() {
476 let kms = InsecureMockAwsKms::new(ack());
477 kms.create_key("dup", KmsAlgorithm::Ed25519).unwrap();
478 assert!(kms.create_key("dup", KmsAlgorithm::Ed25519).is_err());
479 }
480
481 #[test]
482 fn test_aws_sign_and_verify() {
483 let kms = InsecureMockAwsKms::new(ack());
484 kms.create_key("signing-key", KmsAlgorithm::EcP256).unwrap();
485
486 let data = b"hello world";
487 let sig = kms.sign("signing-key", data).unwrap();
488 assert!(!sig.is_empty());
489
490 let valid = kms.verify("signing-key", data, &sig).unwrap();
491 assert!(valid);
492 }
493
494 #[test]
495 fn test_aws_verify_wrong_data_fails() {
496 let kms = InsecureMockAwsKms::new(ack());
497 kms.create_key("k1", KmsAlgorithm::Ed25519).unwrap();
498
499 let sig = kms.sign("k1", b"original").unwrap();
500 let valid = kms.verify("k1", b"tampered", &sig).unwrap();
501 assert!(!valid);
502 }
503
504 #[test]
505 fn test_aws_sign_missing_key_error() {
506 let kms = InsecureMockAwsKms::new(ack());
507 assert!(kms.sign("nonexistent", b"data").is_err());
508 }
509
510 #[test]
511 fn test_aws_get_public_key() {
512 let kms = InsecureMockAwsKms::new(ack());
513 kms.create_key("pk-key", KmsAlgorithm::Ed25519).unwrap();
514 let pub_key = kms.get_public_key("pk-key").unwrap();
515 assert!(!pub_key.is_empty());
516 }
517
518 #[test]
519 fn test_aws_delete_key() {
520 let kms = InsecureMockAwsKms::new(ack());
521 kms.create_key("del-key", KmsAlgorithm::Ed25519).unwrap();
522 kms.delete_key("del-key").unwrap();
523 assert!(kms.sign("del-key", b"data").is_err());
524 }
525
526 #[test]
527 fn test_aws_delete_missing_key_error() {
528 let kms = InsecureMockAwsKms::new(ack());
529 assert!(kms.delete_key("ghost").is_err());
530 }
531
532 #[test]
533 fn test_aws_list_keys() {
534 let kms = InsecureMockAwsKms::new(ack());
535 kms.create_key("a", KmsAlgorithm::Ed25519).unwrap();
536 kms.create_key("b", KmsAlgorithm::EcP256).unwrap();
537
538 let keys = kms.list_keys().unwrap();
539 assert_eq!(keys.len(), 2);
540 assert_eq!(keys[0].key_id, "a");
542 assert_eq!(keys[1].key_id, "b");
543 }
544
545 #[test]
546 fn test_aws_all_algorithms_create() {
547 let kms = InsecureMockAwsKms::new(ack());
548 kms.create_key("ed", KmsAlgorithm::Ed25519).unwrap();
549 kms.create_key("p256", KmsAlgorithm::EcP256).unwrap();
550 kms.create_key("p384", KmsAlgorithm::EcP384).unwrap();
551 kms.create_key("rsa2048", KmsAlgorithm::Rsa2048).unwrap();
552 kms.create_key("rsa4096", KmsAlgorithm::Rsa4096).unwrap();
553
554 let keys = kms.list_keys().unwrap();
555 assert_eq!(keys.len(), 5);
556 }
557
558 #[test]
561 fn test_gcp_create_and_sign() {
562 let kms = InsecureMockGcpKms::new(ack());
563 kms.create_key("gcp-key", KmsAlgorithm::EcP256).unwrap();
564
565 let sig = kms.sign("gcp-key", b"gcp-data").unwrap();
566 let valid = kms.verify("gcp-key", b"gcp-data", &sig).unwrap();
567 assert!(valid);
568 }
569
570 #[test]
571 fn test_gcp_list_empty() {
572 let kms = InsecureMockGcpKms::new(ack());
573 let keys = kms.list_keys().unwrap();
574 assert!(keys.is_empty());
575 }
576
577 #[test]
578 fn test_gcp_public_key_differs_from_private() {
579 let kms = InsecureMockGcpKms::new(ack());
580 kms.create_key("gcp-pk", KmsAlgorithm::Ed25519).unwrap();
581
582 let pub_key = kms.get_public_key("gcp-pk").unwrap();
583 assert!(!pub_key.is_empty());
585 }
586
587 #[test]
588 fn test_gcp_delete_and_recreate() {
589 let kms = InsecureMockGcpKms::new(ack());
590 kms.create_key("reuse", KmsAlgorithm::Ed25519).unwrap();
591 kms.delete_key("reuse").unwrap();
592 kms.create_key("reuse", KmsAlgorithm::Ed25519).unwrap();
594 }
595
596 #[test]
599 fn test_azure_create_and_sign() {
600 let kms = InsecureMockAzureKms::new(ack());
601 kms.create_key("az-key", KmsAlgorithm::Rsa2048).unwrap();
602
603 let sig = kms.sign("az-key", b"azure-data").unwrap();
604 let valid = kms.verify("az-key", b"azure-data", &sig).unwrap();
605 assert!(valid);
606 }
607
608 #[test]
609 fn test_azure_wrong_signature() {
610 let kms = InsecureMockAzureKms::new(ack());
611 kms.create_key("az2", KmsAlgorithm::EcP256).unwrap();
612
613 let bad_sig = vec![0u8; 32];
614 let valid = kms.verify("az2", b"some-data", &bad_sig).unwrap();
615 assert!(!valid);
616 }
617
618 #[test]
619 fn test_azure_list_after_delete() {
620 let kms = InsecureMockAzureKms::new(ack());
621 kms.create_key("x", KmsAlgorithm::Ed25519).unwrap();
622 kms.create_key("y", KmsAlgorithm::Ed25519).unwrap();
623 kms.delete_key("x").unwrap();
624
625 let keys = kms.list_keys().unwrap();
626 assert_eq!(keys.len(), 1);
627 assert_eq!(keys[0].key_id, "y");
628 }
629
630 #[test]
633 fn test_create_mock_kms_aws() {
634 let kms = create_insecure_mock_kms(KmsProvider::InsecureMockAws, ack());
635 kms.create_key("factory-aws", KmsAlgorithm::Ed25519)
636 .unwrap();
637 let keys = kms.list_keys().unwrap();
638 assert_eq!(keys.len(), 1);
639 }
640
641 #[test]
642 fn test_create_mock_kms_gcp() {
643 let kms = create_insecure_mock_kms(KmsProvider::InsecureMockGcp, ack());
644 kms.create_key("factory-gcp", KmsAlgorithm::EcP256).unwrap();
645 let keys = kms.list_keys().unwrap();
646 assert_eq!(keys.len(), 1);
647 }
648
649 #[test]
650 fn test_create_mock_kms_azure() {
651 let kms = create_insecure_mock_kms(KmsProvider::InsecureMockAzure, ack());
652 kms.create_key("factory-azure", KmsAlgorithm::Rsa2048)
653 .unwrap();
654 let keys = kms.list_keys().unwrap();
655 assert_eq!(keys.len(), 1);
656 }
657
658 #[test]
661 fn test_kms_did_signer_create_document() {
662 let backend = create_insecure_mock_kms(KmsProvider::InsecureMockAws, ack());
663 backend
664 .create_key("did-signer-key", KmsAlgorithm::Ed25519)
665 .unwrap();
666
667 let signer = KmsDidSigner::new(backend, "did-signer-key");
668 let did_str = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";
669 let doc = signer.create_did_document(did_str).unwrap();
670
671 assert_eq!(doc.id.as_str(), did_str);
672 assert_eq!(doc.verification_method.len(), 1);
673 assert!(!doc.authentication.is_empty());
674 }
675
676 #[test]
677 fn test_kms_did_signer_sign_credential() {
678 let backend = create_insecure_mock_kms(KmsProvider::InsecureMockGcp, ack());
679 backend.create_key("vc-key", KmsAlgorithm::EcP256).unwrap();
680
681 let signer = KmsDidSigner::new(backend, "vc-key");
682 let credential = serde_json::json!({
683 "@context": ["https://www.w3.org/2018/credentials/v1"],
684 "type": ["VerifiableCredential"],
685 "issuer": "did:example:issuer",
686 "credentialSubject": { "id": "did:example:subject", "name": "Alice" }
687 });
688
689 let signed = signer.sign_credential(&credential).unwrap();
690 assert!(signed.get("proof").is_some());
691 let proof = signed.get("proof").unwrap();
692 assert_eq!(proof["type"].as_str().unwrap(), "KmsHmacSignature2024");
693 assert!(proof.get("signatureValue").is_some());
694 }
695
696 #[test]
697 fn test_kms_did_signer_verify_credential() {
698 let backend = create_insecure_mock_kms(KmsProvider::InsecureMockAzure, ack());
699 backend
700 .create_key("verify-key", KmsAlgorithm::Ed25519)
701 .unwrap();
702
703 let signer = KmsDidSigner::new(backend, "verify-key");
704 let credential = serde_json::json!({
705 "id": "http://example.com/vc/1",
706 "type": ["VerifiableCredential"],
707 "issuer": "did:example:issuer"
708 });
709
710 let signed = signer.sign_credential(&credential).unwrap();
711 let valid = signer.verify_credential(&signed).unwrap();
712 assert!(valid);
713 }
714
715 #[test]
716 fn test_kms_did_signer_tampered_credential_fails() {
717 let backend = create_insecure_mock_kms(KmsProvider::InsecureMockAws, ack());
718 backend
719 .create_key("tamper-key", KmsAlgorithm::EcP256)
720 .unwrap();
721
722 let signer = KmsDidSigner::new(backend, "tamper-key");
723 let credential = serde_json::json!({
724 "type": ["VerifiableCredential"],
725 "issuer": "did:example:issuer"
726 });
727
728 let mut signed = signer.sign_credential(&credential).unwrap();
729 if let Some(obj) = signed.as_object_mut() {
731 obj.insert("issuer".to_string(), serde_json::json!("did:evil:attacker"));
732 }
733
734 let valid = signer.verify_credential(&signed).unwrap();
735 assert!(!valid);
736 }
737
738 #[test]
739 fn test_kms_did_signer_missing_proof_error() {
740 let backend = create_insecure_mock_kms(KmsProvider::InsecureMockAws, ack());
741 backend
742 .create_key("no-proof-key", KmsAlgorithm::Ed25519)
743 .unwrap();
744
745 let signer = KmsDidSigner::new(backend, "no-proof-key");
746 let credential = serde_json::json!({ "type": "VerifiableCredential" });
747 assert!(signer.verify_credential(&credential).is_err());
749 }
750
751 #[test]
752 fn test_key_metadata_fields() {
753 let kms = InsecureMockAwsKms::new(ack());
754 let meta = kms.create_key("meta-test", KmsAlgorithm::EcP384).unwrap();
755
756 assert_eq!(meta.key_id, "meta-test");
757 assert_eq!(meta.algorithm.as_str(), "EC_P384");
758 assert!(matches!(meta.key_usage, KeyUsage::SignVerify));
759 assert!(meta.created_at > 0);
760 assert!(meta.enabled);
761 }
762
763 #[test]
764 fn test_algorithm_key_sizes() {
765 assert_eq!(KmsAlgorithm::Ed25519.key_size_bytes(), 32);
766 assert_eq!(KmsAlgorithm::EcP256.key_size_bytes(), 32);
767 assert_eq!(KmsAlgorithm::EcP384.key_size_bytes(), 48);
768 assert_eq!(KmsAlgorithm::Rsa2048.key_size_bytes(), 256);
769 assert_eq!(KmsAlgorithm::Rsa4096.key_size_bytes(), 512);
770 }
771
772 #[test]
773 fn test_signatures_are_deterministic() {
774 let kms = InsecureMockAwsKms::new(ack());
775 kms.create_key("det-key", KmsAlgorithm::Ed25519).unwrap();
776
777 let sig1 = kms.sign("det-key", b"same data").unwrap();
778 let sig2 = kms.sign("det-key", b"same data").unwrap();
779 assert_eq!(sig1, sig2);
780 }
781
782 #[test]
783 fn test_different_keys_produce_different_signatures() {
784 let kms = InsecureMockAwsKms::new(ack());
785 kms.create_key("key-a", KmsAlgorithm::Ed25519).unwrap();
786 kms.create_key("key-b", KmsAlgorithm::Ed25519).unwrap();
787
788 let sig_a = kms.sign("key-a", b"data").unwrap();
789 let sig_b = kms.sign("key-b", b"data").unwrap();
790 assert_ne!(sig_a, sig_b);
791 }
792}