Skip to main content

fakecloud_kms/
service.rs

1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use base64::Engine;
5use chrono::Utc;
6use http::StatusCode;
7use serde_json::{json, Value};
8use uuid::Uuid;
9
10use fakecloud_core::service::{AwsRequest, AwsResponse, AwsService, AwsServiceError};
11use fakecloud_core::validation::*;
12
13use crate::state::{CustomKeyStore, KeyRotation, KmsAlias, KmsGrant, KmsKey, SharedKmsState};
14
15const FAKE_ENVELOPE_PREFIX: &str = "fakecloud-kms:";
16
17const VALID_KEY_SPECS: &[&str] = &[
18    "ECC_NIST_P256",
19    "ECC_NIST_P384",
20    "ECC_NIST_P521",
21    "ECC_SECG_P256K1",
22    "HMAC_224",
23    "HMAC_256",
24    "HMAC_384",
25    "HMAC_512",
26    "RSA_2048",
27    "RSA_3072",
28    "RSA_4096",
29    "SM2",
30    "SYMMETRIC_DEFAULT",
31];
32
33const VALID_SIGNING_ALGORITHMS: &[&str] = &[
34    "RSASSA_PKCS1_V1_5_SHA_256",
35    "RSASSA_PKCS1_V1_5_SHA_384",
36    "RSASSA_PKCS1_V1_5_SHA_512",
37    "RSASSA_PSS_SHA_256",
38    "RSASSA_PSS_SHA_384",
39    "RSASSA_PSS_SHA_512",
40    "ECDSA_SHA_256",
41    "ECDSA_SHA_384",
42    "ECDSA_SHA_512",
43];
44
45pub struct KmsService {
46    state: SharedKmsState,
47}
48
49impl KmsService {
50    pub fn new(state: SharedKmsState) -> Self {
51        Self { state }
52    }
53}
54
55#[async_trait]
56impl AwsService for KmsService {
57    fn service_name(&self) -> &str {
58        "kms"
59    }
60
61    async fn handle(&self, req: AwsRequest) -> Result<AwsResponse, AwsServiceError> {
62        match req.action.as_str() {
63            "CreateKey" => self.create_key(&req),
64            "DescribeKey" => self.describe_key(&req),
65            "ListKeys" => self.list_keys(&req),
66            "EnableKey" => self.enable_key(&req),
67            "DisableKey" => self.disable_key(&req),
68            "ScheduleKeyDeletion" => self.schedule_key_deletion(&req),
69            "CancelKeyDeletion" => self.cancel_key_deletion(&req),
70            "Encrypt" => self.encrypt(&req),
71            "Decrypt" => self.decrypt(&req),
72            "ReEncrypt" => self.re_encrypt(&req),
73            "GenerateDataKey" => self.generate_data_key(&req),
74            "GenerateDataKeyWithoutPlaintext" => self.generate_data_key_without_plaintext(&req),
75            "GenerateRandom" => self.generate_random(&req),
76            "CreateAlias" => self.create_alias(&req),
77            "DeleteAlias" => self.delete_alias(&req),
78            "UpdateAlias" => self.update_alias(&req),
79            "ListAliases" => self.list_aliases(&req),
80            "TagResource" => self.tag_resource(&req),
81            "UntagResource" => self.untag_resource(&req),
82            "ListResourceTags" => self.list_resource_tags(&req),
83            "UpdateKeyDescription" => self.update_key_description(&req),
84            "GetKeyPolicy" => self.get_key_policy(&req),
85            "PutKeyPolicy" => self.put_key_policy(&req),
86            "ListKeyPolicies" => self.list_key_policies(&req),
87            "GetKeyRotationStatus" => self.get_key_rotation_status(&req),
88            "EnableKeyRotation" => self.enable_key_rotation(&req),
89            "DisableKeyRotation" => self.disable_key_rotation(&req),
90            "RotateKeyOnDemand" => self.rotate_key_on_demand(&req),
91            "ListKeyRotations" => self.list_key_rotations(&req),
92            "Sign" => self.sign(&req),
93            "Verify" => self.verify(&req),
94            "GetPublicKey" => self.get_public_key(&req),
95            "CreateGrant" => self.create_grant(&req),
96            "ListGrants" => self.list_grants(&req),
97            "ListRetirableGrants" => self.list_retirable_grants(&req),
98            "RevokeGrant" => self.revoke_grant(&req),
99            "RetireGrant" => self.retire_grant(&req),
100            "GenerateMac" => self.generate_mac(&req),
101            "VerifyMac" => self.verify_mac(&req),
102            "ReplicateKey" => self.replicate_key(&req),
103            "GenerateDataKeyPair" => self.generate_data_key_pair(&req),
104            "GenerateDataKeyPairWithoutPlaintext" => {
105                self.generate_data_key_pair_without_plaintext(&req)
106            }
107            "DeriveSharedSecret" => self.derive_shared_secret(&req),
108            "GetParametersForImport" => self.get_parameters_for_import(&req),
109            "ImportKeyMaterial" => self.import_key_material(&req),
110            "DeleteImportedKeyMaterial" => self.delete_imported_key_material(&req),
111            "UpdatePrimaryRegion" => self.update_primary_region(&req),
112            "CreateCustomKeyStore" => self.create_custom_key_store(&req),
113            "DeleteCustomKeyStore" => self.delete_custom_key_store(&req),
114            "DescribeCustomKeyStores" => self.describe_custom_key_stores(&req),
115            "ConnectCustomKeyStore" => self.connect_custom_key_store(&req),
116            "DisconnectCustomKeyStore" => self.disconnect_custom_key_store(&req),
117            "UpdateCustomKeyStore" => self.update_custom_key_store(&req),
118            _ => Err(AwsServiceError::action_not_implemented("kms", &req.action)),
119        }
120    }
121
122    fn supported_actions(&self) -> &[&str] {
123        &[
124            "CreateKey",
125            "DescribeKey",
126            "ListKeys",
127            "EnableKey",
128            "DisableKey",
129            "ScheduleKeyDeletion",
130            "CancelKeyDeletion",
131            "Encrypt",
132            "Decrypt",
133            "ReEncrypt",
134            "GenerateDataKey",
135            "GenerateDataKeyWithoutPlaintext",
136            "GenerateRandom",
137            "CreateAlias",
138            "DeleteAlias",
139            "UpdateAlias",
140            "ListAliases",
141            "TagResource",
142            "UntagResource",
143            "ListResourceTags",
144            "UpdateKeyDescription",
145            "GetKeyPolicy",
146            "PutKeyPolicy",
147            "ListKeyPolicies",
148            "GetKeyRotationStatus",
149            "EnableKeyRotation",
150            "DisableKeyRotation",
151            "RotateKeyOnDemand",
152            "ListKeyRotations",
153            "Sign",
154            "Verify",
155            "GetPublicKey",
156            "CreateGrant",
157            "ListGrants",
158            "ListRetirableGrants",
159            "RevokeGrant",
160            "RetireGrant",
161            "GenerateMac",
162            "VerifyMac",
163            "ReplicateKey",
164            "GenerateDataKeyPair",
165            "GenerateDataKeyPairWithoutPlaintext",
166            "DeriveSharedSecret",
167            "GetParametersForImport",
168            "ImportKeyMaterial",
169            "DeleteImportedKeyMaterial",
170            "UpdatePrimaryRegion",
171            "CreateCustomKeyStore",
172            "DeleteCustomKeyStore",
173            "DescribeCustomKeyStores",
174            "ConnectCustomKeyStore",
175            "DisconnectCustomKeyStore",
176            "UpdateCustomKeyStore",
177        ]
178    }
179}
180
181fn body_json(req: &AwsRequest) -> Value {
182    serde_json::from_slice(&req.body).unwrap_or(Value::Null)
183}
184
185fn default_key_policy(account_id: &str) -> String {
186    serde_json::to_string(&json!({
187        "Version": "2012-10-17",
188        "Id": "key-default-1",
189        "Statement": [
190            {
191                "Sid": "Enable IAM User Permissions",
192                "Effect": "Allow",
193                "Principal": {"AWS": format!("arn:aws:iam::{account_id}:root")},
194                "Action": "kms:*",
195                "Resource": "*",
196            }
197        ],
198    }))
199    .unwrap()
200}
201
202fn signing_algorithms_for_key_spec(key_spec: &str) -> Option<Vec<String>> {
203    match key_spec {
204        "RSA_2048" | "RSA_3072" | "RSA_4096" => Some(vec![
205            "RSASSA_PKCS1_V1_5_SHA_256".into(),
206            "RSASSA_PKCS1_V1_5_SHA_384".into(),
207            "RSASSA_PKCS1_V1_5_SHA_512".into(),
208            "RSASSA_PSS_SHA_256".into(),
209            "RSASSA_PSS_SHA_384".into(),
210            "RSASSA_PSS_SHA_512".into(),
211        ]),
212        "ECC_NIST_P256" | "ECC_SECG_P256K1" => Some(vec!["ECDSA_SHA_256".into()]),
213        "ECC_NIST_P384" => Some(vec!["ECDSA_SHA_384".into()]),
214        "ECC_NIST_P521" => Some(vec!["ECDSA_SHA_512".into()]),
215        _ => None,
216    }
217}
218
219fn encryption_algorithms_for_key(key_usage: &str, key_spec: &str) -> Option<Vec<String>> {
220    if key_usage == "ENCRYPT_DECRYPT" {
221        match key_spec {
222            "SYMMETRIC_DEFAULT" => Some(vec!["SYMMETRIC_DEFAULT".into()]),
223            "RSA_2048" | "RSA_3072" | "RSA_4096" => {
224                Some(vec!["RSAES_OAEP_SHA_1".into(), "RSAES_OAEP_SHA_256".into()])
225            }
226            _ => None,
227        }
228    } else {
229        None
230    }
231}
232
233fn mac_algorithms_for_key_spec(key_spec: &str) -> Option<Vec<String>> {
234    match key_spec {
235        "HMAC_224" => Some(vec!["HMAC_SHA_224".into()]),
236        "HMAC_256" => Some(vec!["HMAC_SHA_256".into()]),
237        "HMAC_384" => Some(vec!["HMAC_SHA_384".into()]),
238        "HMAC_512" => Some(vec!["HMAC_SHA_512".into()]),
239        _ => None,
240    }
241}
242
243fn rand_bytes(n: usize) -> Vec<u8> {
244    (0..n)
245        .map(|_| {
246            let u = Uuid::new_v4();
247            u.as_bytes()[0]
248        })
249        .collect()
250}
251
252impl KmsService {
253    fn resolve_key_id(&self, key_id_or_arn: &str) -> Option<String> {
254        let state = self.state.read();
255        Self::resolve_key_id_with_state(&state, key_id_or_arn)
256    }
257
258    fn resolve_key_id_with_state(
259        state: &crate::state::KmsState,
260        key_id_or_arn: &str,
261    ) -> Option<String> {
262        // Direct key ID
263        if state.keys.contains_key(key_id_or_arn) {
264            return Some(key_id_or_arn.to_string());
265        }
266
267        // ARN for key
268        if key_id_or_arn.starts_with("arn:aws:kms:") {
269            // Could be key ARN or alias ARN
270            if key_id_or_arn.contains(":key/") {
271                if let Some(id) = key_id_or_arn.rsplit('/').next() {
272                    if state.keys.contains_key(id) {
273                        return Some(id.to_string());
274                    }
275                }
276            }
277            // alias ARN: arn:aws:kms:region:account:alias/name
278            if key_id_or_arn.contains(":alias/") {
279                if let Some(alias_part) = key_id_or_arn.split(':').next_back() {
280                    if let Some(alias) = state.aliases.get(alias_part) {
281                        return Some(alias.target_key_id.clone());
282                    }
283                }
284            }
285        }
286
287        // Alias name
288        if key_id_or_arn.starts_with("alias/") {
289            if let Some(alias) = state.aliases.get(key_id_or_arn) {
290                return Some(alias.target_key_id.clone());
291            }
292        }
293
294        None
295    }
296
297    fn require_key_id(body: &Value) -> Result<String, AwsServiceError> {
298        body["KeyId"]
299            .as_str()
300            .map(|s| s.to_string())
301            .ok_or_else(|| {
302                AwsServiceError::aws_error(
303                    StatusCode::BAD_REQUEST,
304                    "ValidationException",
305                    "KeyId is required",
306                )
307            })
308    }
309
310    fn resolve_required_key(&self, body: &Value) -> Result<String, AwsServiceError> {
311        let key_id_input = Self::require_key_id(body)?;
312        self.resolve_key_id(&key_id_input).ok_or_else(|| {
313            AwsServiceError::aws_error(
314                StatusCode::BAD_REQUEST,
315                "NotFoundException",
316                format!("Key '{key_id_input}' does not exist"),
317            )
318        })
319    }
320
321    fn create_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
322        let body = body_json(req);
323
324        validate_optional_string_length(
325            "customKeyStoreId",
326            body["CustomKeyStoreId"].as_str(),
327            1,
328            64,
329        )?;
330
331        validate_optional_string_length("description", body["Description"].as_str(), 0, 8192)?;
332        validate_optional_enum(
333            "keyUsage",
334            body["KeyUsage"].as_str(),
335            &[
336                "SIGN_VERIFY",
337                "ENCRYPT_DECRYPT",
338                "GENERATE_VERIFY_MAC",
339                "KEY_AGREEMENT",
340            ],
341        )?;
342        validate_optional_enum(
343            "origin",
344            body["Origin"].as_str(),
345            &["AWS_KMS", "EXTERNAL", "AWS_CLOUDHSM", "EXTERNAL_KEY_STORE"],
346        )?;
347        validate_optional_string_length("policy", body["Policy"].as_str(), 1, 131072)?;
348        validate_optional_string_length("xksKeyId", body["XksKeyId"].as_str(), 1, 64)?;
349
350        let custom_key_store_id = body["CustomKeyStoreId"].as_str().map(|s| s.to_string());
351        let description = body["Description"].as_str().unwrap_or("").to_string();
352        let key_usage = body["KeyUsage"]
353            .as_str()
354            .unwrap_or("ENCRYPT_DECRYPT")
355            .to_string();
356        let key_spec = body["KeySpec"]
357            .as_str()
358            .or_else(|| body["CustomerMasterKeySpec"].as_str())
359            .unwrap_or("SYMMETRIC_DEFAULT")
360            .to_string();
361        let origin = body["Origin"].as_str().unwrap_or("AWS_KMS").to_string();
362        let multi_region = body["MultiRegion"].as_bool().unwrap_or(false);
363        let policy = body["Policy"].as_str().map(|s| s.to_string());
364
365        // Validate key spec
366        if !VALID_KEY_SPECS.contains(&key_spec.as_str()) {
367            return Err(AwsServiceError::aws_error(
368                StatusCode::BAD_REQUEST,
369                "ValidationException",
370                format!(
371                    "1 validation error detected: Value '{}' at 'KeySpec' failed to satisfy constraint: Member must satisfy enum value set: {}",
372                    key_spec, fmt_enum_set(&VALID_KEY_SPECS.iter().map(|s| s.to_string()).collect::<Vec<_>>())
373                ),
374            ));
375        }
376
377        let mut state = self.state.write();
378
379        let key_id = if multi_region {
380            format!("mrk-{}", Uuid::new_v4().as_simple())
381        } else {
382            Uuid::new_v4().to_string()
383        };
384
385        let arn = format!(
386            "arn:aws:kms:{}:{}:key/{}",
387            state.region, state.account_id, key_id
388        );
389        let now = Utc::now().timestamp() as f64;
390
391        let tags: HashMap<String, String> = body["Tags"]
392            .as_array()
393            .map(|arr| {
394                arr.iter()
395                    .filter_map(|t| {
396                        let k = t["TagKey"].as_str()?;
397                        let v = t["TagValue"].as_str()?;
398                        Some((k.to_string(), v.to_string()))
399                    })
400                    .collect()
401            })
402            .unwrap_or_default();
403
404        let signing_algs = if key_usage == "SIGN_VERIFY" {
405            signing_algorithms_for_key_spec(&key_spec)
406        } else {
407            None
408        };
409
410        let encryption_algs = encryption_algorithms_for_key(&key_usage, &key_spec);
411
412        let mac_algs = if key_usage == "GENERATE_VERIFY_MAC" {
413            mac_algorithms_for_key_spec(&key_spec)
414        } else {
415            None
416        };
417
418        let default_policy = default_key_policy(&state.account_id);
419        let key_policy = policy.unwrap_or(default_policy);
420
421        let key = KmsKey {
422            key_id: key_id.clone(),
423            arn: arn.clone(),
424            creation_date: now,
425            description,
426            enabled: true,
427            key_usage,
428            key_spec,
429            key_manager: "CUSTOMER".to_string(),
430            key_state: "Enabled".to_string(),
431            deletion_date: None,
432            tags,
433            policy: key_policy,
434            key_rotation_enabled: false,
435            origin,
436            multi_region,
437            rotations: Vec::new(),
438            signing_algorithms: signing_algs,
439            encryption_algorithms: encryption_algs,
440            mac_algorithms: mac_algs,
441            custom_key_store_id,
442            imported_key_material: false,
443            primary_region: None,
444        };
445
446        let metadata = key_metadata_json(&key, &state.account_id);
447        state.keys.insert(key_id, key);
448
449        Ok(AwsResponse::json(
450            StatusCode::OK,
451            serde_json::to_string(&json!({ "KeyMetadata": metadata })).unwrap(),
452        ))
453    }
454
455    fn describe_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
456        let body = body_json(req);
457        let key_id_input = body["KeyId"].as_str().ok_or_else(|| {
458            AwsServiceError::aws_error(
459                StatusCode::BAD_REQUEST,
460                "ValidationException",
461                "KeyId is required",
462            )
463        })?;
464
465        let state = self.state.read();
466
467        // Check key policy for Deny rules
468        let resolved = Self::resolve_key_id_with_state(&state, key_id_input).ok_or_else(|| {
469            AwsServiceError::aws_error(
470                StatusCode::BAD_REQUEST,
471                "NotFoundException",
472                format!("Key '{key_id_input}' does not exist"),
473            )
474        })?;
475
476        let key = state.keys.get(&resolved).ok_or_else(|| {
477            AwsServiceError::aws_error(
478                StatusCode::BAD_REQUEST,
479                "NotFoundException",
480                format!("Key '{key_id_input}' does not exist"),
481            )
482        })?;
483
484        // Check policy for Deny on DescribeKey
485        check_policy_deny(key, "kms:DescribeKey")?;
486
487        let metadata = key_metadata_json(key, &state.account_id);
488        Ok(AwsResponse::json(
489            StatusCode::OK,
490            serde_json::to_string(&json!({ "KeyMetadata": metadata })).unwrap(),
491        ))
492    }
493
494    fn list_keys(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
495        let body = body_json(req);
496
497        validate_optional_range_i64("limit", body["Limit"].as_i64(), 1, 1000)?;
498        validate_optional_string_length("marker", body["Marker"].as_str(), 1, 320)?;
499
500        let limit = body["Limit"].as_u64().unwrap_or(1000) as usize;
501        let marker = body["Marker"].as_str();
502
503        let state = self.state.read();
504        let all_keys: Vec<Value> = state
505            .keys
506            .values()
507            .map(|k| {
508                json!({
509                    "KeyId": k.key_id,
510                    "KeyArn": k.arn,
511                })
512            })
513            .collect();
514
515        let start = if let Some(m) = marker {
516            all_keys
517                .iter()
518                .position(|k| k["KeyId"].as_str() == Some(m))
519                .map(|pos| pos + 1)
520                .unwrap_or(0)
521        } else {
522            0
523        };
524
525        let page = &all_keys[start..all_keys.len().min(start + limit)];
526        let truncated = start + limit < all_keys.len();
527
528        let mut result = json!({
529            "Keys": page,
530            "Truncated": truncated,
531        });
532
533        if truncated {
534            if let Some(last) = page.last() {
535                result["NextMarker"] = last["KeyId"].clone();
536            }
537        }
538
539        Ok(AwsResponse::json(
540            StatusCode::OK,
541            serde_json::to_string(&result).unwrap(),
542        ))
543    }
544
545    fn enable_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
546        let body = body_json(req);
547        let resolved = self.resolve_required_key(&body)?;
548
549        let mut state = self.state.write();
550        let key = state.keys.get_mut(&resolved).unwrap();
551        key.enabled = true;
552        key.key_state = "Enabled".to_string();
553
554        Ok(AwsResponse::json(StatusCode::OK, "{}"))
555    }
556
557    fn disable_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
558        let body = body_json(req);
559        let resolved = self.resolve_required_key(&body)?;
560
561        let mut state = self.state.write();
562        let key = state.keys.get_mut(&resolved).unwrap();
563        key.enabled = false;
564        key.key_state = "Disabled".to_string();
565
566        Ok(AwsResponse::json(StatusCode::OK, "{}"))
567    }
568
569    fn schedule_key_deletion(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
570        let body = body_json(req);
571        let resolved = self.resolve_required_key(&body)?;
572        let pending_days = body["PendingWindowInDays"].as_i64().unwrap_or(30);
573
574        let mut state = self.state.write();
575        let key = state.keys.get_mut(&resolved).unwrap();
576        let deletion_date =
577            Utc::now().timestamp() as f64 + (pending_days as f64 * 24.0 * 60.0 * 60.0);
578        key.key_state = "PendingDeletion".to_string();
579        key.enabled = false;
580        key.deletion_date = Some(deletion_date);
581
582        Ok(AwsResponse::json(
583            StatusCode::OK,
584            serde_json::to_string(&json!({
585                "KeyId": key.key_id,
586                "DeletionDate": deletion_date,
587                "KeyState": "PendingDeletion",
588                "PendingWindowInDays": pending_days,
589            }))
590            .unwrap(),
591        ))
592    }
593
594    fn cancel_key_deletion(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
595        let body = body_json(req);
596        let resolved = self.resolve_required_key(&body)?;
597
598        let mut state = self.state.write();
599        let key = state.keys.get_mut(&resolved).unwrap();
600        key.key_state = "Disabled".to_string();
601        key.deletion_date = None;
602
603        Ok(AwsResponse::json(
604            StatusCode::OK,
605            serde_json::to_string(&json!({
606                "KeyId": key.key_id,
607            }))
608            .unwrap(),
609        ))
610    }
611
612    fn encrypt(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
613        let body = body_json(req);
614        let key_id = Self::require_key_id(&body)?;
615        let plaintext_b64 = body["Plaintext"].as_str().ok_or_else(|| {
616            AwsServiceError::aws_error(
617                StatusCode::BAD_REQUEST,
618                "ValidationException",
619                "Plaintext is required",
620            )
621        })?;
622
623        // Decode the plaintext to check length
624        let plaintext_bytes = base64::engine::general_purpose::STANDARD
625            .decode(plaintext_b64)
626            .unwrap_or_default();
627
628        if plaintext_bytes.is_empty() {
629            return Err(AwsServiceError::aws_error(
630                StatusCode::BAD_REQUEST,
631                "ValidationException",
632                "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1",
633            ));
634        }
635
636        if plaintext_bytes.len() > 4096 {
637            return Err(AwsServiceError::aws_error(
638                StatusCode::BAD_REQUEST,
639                "ValidationException",
640                "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length less than or equal to 4096",
641            ));
642        }
643
644        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
645            AwsServiceError::aws_error(
646                StatusCode::BAD_REQUEST,
647                "NotFoundException",
648                format!("Key '{key_id}' does not exist"),
649            )
650        })?;
651
652        let state = self.state.read();
653        let key = state.keys.get(&resolved).unwrap();
654        if !key.enabled {
655            return Err(AwsServiceError::aws_error(
656                StatusCode::BAD_REQUEST,
657                "DisabledException",
658                format!("Key '{}' is disabled", key.arn),
659            ));
660        }
661
662        // Fake encryption: prefix + key_id + ":" + base64(plaintext_bytes)
663        let envelope = format!("{FAKE_ENVELOPE_PREFIX}{}:{plaintext_b64}", key.key_id);
664        let ciphertext_b64 = base64::engine::general_purpose::STANDARD.encode(envelope.as_bytes());
665
666        Ok(AwsResponse::json(
667            StatusCode::OK,
668            serde_json::to_string(&json!({
669                "CiphertextBlob": ciphertext_b64,
670                "KeyId": key.arn,
671                "EncryptionAlgorithm": "SYMMETRIC_DEFAULT",
672            }))
673            .unwrap(),
674        ))
675    }
676
677    fn decrypt(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
678        let body = body_json(req);
679        let ciphertext_b64 = body["CiphertextBlob"].as_str().ok_or_else(|| {
680            AwsServiceError::aws_error(
681                StatusCode::BAD_REQUEST,
682                "ValidationException",
683                "CiphertextBlob is required",
684            )
685        })?;
686
687        let ciphertext_bytes = base64::engine::general_purpose::STANDARD
688            .decode(ciphertext_b64)
689            .map_err(|_| {
690                AwsServiceError::aws_error(
691                    StatusCode::BAD_REQUEST,
692                    "InvalidCiphertextException",
693                    "The ciphertext is invalid",
694                )
695            })?;
696
697        let envelope = String::from_utf8(ciphertext_bytes).map_err(|_| {
698            AwsServiceError::aws_error(
699                StatusCode::BAD_REQUEST,
700                "InvalidCiphertextException",
701                "The ciphertext is invalid",
702            )
703        })?;
704
705        if !envelope.starts_with(FAKE_ENVELOPE_PREFIX) {
706            return Err(AwsServiceError::aws_error(
707                StatusCode::BAD_REQUEST,
708                "InvalidCiphertextException",
709                "The ciphertext is not a valid FakeCloud KMS ciphertext",
710            ));
711        }
712
713        let rest = &envelope[FAKE_ENVELOPE_PREFIX.len()..];
714        let (key_id, plaintext_b64) = rest.split_once(':').ok_or_else(|| {
715            AwsServiceError::aws_error(
716                StatusCode::BAD_REQUEST,
717                "InvalidCiphertextException",
718                "The ciphertext is invalid",
719            )
720        })?;
721
722        let state = self.state.read();
723        let key = state.keys.get(key_id).ok_or_else(|| {
724            AwsServiceError::aws_error(
725                StatusCode::BAD_REQUEST,
726                "NotFoundException",
727                format!("Key '{key_id}' does not exist"),
728            )
729        })?;
730
731        Ok(AwsResponse::json(
732            StatusCode::OK,
733            serde_json::to_string(&json!({
734                "Plaintext": plaintext_b64,
735                "KeyId": key.arn,
736                "EncryptionAlgorithm": "SYMMETRIC_DEFAULT",
737            }))
738            .unwrap(),
739        ))
740    }
741
742    fn re_encrypt(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
743        let body = body_json(req);
744        let ciphertext_b64 = body["CiphertextBlob"].as_str().ok_or_else(|| {
745            AwsServiceError::aws_error(
746                StatusCode::BAD_REQUEST,
747                "ValidationException",
748                "CiphertextBlob is required",
749            )
750        })?;
751        let dest_key_id = body["DestinationKeyId"].as_str().ok_or_else(|| {
752            AwsServiceError::aws_error(
753                StatusCode::BAD_REQUEST,
754                "ValidationException",
755                "DestinationKeyId is required",
756            )
757        })?;
758
759        // Decrypt
760        let ciphertext_bytes = base64::engine::general_purpose::STANDARD
761            .decode(ciphertext_b64)
762            .map_err(|_| {
763                AwsServiceError::aws_error(
764                    StatusCode::BAD_REQUEST,
765                    "InvalidCiphertextException",
766                    "The ciphertext is invalid",
767                )
768            })?;
769
770        let envelope = String::from_utf8(ciphertext_bytes).map_err(|_| {
771            AwsServiceError::aws_error(
772                StatusCode::BAD_REQUEST,
773                "InvalidCiphertextException",
774                "The ciphertext is invalid",
775            )
776        })?;
777
778        if !envelope.starts_with(FAKE_ENVELOPE_PREFIX) {
779            return Err(AwsServiceError::aws_error(
780                StatusCode::BAD_REQUEST,
781                "InvalidCiphertextException",
782                "The ciphertext is invalid",
783            ));
784        }
785
786        let rest = &envelope[FAKE_ENVELOPE_PREFIX.len()..];
787        let (source_key_id, plaintext_b64) = rest.split_once(':').ok_or_else(|| {
788            AwsServiceError::aws_error(
789                StatusCode::BAD_REQUEST,
790                "InvalidCiphertextException",
791                "The ciphertext is invalid",
792            )
793        })?;
794
795        let state = self.state.read();
796
797        let source_key = state.keys.get(source_key_id).ok_or_else(|| {
798            AwsServiceError::aws_error(
799                StatusCode::BAD_REQUEST,
800                "NotFoundException",
801                format!("Key '{source_key_id}' does not exist"),
802            )
803        })?;
804        let source_arn = source_key.arn.clone();
805
806        // Resolve destination
807        let dest_resolved =
808            Self::resolve_key_id_with_state(&state, dest_key_id).ok_or_else(|| {
809                AwsServiceError::aws_error(
810                    StatusCode::BAD_REQUEST,
811                    "NotFoundException",
812                    format!("Key '{dest_key_id}' does not exist"),
813                )
814            })?;
815
816        let dest_key = state.keys.get(&dest_resolved).unwrap();
817
818        // Re-encrypt with destination key
819        let new_envelope = format!("{FAKE_ENVELOPE_PREFIX}{}:{plaintext_b64}", dest_key.key_id);
820        let new_ciphertext_b64 =
821            base64::engine::general_purpose::STANDARD.encode(new_envelope.as_bytes());
822
823        Ok(AwsResponse::json(
824            StatusCode::OK,
825            serde_json::to_string(&json!({
826                "CiphertextBlob": new_ciphertext_b64,
827                "KeyId": dest_key.arn,
828                "SourceKeyId": source_arn,
829                "SourceEncryptionAlgorithm": "SYMMETRIC_DEFAULT",
830                "DestinationEncryptionAlgorithm": "SYMMETRIC_DEFAULT",
831            }))
832            .unwrap(),
833        ))
834    }
835
836    fn generate_data_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
837        let body = body_json(req);
838        let key_id = Self::require_key_id(&body)?;
839
840        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
841            AwsServiceError::aws_error(
842                StatusCode::BAD_REQUEST,
843                "NotFoundException",
844                format!("Key '{key_id}' does not exist"),
845            )
846        })?;
847
848        let state = self.state.read();
849        let key = state.keys.get(&resolved).unwrap();
850        if !key.enabled {
851            return Err(AwsServiceError::aws_error(
852                StatusCode::BAD_REQUEST,
853                "DisabledException",
854                format!("Key '{}' is disabled", key.arn),
855            ));
856        }
857
858        let num_bytes = data_key_size_from_body(&body)?;
859
860        let data_key_bytes: Vec<u8> = rand_bytes(num_bytes);
861        let plaintext_b64 = base64::engine::general_purpose::STANDARD.encode(&data_key_bytes);
862
863        // Encrypt the data key
864        let envelope = format!("{FAKE_ENVELOPE_PREFIX}{}:{plaintext_b64}", key.key_id);
865        let ciphertext_b64 = base64::engine::general_purpose::STANDARD.encode(envelope.as_bytes());
866
867        Ok(AwsResponse::json(
868            StatusCode::OK,
869            serde_json::to_string(&json!({
870                "Plaintext": plaintext_b64,
871                "CiphertextBlob": ciphertext_b64,
872                "KeyId": key.arn,
873            }))
874            .unwrap(),
875        ))
876    }
877
878    fn generate_data_key_without_plaintext(
879        &self,
880        req: &AwsRequest,
881    ) -> Result<AwsResponse, AwsServiceError> {
882        let body = body_json(req);
883        let key_id = Self::require_key_id(&body)?;
884
885        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
886            AwsServiceError::aws_error(
887                StatusCode::BAD_REQUEST,
888                "NotFoundException",
889                format!("Key '{key_id}' does not exist"),
890            )
891        })?;
892
893        let state = self.state.read();
894        let key = state.keys.get(&resolved).unwrap();
895        if !key.enabled {
896            return Err(AwsServiceError::aws_error(
897                StatusCode::BAD_REQUEST,
898                "DisabledException",
899                format!("Key '{}' is disabled", key.arn),
900            ));
901        }
902
903        let num_bytes = data_key_size_from_body(&body)?;
904        let data_key_bytes: Vec<u8> = rand_bytes(num_bytes);
905        let plaintext_b64 = base64::engine::general_purpose::STANDARD.encode(&data_key_bytes);
906        let envelope = format!("{FAKE_ENVELOPE_PREFIX}{}:{plaintext_b64}", key.key_id);
907        let ciphertext_b64 = base64::engine::general_purpose::STANDARD.encode(envelope.as_bytes());
908
909        Ok(AwsResponse::json(
910            StatusCode::OK,
911            serde_json::to_string(&json!({
912                "CiphertextBlob": ciphertext_b64,
913                "KeyId": key.arn,
914            }))
915            .unwrap(),
916        ))
917    }
918
919    fn generate_random(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
920        let body = body_json(req);
921
922        // CustomKeyStoreId is accepted for API compatibility but has no effect on
923        // random number generation in this emulator.
924        validate_optional_string_length(
925            "customKeyStoreId",
926            body["CustomKeyStoreId"].as_str(),
927            1,
928            64,
929        )?;
930
931        let num_bytes = body["NumberOfBytes"].as_u64().unwrap_or(32) as usize;
932
933        validate_range_i64("numberOfBytes", num_bytes as i64, 1, 1024)?;
934
935        let random_bytes = rand_bytes(num_bytes);
936        let b64 = base64::engine::general_purpose::STANDARD.encode(&random_bytes);
937
938        Ok(AwsResponse::json(
939            StatusCode::OK,
940            serde_json::to_string(&json!({
941                "Plaintext": b64,
942            }))
943            .unwrap(),
944        ))
945    }
946
947    fn create_alias(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
948        let body = body_json(req);
949        let alias_name = body["AliasName"]
950            .as_str()
951            .ok_or_else(|| {
952                AwsServiceError::aws_error(
953                    StatusCode::BAD_REQUEST,
954                    "ValidationException",
955                    "AliasName is required",
956                )
957            })?
958            .to_string();
959        let target_key_id = body["TargetKeyId"]
960            .as_str()
961            .ok_or_else(|| {
962                AwsServiceError::aws_error(
963                    StatusCode::BAD_REQUEST,
964                    "ValidationException",
965                    "TargetKeyId is required",
966                )
967            })?
968            .to_string();
969
970        // Validate prefix
971        if !alias_name.starts_with("alias/") {
972            return Err(AwsServiceError::aws_error(
973                StatusCode::BAD_REQUEST,
974                "ValidationException",
975                "Invalid identifier",
976            ));
977        }
978
979        // Check for reserved aliases
980        if alias_name.starts_with("alias/aws/") {
981            return Err(AwsServiceError::aws_error(
982                StatusCode::BAD_REQUEST,
983                "NotAuthorizedException",
984                "",
985            ));
986        }
987
988        // Check for restricted characters
989        let alias_suffix = &alias_name["alias/".len()..];
990        if alias_suffix.contains(':') {
991            return Err(AwsServiceError::aws_error(
992                StatusCode::BAD_REQUEST,
993                "ValidationException",
994                format!("{alias_name} contains invalid characters for an alias"),
995            ));
996        }
997
998        // Check regex pattern
999        let valid_chars = alias_name
1000            .chars()
1001            .all(|c| c.is_alphanumeric() || c == '/' || c == '_' || c == '-' || c == ':');
1002        if !valid_chars {
1003            return Err(AwsServiceError::aws_error(
1004                StatusCode::BAD_REQUEST,
1005                "ValidationException",
1006                format!(
1007                    "1 validation error detected: Value '{}' at 'aliasName' failed to satisfy constraint: Member must satisfy regular expression pattern: ^[a-zA-Z0-9:/_-]+$",
1008                    alias_name
1009                ),
1010            ));
1011        }
1012
1013        // Check if target is an alias
1014        if target_key_id.starts_with("alias/") {
1015            return Err(AwsServiceError::aws_error(
1016                StatusCode::BAD_REQUEST,
1017                "ValidationException",
1018                "Aliases must refer to keys. Not aliases",
1019            ));
1020        }
1021
1022        let resolved = self.resolve_key_id(&target_key_id).ok_or_else(|| {
1023            AwsServiceError::aws_error(
1024                StatusCode::BAD_REQUEST,
1025                "NotFoundException",
1026                format!("Key '{target_key_id}' does not exist"),
1027            )
1028        })?;
1029
1030        let mut state = self.state.write();
1031
1032        if state.aliases.contains_key(&alias_name) {
1033            let alias_arn = format!(
1034                "arn:aws:kms:{}:{}:{}",
1035                state.region, state.account_id, alias_name
1036            );
1037            return Err(AwsServiceError::aws_error(
1038                StatusCode::BAD_REQUEST,
1039                "AlreadyExistsException",
1040                format!("An alias with the name {alias_arn} already exists"),
1041            ));
1042        }
1043
1044        let alias_arn = format!(
1045            "arn:aws:kms:{}:{}:{}",
1046            state.region, state.account_id, alias_name
1047        );
1048
1049        state.aliases.insert(
1050            alias_name.clone(),
1051            KmsAlias {
1052                alias_name,
1053                alias_arn,
1054                target_key_id: resolved,
1055                creation_date: Utc::now().timestamp() as f64,
1056            },
1057        );
1058
1059        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1060    }
1061
1062    fn delete_alias(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1063        let body = body_json(req);
1064        let alias_name = body["AliasName"].as_str().ok_or_else(|| {
1065            AwsServiceError::aws_error(
1066                StatusCode::BAD_REQUEST,
1067                "ValidationException",
1068                "AliasName is required",
1069            )
1070        })?;
1071
1072        if !alias_name.starts_with("alias/") {
1073            return Err(AwsServiceError::aws_error(
1074                StatusCode::BAD_REQUEST,
1075                "ValidationException",
1076                "Invalid identifier",
1077            ));
1078        }
1079
1080        let mut state = self.state.write();
1081        if state.aliases.remove(alias_name).is_none() {
1082            let alias_arn = format!(
1083                "arn:aws:kms:{}:{}:{}",
1084                state.region, state.account_id, alias_name
1085            );
1086            return Err(AwsServiceError::aws_error(
1087                StatusCode::BAD_REQUEST,
1088                "NotFoundException",
1089                format!("Alias {alias_arn} is not found."),
1090            ));
1091        }
1092
1093        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1094    }
1095
1096    fn update_alias(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1097        let body = body_json(req);
1098        let alias_name = body["AliasName"].as_str().ok_or_else(|| {
1099            AwsServiceError::aws_error(
1100                StatusCode::BAD_REQUEST,
1101                "ValidationException",
1102                "AliasName is required",
1103            )
1104        })?;
1105        let target_key_id = body["TargetKeyId"].as_str().ok_or_else(|| {
1106            AwsServiceError::aws_error(
1107                StatusCode::BAD_REQUEST,
1108                "ValidationException",
1109                "TargetKeyId is required",
1110            )
1111        })?;
1112
1113        let resolved = self.resolve_key_id(target_key_id).ok_or_else(|| {
1114            AwsServiceError::aws_error(
1115                StatusCode::BAD_REQUEST,
1116                "NotFoundException",
1117                format!("Key '{target_key_id}' does not exist"),
1118            )
1119        })?;
1120
1121        let mut state = self.state.write();
1122        let alias = state.aliases.get_mut(alias_name).ok_or_else(|| {
1123            AwsServiceError::aws_error(
1124                StatusCode::BAD_REQUEST,
1125                "NotFoundException",
1126                format!("Alias '{alias_name}' does not exist"),
1127            )
1128        })?;
1129
1130        alias.target_key_id = resolved;
1131
1132        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1133    }
1134
1135    fn list_aliases(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1136        let body = body_json(req);
1137
1138        validate_optional_range_i64("limit", body["Limit"].as_i64(), 1, 100)?;
1139        validate_optional_string_length("marker", body["Marker"].as_str(), 1, 320)?;
1140
1141        if !body["KeyId"].is_null() && !body["KeyId"].is_string() {
1142            return Err(AwsServiceError::aws_error(
1143                StatusCode::BAD_REQUEST,
1144                "ValidationException",
1145                "KeyId must be a string",
1146            ));
1147        }
1148        validate_optional_string_length("keyId", body["KeyId"].as_str(), 1, 2048)?;
1149
1150        let key_id_filter = body["KeyId"].as_str();
1151
1152        let state = self.state.read();
1153
1154        // Resolve key_id_filter to actual key ID if needed
1155        let resolved_filter =
1156            key_id_filter.and_then(|kid| Self::resolve_key_id_with_state(&state, kid));
1157
1158        let aliases: Vec<Value> = state
1159            .aliases
1160            .values()
1161            .filter(|a| match (&resolved_filter, key_id_filter) {
1162                (Some(r), _) => a.target_key_id == *r,
1163                (None, Some(_)) => false,
1164                (None, None) => true,
1165            })
1166            .map(|a| {
1167                json!({
1168                    "AliasName": a.alias_name,
1169                    "AliasArn": a.alias_arn,
1170                    "TargetKeyId": a.target_key_id,
1171                })
1172            })
1173            .collect();
1174
1175        Ok(AwsResponse::json(
1176            StatusCode::OK,
1177            serde_json::to_string(&json!({
1178                "Aliases": aliases,
1179                "Truncated": false,
1180            }))
1181            .unwrap(),
1182        ))
1183    }
1184
1185    fn tag_resource(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1186        let body = body_json(req);
1187        let key_id = Self::require_key_id(&body)?;
1188
1189        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1190            AwsServiceError::aws_error(
1191                StatusCode::BAD_REQUEST,
1192                "NotFoundException",
1193                format!("Invalid keyId {key_id}"),
1194            )
1195        })?;
1196
1197        let tags = body["Tags"].as_array();
1198
1199        let mut state = self.state.write();
1200        let key = state.keys.get_mut(&resolved).unwrap();
1201        if let Some(tags) = tags {
1202            for tag in tags {
1203                if let (Some(k), Some(v)) = (tag["TagKey"].as_str(), tag["TagValue"].as_str()) {
1204                    key.tags.insert(k.to_string(), v.to_string());
1205                }
1206            }
1207        }
1208
1209        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1210    }
1211
1212    fn untag_resource(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1213        let body = body_json(req);
1214        let key_id = Self::require_key_id(&body)?;
1215
1216        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1217            AwsServiceError::aws_error(
1218                StatusCode::BAD_REQUEST,
1219                "NotFoundException",
1220                format!("Invalid keyId {key_id}"),
1221            )
1222        })?;
1223
1224        let tag_keys = body["TagKeys"].as_array();
1225
1226        let mut state = self.state.write();
1227        let key = state.keys.get_mut(&resolved).unwrap();
1228        if let Some(tag_keys) = tag_keys {
1229            for tag_key in tag_keys {
1230                if let Some(k) = tag_key.as_str() {
1231                    key.tags.remove(k);
1232                }
1233            }
1234        }
1235
1236        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1237    }
1238
1239    fn list_resource_tags(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1240        let body = body_json(req);
1241        let key_id = Self::require_key_id(&body)?;
1242
1243        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1244            AwsServiceError::aws_error(
1245                StatusCode::BAD_REQUEST,
1246                "NotFoundException",
1247                format!("Invalid keyId {key_id}"),
1248            )
1249        })?;
1250
1251        let state = self.state.read();
1252        let key = state.keys.get(&resolved).unwrap();
1253        let mut sorted_tags: Vec<(&String, &String)> = key.tags.iter().collect();
1254        sorted_tags.sort_by_key(|(k, _)| (*k).clone());
1255        let tags: Vec<Value> = sorted_tags
1256            .iter()
1257            .map(|(k, v)| {
1258                json!({
1259                    "TagKey": k,
1260                    "TagValue": v,
1261                })
1262            })
1263            .collect();
1264
1265        Ok(AwsResponse::json(
1266            StatusCode::OK,
1267            serde_json::to_string(&json!({
1268                "Tags": tags,
1269                "Truncated": false,
1270            }))
1271            .unwrap(),
1272        ))
1273    }
1274
1275    fn update_key_description(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1276        let body = body_json(req);
1277        let resolved = self.resolve_required_key(&body)?;
1278        let description = body["Description"].as_str().unwrap_or("").to_string();
1279
1280        let mut state = self.state.write();
1281        let key = state.keys.get_mut(&resolved).unwrap();
1282        key.description = description;
1283
1284        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1285    }
1286
1287    fn get_key_policy(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1288        let body = body_json(req);
1289        let key_id = Self::require_key_id(&body)?;
1290
1291        // For key policy operations, aliases should not work
1292        if key_id.starts_with("alias/") {
1293            return Err(AwsServiceError::aws_error(
1294                StatusCode::BAD_REQUEST,
1295                "NotFoundException",
1296                format!("Invalid keyId {key_id}"),
1297            ));
1298        }
1299
1300        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1301            AwsServiceError::aws_error(
1302                StatusCode::BAD_REQUEST,
1303                "NotFoundException",
1304                format!("Key '{key_id}' does not exist"),
1305            )
1306        })?;
1307
1308        let state = self.state.read();
1309        let key = state.keys.get(&resolved).unwrap();
1310
1311        Ok(AwsResponse::json(
1312            StatusCode::OK,
1313            serde_json::to_string(&json!({
1314                "Policy": key.policy,
1315            }))
1316            .unwrap(),
1317        ))
1318    }
1319
1320    fn put_key_policy(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1321        let body = body_json(req);
1322        let key_id = Self::require_key_id(&body)?;
1323
1324        // For key policy operations, aliases should not work
1325        if key_id.starts_with("alias/") {
1326            return Err(AwsServiceError::aws_error(
1327                StatusCode::BAD_REQUEST,
1328                "NotFoundException",
1329                format!("Invalid keyId {key_id}"),
1330            ));
1331        }
1332
1333        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1334            AwsServiceError::aws_error(
1335                StatusCode::BAD_REQUEST,
1336                "NotFoundException",
1337                format!("Key '{key_id}' does not exist"),
1338            )
1339        })?;
1340
1341        let policy = body["Policy"].as_str().unwrap_or("").to_string();
1342
1343        let mut state = self.state.write();
1344        let key = state.keys.get_mut(&resolved).unwrap();
1345        key.policy = policy;
1346
1347        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1348    }
1349
1350    fn list_key_policies(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1351        let body = body_json(req);
1352        let _resolved = self.resolve_required_key(&body)?;
1353
1354        Ok(AwsResponse::json(
1355            StatusCode::OK,
1356            serde_json::to_string(&json!({
1357                "PolicyNames": ["default"],
1358                "Truncated": false,
1359            }))
1360            .unwrap(),
1361        ))
1362    }
1363
1364    fn get_key_rotation_status(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1365        let body = body_json(req);
1366        let key_id = Self::require_key_id(&body)?;
1367
1368        // Aliases should fail for rotation operations
1369        if key_id.starts_with("alias/") {
1370            return Err(AwsServiceError::aws_error(
1371                StatusCode::BAD_REQUEST,
1372                "NotFoundException",
1373                format!("Invalid keyId {key_id}"),
1374            ));
1375        }
1376
1377        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1378            AwsServiceError::aws_error(
1379                StatusCode::BAD_REQUEST,
1380                "NotFoundException",
1381                format!("Key '{key_id}' does not exist"),
1382            )
1383        })?;
1384
1385        let state = self.state.read();
1386        let key = state.keys.get(&resolved).unwrap();
1387
1388        Ok(AwsResponse::json(
1389            StatusCode::OK,
1390            serde_json::to_string(&json!({
1391                "KeyRotationEnabled": key.key_rotation_enabled,
1392            }))
1393            .unwrap(),
1394        ))
1395    }
1396
1397    fn enable_key_rotation(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1398        let body = body_json(req);
1399        let key_id = Self::require_key_id(&body)?;
1400
1401        if key_id.starts_with("alias/") {
1402            return Err(AwsServiceError::aws_error(
1403                StatusCode::BAD_REQUEST,
1404                "NotFoundException",
1405                format!("Invalid keyId {key_id}"),
1406            ));
1407        }
1408
1409        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1410            AwsServiceError::aws_error(
1411                StatusCode::BAD_REQUEST,
1412                "NotFoundException",
1413                format!("Key '{key_id}' does not exist"),
1414            )
1415        })?;
1416
1417        let mut state = self.state.write();
1418        let key = state.keys.get_mut(&resolved).unwrap();
1419        key.key_rotation_enabled = true;
1420
1421        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1422    }
1423
1424    fn disable_key_rotation(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1425        let body = body_json(req);
1426        let key_id = Self::require_key_id(&body)?;
1427
1428        if key_id.starts_with("alias/") {
1429            return Err(AwsServiceError::aws_error(
1430                StatusCode::BAD_REQUEST,
1431                "NotFoundException",
1432                format!("Invalid keyId {key_id}"),
1433            ));
1434        }
1435
1436        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1437            AwsServiceError::aws_error(
1438                StatusCode::BAD_REQUEST,
1439                "NotFoundException",
1440                format!("Key '{key_id}' does not exist"),
1441            )
1442        })?;
1443
1444        let mut state = self.state.write();
1445        let key = state.keys.get_mut(&resolved).unwrap();
1446        key.key_rotation_enabled = false;
1447
1448        Ok(AwsResponse::json(StatusCode::OK, "{}"))
1449    }
1450
1451    fn rotate_key_on_demand(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1452        let body = body_json(req);
1453        let resolved = self.resolve_required_key(&body)?;
1454
1455        let mut state = self.state.write();
1456        let key = state.keys.get_mut(&resolved).unwrap();
1457
1458        let rotation = KeyRotation {
1459            key_id: key.key_id.clone(),
1460            rotation_date: Utc::now().timestamp() as f64,
1461            rotation_type: "ON_DEMAND".to_string(),
1462        };
1463        key.rotations.push(rotation);
1464
1465        Ok(AwsResponse::json(
1466            StatusCode::OK,
1467            serde_json::to_string(&json!({
1468                "KeyId": key.key_id,
1469            }))
1470            .unwrap(),
1471        ))
1472    }
1473
1474    fn list_key_rotations(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1475        let body = body_json(req);
1476        let resolved = self.resolve_required_key(&body)?;
1477        let limit = body["Limit"].as_u64().unwrap_or(1000) as usize;
1478        let marker = body["Marker"].as_str();
1479
1480        let state = self.state.read();
1481        let key = state.keys.get(&resolved).unwrap();
1482
1483        let start_index = if let Some(marker) = marker {
1484            marker.parse::<usize>().unwrap_or(0)
1485        } else {
1486            0
1487        };
1488
1489        let rotations: Vec<Value> = key
1490            .rotations
1491            .iter()
1492            .skip(start_index)
1493            .take(limit)
1494            .map(|r| {
1495                json!({
1496                    "KeyId": r.key_id,
1497                    "RotationDate": r.rotation_date,
1498                    "RotationType": r.rotation_type,
1499                })
1500            })
1501            .collect();
1502
1503        let total_after_start = key.rotations.len().saturating_sub(start_index);
1504        let truncated = total_after_start > limit;
1505
1506        let mut response = json!({
1507            "Rotations": rotations,
1508            "Truncated": truncated,
1509        });
1510
1511        if truncated {
1512            response["NextMarker"] = json!((start_index + limit).to_string());
1513        }
1514
1515        Ok(AwsResponse::json(
1516            StatusCode::OK,
1517            serde_json::to_string(&response).unwrap(),
1518        ))
1519    }
1520
1521    fn sign(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1522        let body = body_json(req);
1523        let key_id = Self::require_key_id(&body)?;
1524        let message_b64 = body["Message"].as_str().unwrap_or("");
1525        let signing_algorithm = body["SigningAlgorithm"].as_str().unwrap_or("");
1526
1527        // Validate message
1528        let message_bytes = base64::engine::general_purpose::STANDARD
1529            .decode(message_b64)
1530            .unwrap_or_default();
1531
1532        if message_bytes.is_empty() {
1533            return Err(AwsServiceError::aws_error(
1534                StatusCode::BAD_REQUEST,
1535                "ValidationException",
1536                "1 validation error detected: Value at 'Message' failed to satisfy constraint: Member must have length greater than or equal to 1",
1537            ));
1538        }
1539
1540        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1541            AwsServiceError::aws_error(
1542                StatusCode::BAD_REQUEST,
1543                "NotFoundException",
1544                format!("Key '{key_id}' does not exist"),
1545            )
1546        })?;
1547
1548        let state = self.state.read();
1549        let key = state.keys.get(&resolved).unwrap();
1550
1551        // Validate key usage
1552        if key.key_usage != "SIGN_VERIFY" {
1553            return Err(AwsServiceError::aws_error(
1554                StatusCode::BAD_REQUEST,
1555                "ValidationException",
1556                format!(
1557                    "1 validation error detected: Value '{}' at 'KeyId' failed to satisfy constraint: Member must point to a key with usage: 'SIGN_VERIFY'",
1558                    resolved
1559                ),
1560            ));
1561        }
1562
1563        // Validate signing algorithm against key's supported algorithms
1564        let valid_algs = key.signing_algorithms.as_deref().unwrap_or(&[]);
1565        if !valid_algs.iter().any(|a| a == signing_algorithm) {
1566            let set: Vec<String> = if valid_algs.is_empty() {
1567                VALID_SIGNING_ALGORITHMS
1568                    .iter()
1569                    .map(|s| s.to_string())
1570                    .collect()
1571            } else {
1572                valid_algs.to_vec()
1573            };
1574            return Err(AwsServiceError::aws_error(
1575                StatusCode::BAD_REQUEST,
1576                "ValidationException",
1577                format!(
1578                    "1 validation error detected: Value '{}' at 'SigningAlgorithm' failed to satisfy constraint: Member must satisfy enum value set: {}",
1579                    signing_algorithm, fmt_enum_set(&set)
1580                ),
1581            ));
1582        }
1583
1584        // Generate a fake signature
1585        let sig_data = format!(
1586            "fakecloud-sig:{}:{}:{}",
1587            key.key_id, signing_algorithm, message_b64
1588        );
1589        let signature_b64 = base64::engine::general_purpose::STANDARD.encode(sig_data.as_bytes());
1590
1591        Ok(AwsResponse::json(
1592            StatusCode::OK,
1593            serde_json::to_string(&json!({
1594                "Signature": signature_b64,
1595                "SigningAlgorithm": signing_algorithm,
1596                "KeyId": key.arn,
1597            }))
1598            .unwrap(),
1599        ))
1600    }
1601
1602    fn verify(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1603        let body = body_json(req);
1604        let key_id = Self::require_key_id(&body)?;
1605        let message_b64 = body["Message"].as_str().unwrap_or("");
1606        let signature_b64 = body["Signature"].as_str().unwrap_or("");
1607        let signing_algorithm = body["SigningAlgorithm"].as_str().unwrap_or("");
1608
1609        // Validate message
1610        let message_bytes = base64::engine::general_purpose::STANDARD
1611            .decode(message_b64)
1612            .unwrap_or_default();
1613
1614        if message_bytes.is_empty() {
1615            return Err(AwsServiceError::aws_error(
1616                StatusCode::BAD_REQUEST,
1617                "ValidationException",
1618                "1 validation error detected: Value at 'Message' failed to satisfy constraint: Member must have length greater than or equal to 1",
1619            ));
1620        }
1621
1622        // Validate signature
1623        let sig_bytes = base64::engine::general_purpose::STANDARD
1624            .decode(signature_b64)
1625            .unwrap_or_default();
1626        if sig_bytes.is_empty() {
1627            return Err(AwsServiceError::aws_error(
1628                StatusCode::BAD_REQUEST,
1629                "ValidationException",
1630                "1 validation error detected: Value at 'Signature' failed to satisfy constraint: Member must have length greater than or equal to 1",
1631            ));
1632        }
1633
1634        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1635            AwsServiceError::aws_error(
1636                StatusCode::BAD_REQUEST,
1637                "NotFoundException",
1638                format!("Key '{key_id}' does not exist"),
1639            )
1640        })?;
1641
1642        let state = self.state.read();
1643        let key = state.keys.get(&resolved).unwrap();
1644
1645        // Validate key usage
1646        if key.key_usage != "SIGN_VERIFY" {
1647            return Err(AwsServiceError::aws_error(
1648                StatusCode::BAD_REQUEST,
1649                "ValidationException",
1650                format!(
1651                    "1 validation error detected: Value '{}' at 'KeyId' failed to satisfy constraint: Member must point to a key with usage: 'SIGN_VERIFY'",
1652                    resolved
1653                ),
1654            ));
1655        }
1656
1657        // Validate signing algorithm
1658        let valid_algs = key.signing_algorithms.as_deref().unwrap_or(&[]);
1659        if !valid_algs.iter().any(|a| a == signing_algorithm) {
1660            let set: Vec<String> = if valid_algs.is_empty() {
1661                VALID_SIGNING_ALGORITHMS
1662                    .iter()
1663                    .map(|s| s.to_string())
1664                    .collect()
1665            } else {
1666                valid_algs.to_vec()
1667            };
1668            return Err(AwsServiceError::aws_error(
1669                StatusCode::BAD_REQUEST,
1670                "ValidationException",
1671                format!(
1672                    "1 validation error detected: Value '{}' at 'SigningAlgorithm' failed to satisfy constraint: Member must satisfy enum value set: {}",
1673                    signing_algorithm, fmt_enum_set(&set)
1674                ),
1675            ));
1676        }
1677
1678        // Check if signature matches
1679        let expected_sig_data = format!(
1680            "fakecloud-sig:{}:{}:{}",
1681            key.key_id, signing_algorithm, message_b64
1682        );
1683        let expected_signature_b64 =
1684            base64::engine::general_purpose::STANDARD.encode(expected_sig_data.as_bytes());
1685
1686        let signature_valid = signature_b64 == expected_signature_b64;
1687
1688        Ok(AwsResponse::json(
1689            StatusCode::OK,
1690            serde_json::to_string(&json!({
1691                "SignatureValid": signature_valid,
1692                "SigningAlgorithm": signing_algorithm,
1693                "KeyId": key.arn,
1694            }))
1695            .unwrap(),
1696        ))
1697    }
1698
1699    fn get_public_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1700        let body = body_json(req);
1701        let key_id = Self::require_key_id(&body)?;
1702
1703        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1704            AwsServiceError::aws_error(
1705                StatusCode::BAD_REQUEST,
1706                "NotFoundException",
1707                format!("Key '{key_id}' does not exist"),
1708            )
1709        })?;
1710
1711        let state = self.state.read();
1712        let key = state.keys.get(&resolved).unwrap();
1713
1714        // Generate a fake DER-encoded public key
1715        let fake_public_key = generate_fake_public_key(&key.key_spec);
1716        let public_key_b64 = base64::engine::general_purpose::STANDARD.encode(&fake_public_key);
1717
1718        let mut response = json!({
1719            "KeyId": key.arn,
1720            "KeySpec": key.key_spec,
1721            "KeyUsage": key.key_usage,
1722            "PublicKey": public_key_b64,
1723            "CustomerMasterKeySpec": key.key_spec,
1724        });
1725
1726        if let Some(ref signing_algs) = key.signing_algorithms {
1727            response["SigningAlgorithms"] = json!(signing_algs);
1728        }
1729        if let Some(ref enc_algs) = key.encryption_algorithms {
1730            response["EncryptionAlgorithms"] = json!(enc_algs);
1731        }
1732
1733        Ok(AwsResponse::json(
1734            StatusCode::OK,
1735            serde_json::to_string(&response).unwrap(),
1736        ))
1737    }
1738
1739    fn create_grant(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1740        let body = body_json(req);
1741        let key_id = Self::require_key_id(&body)?;
1742
1743        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1744            AwsServiceError::aws_error(
1745                StatusCode::BAD_REQUEST,
1746                "NotFoundException",
1747                format!("Key '{key_id}' does not exist"),
1748            )
1749        })?;
1750
1751        let grantee_principal = body["GranteePrincipal"].as_str().unwrap_or("").to_string();
1752        let retiring_principal = body["RetiringPrincipal"].as_str().map(|s| s.to_string());
1753        let operations: Vec<String> = body["Operations"]
1754            .as_array()
1755            .map(|arr| {
1756                arr.iter()
1757                    .filter_map(|v| v.as_str().map(|s| s.to_string()))
1758                    .collect()
1759            })
1760            .unwrap_or_default();
1761        let constraints = if body["Constraints"].is_null() {
1762            None
1763        } else {
1764            Some(body["Constraints"].clone())
1765        };
1766        let name = body["Name"].as_str().map(|s| s.to_string());
1767
1768        let grant_id = Uuid::new_v4().to_string();
1769        let grant_token = Uuid::new_v4().to_string();
1770
1771        let mut state = self.state.write();
1772        state.grants.push(KmsGrant {
1773            grant_id: grant_id.clone(),
1774            grant_token: grant_token.clone(),
1775            key_id: resolved,
1776            grantee_principal,
1777            retiring_principal,
1778            operations,
1779            constraints,
1780            name,
1781            creation_date: Utc::now().timestamp() as f64,
1782        });
1783
1784        Ok(AwsResponse::json(
1785            StatusCode::OK,
1786            serde_json::to_string(&json!({
1787                "GrantId": grant_id,
1788                "GrantToken": grant_token,
1789            }))
1790            .unwrap(),
1791        ))
1792    }
1793
1794    fn list_grants(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1795        let body = body_json(req);
1796        let key_id = Self::require_key_id(&body)?;
1797
1798        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1799            AwsServiceError::aws_error(
1800                StatusCode::BAD_REQUEST,
1801                "NotFoundException",
1802                format!("Key '{key_id}' does not exist"),
1803            )
1804        })?;
1805
1806        let grant_id_filter = body["GrantId"].as_str();
1807
1808        let state = self.state.read();
1809        let grants: Vec<Value> = state
1810            .grants
1811            .iter()
1812            .filter(|g| g.key_id == resolved)
1813            .filter(|g| {
1814                if let Some(gid) = grant_id_filter {
1815                    g.grant_id == gid
1816                } else {
1817                    true
1818                }
1819            })
1820            .map(grant_to_json)
1821            .collect();
1822
1823        Ok(AwsResponse::json(
1824            StatusCode::OK,
1825            serde_json::to_string(&json!({
1826                "Grants": grants,
1827                "Truncated": false,
1828            }))
1829            .unwrap(),
1830        ))
1831    }
1832
1833    fn list_retirable_grants(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1834        let body = body_json(req);
1835
1836        validate_required("RetiringPrincipal", &body["RetiringPrincipal"])?;
1837        let retiring_principal = body["RetiringPrincipal"].as_str().ok_or_else(|| {
1838            AwsServiceError::aws_error(
1839                StatusCode::BAD_REQUEST,
1840                "ValidationException",
1841                "RetiringPrincipal must be a string",
1842            )
1843        })?;
1844        validate_string_length("retiringPrincipal", retiring_principal, 1, 256)?;
1845        validate_optional_range_i64("limit", body["Limit"].as_i64(), 1, 1000)?;
1846        validate_optional_string_length("marker", body["Marker"].as_str(), 1, 320)?;
1847
1848        let limit = body["Limit"].as_u64().unwrap_or(1000) as usize;
1849        let marker = body["Marker"].as_str();
1850
1851        let state = self.state.read();
1852        let all_grants: Vec<Value> = state
1853            .grants
1854            .iter()
1855            .filter(|g| {
1856                g.retiring_principal
1857                    .as_deref()
1858                    .is_some_and(|rp| rp == retiring_principal)
1859            })
1860            .map(grant_to_json)
1861            .collect();
1862
1863        let start = if let Some(m) = marker {
1864            all_grants
1865                .iter()
1866                .position(|g| g["GrantId"].as_str() == Some(m))
1867                .map(|pos| pos + 1)
1868                .unwrap_or(0)
1869        } else {
1870            0
1871        };
1872
1873        let page = &all_grants[start..all_grants.len().min(start + limit)];
1874        let truncated = start + limit < all_grants.len();
1875
1876        let mut result = json!({
1877            "Grants": page,
1878            "Truncated": truncated,
1879        });
1880
1881        if truncated {
1882            if let Some(last) = page.last() {
1883                result["NextMarker"] = last["GrantId"].clone();
1884            }
1885        }
1886
1887        Ok(AwsResponse::json(
1888            StatusCode::OK,
1889            serde_json::to_string(&result).unwrap(),
1890        ))
1891    }
1892
1893    fn revoke_grant(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1894        let body = body_json(req);
1895        let key_id = Self::require_key_id(&body)?;
1896        let grant_id = body["GrantId"].as_str().unwrap_or("");
1897
1898        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1899            AwsServiceError::aws_error(
1900                StatusCode::BAD_REQUEST,
1901                "NotFoundException",
1902                format!("Key '{key_id}' does not exist"),
1903            )
1904        })?;
1905
1906        let mut state = self.state.write();
1907        let idx = state
1908            .grants
1909            .iter()
1910            .position(|g| g.key_id == resolved && g.grant_id == grant_id);
1911
1912        match idx {
1913            Some(i) => {
1914                state.grants.remove(i);
1915                Ok(AwsResponse::json(StatusCode::OK, "{}"))
1916            }
1917            None => Err(AwsServiceError::aws_error(
1918                StatusCode::BAD_REQUEST,
1919                "NotFoundException",
1920                format!("Grant ID {grant_id} not found"),
1921            )),
1922        }
1923    }
1924
1925    fn retire_grant(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1926        let body = body_json(req);
1927        let grant_token = body["GrantToken"].as_str();
1928        let grant_id = body["GrantId"].as_str();
1929        let key_id = body["KeyId"].as_str();
1930
1931        let mut state = self.state.write();
1932
1933        let idx = if let Some(token) = grant_token {
1934            state.grants.iter().position(|g| g.grant_token == token)
1935        } else if let (Some(kid), Some(gid)) = (key_id, grant_id) {
1936            let resolved = Self::resolve_key_id_with_state(&state, kid);
1937            resolved.and_then(|r| {
1938                state
1939                    .grants
1940                    .iter()
1941                    .position(|g| g.key_id == r && g.grant_id == gid)
1942            })
1943        } else {
1944            None
1945        };
1946
1947        match idx {
1948            Some(i) => {
1949                state.grants.remove(i);
1950                Ok(AwsResponse::json(StatusCode::OK, "{}"))
1951            }
1952            None => Err(AwsServiceError::aws_error(
1953                StatusCode::BAD_REQUEST,
1954                "NotFoundException",
1955                "Grant not found",
1956            )),
1957        }
1958    }
1959
1960    fn generate_mac(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
1961        let body = body_json(req);
1962        let key_id = Self::require_key_id(&body)?;
1963        let mac_algorithm = body["MacAlgorithm"].as_str().unwrap_or("").to_string();
1964        let message_b64 = body["Message"].as_str().unwrap_or("");
1965
1966        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
1967            AwsServiceError::aws_error(
1968                StatusCode::BAD_REQUEST,
1969                "NotFoundException",
1970                format!("Key '{key_id}' does not exist"),
1971            )
1972        })?;
1973
1974        let state = self.state.read();
1975        let key = state.keys.get(&resolved).unwrap();
1976
1977        // Validate key usage
1978        if key.key_usage != "GENERATE_VERIFY_MAC" {
1979            return Err(AwsServiceError::aws_error(
1980                StatusCode::BAD_REQUEST,
1981                "InvalidKeyUsageException",
1982                format!("Key '{}' is not a GENERATE_VERIFY_MAC key", key.arn),
1983            ));
1984        }
1985
1986        // Validate key spec supports MAC
1987        if key.mac_algorithms.is_none() {
1988            return Err(AwsServiceError::aws_error(
1989                StatusCode::BAD_REQUEST,
1990                "InvalidKeyUsageException",
1991                format!("Key '{}' does not support MAC operations", key.arn),
1992            ));
1993        }
1994
1995        // Generate fake MAC
1996        let mac_data = format!(
1997            "fakecloud-mac:{}:{}:{}",
1998            key.key_id, mac_algorithm, message_b64
1999        );
2000        let mac_b64 = base64::engine::general_purpose::STANDARD.encode(mac_data.as_bytes());
2001
2002        Ok(AwsResponse::json(
2003            StatusCode::OK,
2004            serde_json::to_string(&json!({
2005                "Mac": mac_b64,
2006                "KeyId": key.key_id,
2007                "MacAlgorithm": mac_algorithm,
2008            }))
2009            .unwrap(),
2010        ))
2011    }
2012
2013    fn verify_mac(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2014        let body = body_json(req);
2015        let key_id = Self::require_key_id(&body)?;
2016        let mac_algorithm = body["MacAlgorithm"].as_str().unwrap_or("").to_string();
2017        let message_b64 = body["Message"].as_str().unwrap_or("");
2018        let mac_b64 = body["Mac"].as_str().unwrap_or("");
2019
2020        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2021            AwsServiceError::aws_error(
2022                StatusCode::BAD_REQUEST,
2023                "NotFoundException",
2024                format!("Key '{key_id}' does not exist"),
2025            )
2026        })?;
2027
2028        let state = self.state.read();
2029        let key = state.keys.get(&resolved).unwrap();
2030
2031        // Validate key usage
2032        if key.key_usage != "GENERATE_VERIFY_MAC" {
2033            return Err(AwsServiceError::aws_error(
2034                StatusCode::BAD_REQUEST,
2035                "InvalidKeyUsageException",
2036                format!("Key '{}' is not a GENERATE_VERIFY_MAC key", key.arn),
2037            ));
2038        }
2039
2040        // Check if MAC matches
2041        let expected_mac_data = format!(
2042            "fakecloud-mac:{}:{}:{}",
2043            key.key_id, mac_algorithm, message_b64
2044        );
2045        let expected_mac_b64 =
2046            base64::engine::general_purpose::STANDARD.encode(expected_mac_data.as_bytes());
2047
2048        let mac_valid = mac_b64 == expected_mac_b64;
2049
2050        if !mac_valid {
2051            return Err(AwsServiceError::aws_error(
2052                StatusCode::BAD_REQUEST,
2053                "KMSInvalidMacException",
2054                "MAC verification failed",
2055            ));
2056        }
2057
2058        Ok(AwsResponse::json(
2059            StatusCode::OK,
2060            serde_json::to_string(&json!({
2061                "KeyId": key.key_id,
2062                "MacAlgorithm": mac_algorithm,
2063                "MacValid": true,
2064            }))
2065            .unwrap(),
2066        ))
2067    }
2068
2069    fn replicate_key(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2070        let body = body_json(req);
2071        let key_id = Self::require_key_id(&body)?;
2072        let replica_region = body["ReplicaRegion"].as_str().unwrap_or("").to_string();
2073
2074        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2075            AwsServiceError::aws_error(
2076                StatusCode::BAD_REQUEST,
2077                "NotFoundException",
2078                format!("Key '{key_id}' does not exist"),
2079            )
2080        })?;
2081
2082        let mut state = self.state.write();
2083
2084        // Clone all needed data from source key first to avoid borrow issues
2085        let source_key = state.keys.get(&resolved).unwrap();
2086        let source_key_id = source_key.key_id.clone();
2087        let source_arn = source_key.arn.clone();
2088        let source_creation_date = source_key.creation_date;
2089        let source_description = source_key.description.clone();
2090        let source_enabled = source_key.enabled;
2091        let source_key_usage = source_key.key_usage.clone();
2092        let source_key_spec = source_key.key_spec.clone();
2093        let source_key_manager = source_key.key_manager.clone();
2094        let source_key_state = source_key.key_state.clone();
2095        let source_origin = source_key.origin.clone();
2096        let source_tags = source_key.tags.clone();
2097        let source_policy = source_key.policy.clone();
2098        let source_signing_algorithms = source_key.signing_algorithms.clone();
2099        let source_encryption_algorithms = source_key.encryption_algorithms.clone();
2100        let source_mac_algorithms = source_key.mac_algorithms.clone();
2101        let account_id = state.account_id.clone();
2102        let source_region = state.region.clone();
2103
2104        let replica_arn = format!(
2105            "arn:aws:kms:{}:{}:key/{}",
2106            replica_region, account_id, source_key_id
2107        );
2108
2109        let metadata = json!({
2110            "KeyId": source_key_id,
2111            "Arn": replica_arn,
2112            "AWSAccountId": account_id,
2113            "CreationDate": source_creation_date,
2114            "Description": source_description,
2115            "Enabled": source_enabled,
2116            "KeyUsage": source_key_usage,
2117            "KeySpec": source_key_spec,
2118            "CustomerMasterKeySpec": source_key_spec,
2119            "KeyManager": source_key_manager,
2120            "KeyState": source_key_state,
2121            "Origin": source_origin,
2122            "MultiRegion": true,
2123            "MultiRegionConfiguration": {
2124                "MultiRegionKeyType": "REPLICA",
2125                "PrimaryKey": {
2126                    "Arn": source_arn,
2127                    "Region": source_region,
2128                },
2129                "ReplicaKeys": [],
2130            },
2131        });
2132
2133        let replica_key = KmsKey {
2134            key_id: source_key_id.clone(),
2135            arn: replica_arn,
2136            creation_date: source_creation_date,
2137            description: source_description,
2138            enabled: source_enabled,
2139            key_usage: source_key_usage,
2140            key_spec: source_key_spec,
2141            key_manager: source_key_manager,
2142            key_state: source_key_state,
2143            deletion_date: None,
2144            tags: source_tags,
2145            policy: source_policy.clone(),
2146            key_rotation_enabled: false,
2147            origin: source_origin,
2148            multi_region: true,
2149            rotations: Vec::new(),
2150            signing_algorithms: source_signing_algorithms,
2151            encryption_algorithms: source_encryption_algorithms,
2152            mac_algorithms: source_mac_algorithms,
2153            custom_key_store_id: None,
2154            imported_key_material: false,
2155            primary_region: None,
2156        };
2157
2158        let replica_storage_key = format!("{}:{}", replica_region, source_key_id);
2159        state.keys.insert(replica_storage_key, replica_key);
2160
2161        Ok(AwsResponse::json(
2162            StatusCode::OK,
2163            serde_json::to_string(&json!({
2164                "ReplicaKeyMetadata": metadata,
2165                "ReplicaPolicy": source_policy,
2166            }))
2167            .unwrap(),
2168        ))
2169    }
2170
2171    fn generate_data_key_pair(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2172        let body = body_json(req);
2173        let key_id = Self::require_key_id(&body)?;
2174        let key_pair_spec = body["KeyPairSpec"]
2175            .as_str()
2176            .unwrap_or("RSA_2048")
2177            .to_string();
2178
2179        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2180            AwsServiceError::aws_error(
2181                StatusCode::BAD_REQUEST,
2182                "NotFoundException",
2183                format!("Key '{key_id}' does not exist"),
2184            )
2185        })?;
2186
2187        let state = self.state.read();
2188        let key = state.keys.get(&resolved).unwrap();
2189        if !key.enabled {
2190            return Err(AwsServiceError::aws_error(
2191                StatusCode::BAD_REQUEST,
2192                "DisabledException",
2193                format!("Key '{}' is disabled", key.arn),
2194            ));
2195        }
2196
2197        let public_key_bytes = generate_fake_public_key(&key_pair_spec);
2198        let private_key_bytes = rand_bytes(256);
2199        let public_key_b64 = base64::engine::general_purpose::STANDARD.encode(&public_key_bytes);
2200        let private_plaintext_b64 =
2201            base64::engine::general_purpose::STANDARD.encode(&private_key_bytes);
2202
2203        // Encrypt private key
2204        let envelope = format!(
2205            "{FAKE_ENVELOPE_PREFIX}{}:{private_plaintext_b64}",
2206            key.key_id
2207        );
2208        let private_ciphertext_b64 =
2209            base64::engine::general_purpose::STANDARD.encode(envelope.as_bytes());
2210
2211        Ok(AwsResponse::json(
2212            StatusCode::OK,
2213            serde_json::to_string(&json!({
2214                "KeyId": key.arn,
2215                "KeyPairSpec": key_pair_spec,
2216                "PublicKey": public_key_b64,
2217                "PrivateKeyPlaintext": private_plaintext_b64,
2218                "PrivateKeyCiphertextBlob": private_ciphertext_b64,
2219            }))
2220            .unwrap(),
2221        ))
2222    }
2223
2224    fn generate_data_key_pair_without_plaintext(
2225        &self,
2226        req: &AwsRequest,
2227    ) -> Result<AwsResponse, AwsServiceError> {
2228        let body = body_json(req);
2229        let key_id = Self::require_key_id(&body)?;
2230        let key_pair_spec = body["KeyPairSpec"]
2231            .as_str()
2232            .unwrap_or("RSA_2048")
2233            .to_string();
2234
2235        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2236            AwsServiceError::aws_error(
2237                StatusCode::BAD_REQUEST,
2238                "NotFoundException",
2239                format!("Key '{key_id}' does not exist"),
2240            )
2241        })?;
2242
2243        let state = self.state.read();
2244        let key = state.keys.get(&resolved).unwrap();
2245        if !key.enabled {
2246            return Err(AwsServiceError::aws_error(
2247                StatusCode::BAD_REQUEST,
2248                "DisabledException",
2249                format!("Key '{}' is disabled", key.arn),
2250            ));
2251        }
2252
2253        let public_key_bytes = generate_fake_public_key(&key_pair_spec);
2254        let private_key_bytes = rand_bytes(256);
2255        let public_key_b64 = base64::engine::general_purpose::STANDARD.encode(&public_key_bytes);
2256        let private_plaintext_b64 =
2257            base64::engine::general_purpose::STANDARD.encode(&private_key_bytes);
2258
2259        let envelope = format!(
2260            "{FAKE_ENVELOPE_PREFIX}{}:{private_plaintext_b64}",
2261            key.key_id
2262        );
2263        let private_ciphertext_b64 =
2264            base64::engine::general_purpose::STANDARD.encode(envelope.as_bytes());
2265
2266        Ok(AwsResponse::json(
2267            StatusCode::OK,
2268            serde_json::to_string(&json!({
2269                "KeyId": key.arn,
2270                "KeyPairSpec": key_pair_spec,
2271                "PublicKey": public_key_b64,
2272                "PrivateKeyCiphertextBlob": private_ciphertext_b64,
2273            }))
2274            .unwrap(),
2275        ))
2276    }
2277
2278    fn derive_shared_secret(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2279        let body = body_json(req);
2280        let key_id = Self::require_key_id(&body)?;
2281        let _key_agreement_algorithm = body["KeyAgreementAlgorithm"]
2282            .as_str()
2283            .unwrap_or("ECDH")
2284            .to_string();
2285        let _public_key = body["PublicKey"].as_str().ok_or_else(|| {
2286            AwsServiceError::aws_error(
2287                StatusCode::BAD_REQUEST,
2288                "ValidationException",
2289                "PublicKey is required",
2290            )
2291        })?;
2292
2293        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2294            AwsServiceError::aws_error(
2295                StatusCode::BAD_REQUEST,
2296                "NotFoundException",
2297                format!("Key '{key_id}' does not exist"),
2298            )
2299        })?;
2300
2301        let state = self.state.read();
2302        let key = state.keys.get(&resolved).unwrap();
2303
2304        if !key.enabled {
2305            return Err(AwsServiceError::aws_error(
2306                StatusCode::BAD_REQUEST,
2307                "DisabledException",
2308                format!("Key '{}' is disabled", key.arn),
2309            ));
2310        }
2311
2312        // Key must be asymmetric (KEY_AGREEMENT usage)
2313        if key.key_usage != "KEY_AGREEMENT" {
2314            return Err(AwsServiceError::aws_error(
2315                StatusCode::BAD_REQUEST,
2316                "InvalidKeyUsageException",
2317                format!(
2318                    "Key '{}' usage is '{}', not KEY_AGREEMENT",
2319                    key.arn, key.key_usage
2320                ),
2321            ));
2322        }
2323
2324        let shared_secret_bytes = rand_bytes(32);
2325        let shared_secret_b64 =
2326            base64::engine::general_purpose::STANDARD.encode(&shared_secret_bytes);
2327
2328        Ok(AwsResponse::json(
2329            StatusCode::OK,
2330            serde_json::to_string(&json!({
2331                "KeyId": key.arn,
2332                "SharedSecret": shared_secret_b64,
2333                "KeyAgreementAlgorithm": "ECDH",
2334                "KeyOrigin": key.origin,
2335            }))
2336            .unwrap(),
2337        ))
2338    }
2339
2340    fn get_parameters_for_import(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2341        let body = body_json(req);
2342        let key_id = Self::require_key_id(&body)?;
2343
2344        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2345            AwsServiceError::aws_error(
2346                StatusCode::BAD_REQUEST,
2347                "NotFoundException",
2348                format!("Key '{key_id}' does not exist"),
2349            )
2350        })?;
2351
2352        let state = self.state.read();
2353        let key = state.keys.get(&resolved).unwrap();
2354
2355        if key.origin != "EXTERNAL" {
2356            return Err(AwsServiceError::aws_error(
2357                StatusCode::BAD_REQUEST,
2358                "UnsupportedOperationException",
2359                format!("Key '{}' origin is '{}', not EXTERNAL", key.arn, key.origin),
2360            ));
2361        }
2362
2363        let import_token_bytes = rand_bytes(64);
2364        let import_token_b64 =
2365            base64::engine::general_purpose::STANDARD.encode(&import_token_bytes);
2366        let public_key_bytes = generate_fake_public_key("RSA_2048");
2367        let public_key_b64 = base64::engine::general_purpose::STANDARD.encode(&public_key_bytes);
2368
2369        // Valid for 24 hours
2370        let parameters_valid_to = Utc::now().timestamp() as f64 + 86400.0;
2371
2372        Ok(AwsResponse::json(
2373            StatusCode::OK,
2374            serde_json::to_string(&json!({
2375                "KeyId": key.arn,
2376                "ImportToken": import_token_b64,
2377                "PublicKey": public_key_b64,
2378                "ParametersValidTo": parameters_valid_to,
2379            }))
2380            .unwrap(),
2381        ))
2382    }
2383
2384    fn import_key_material(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2385        let body = body_json(req);
2386        let key_id = Self::require_key_id(&body)?;
2387
2388        let _import_token = body["ImportToken"].as_str().ok_or_else(|| {
2389            AwsServiceError::aws_error(
2390                StatusCode::BAD_REQUEST,
2391                "ValidationException",
2392                "ImportToken is required",
2393            )
2394        })?;
2395
2396        let _encrypted_key_material = body["EncryptedKeyMaterial"].as_str().ok_or_else(|| {
2397            AwsServiceError::aws_error(
2398                StatusCode::BAD_REQUEST,
2399                "ValidationException",
2400                "EncryptedKeyMaterial is required",
2401            )
2402        })?;
2403
2404        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2405            AwsServiceError::aws_error(
2406                StatusCode::BAD_REQUEST,
2407                "NotFoundException",
2408                format!("Key '{key_id}' does not exist"),
2409            )
2410        })?;
2411
2412        let mut state = self.state.write();
2413        let key = state.keys.get_mut(&resolved).ok_or_else(|| {
2414            AwsServiceError::aws_error(
2415                StatusCode::BAD_REQUEST,
2416                "NotFoundException",
2417                format!("Key '{key_id}' does not exist"),
2418            )
2419        })?;
2420
2421        if key.origin != "EXTERNAL" {
2422            return Err(AwsServiceError::aws_error(
2423                StatusCode::BAD_REQUEST,
2424                "UnsupportedOperationException",
2425                format!("Key '{}' origin is '{}', not EXTERNAL", key.arn, key.origin),
2426            ));
2427        }
2428
2429        key.imported_key_material = true;
2430        key.enabled = true;
2431        key.key_state = "Enabled".to_string();
2432
2433        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2434    }
2435
2436    fn delete_imported_key_material(
2437        &self,
2438        req: &AwsRequest,
2439    ) -> Result<AwsResponse, AwsServiceError> {
2440        let body = body_json(req);
2441        let key_id = Self::require_key_id(&body)?;
2442
2443        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2444            AwsServiceError::aws_error(
2445                StatusCode::BAD_REQUEST,
2446                "NotFoundException",
2447                format!("Key '{key_id}' does not exist"),
2448            )
2449        })?;
2450
2451        let mut state = self.state.write();
2452        let key = state.keys.get_mut(&resolved).ok_or_else(|| {
2453            AwsServiceError::aws_error(
2454                StatusCode::BAD_REQUEST,
2455                "NotFoundException",
2456                format!("Key '{key_id}' does not exist"),
2457            )
2458        })?;
2459
2460        if key.origin != "EXTERNAL" {
2461            return Err(AwsServiceError::aws_error(
2462                StatusCode::BAD_REQUEST,
2463                "UnsupportedOperationException",
2464                format!("Key '{}' origin is '{}', not EXTERNAL", key.arn, key.origin),
2465            ));
2466        }
2467
2468        key.imported_key_material = false;
2469        key.enabled = false;
2470        key.key_state = "PendingImport".to_string();
2471
2472        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2473    }
2474
2475    fn update_primary_region(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2476        let body = body_json(req);
2477        let key_id = Self::require_key_id(&body)?;
2478        let primary_region = body["PrimaryRegion"]
2479            .as_str()
2480            .ok_or_else(|| {
2481                AwsServiceError::aws_error(
2482                    StatusCode::BAD_REQUEST,
2483                    "ValidationException",
2484                    "PrimaryRegion is required",
2485                )
2486            })?
2487            .to_string();
2488
2489        let resolved = self.resolve_key_id(&key_id).ok_or_else(|| {
2490            AwsServiceError::aws_error(
2491                StatusCode::BAD_REQUEST,
2492                "NotFoundException",
2493                format!("Key '{key_id}' does not exist"),
2494            )
2495        })?;
2496
2497        let mut state = self.state.write();
2498        let account_id = state.account_id.clone();
2499        let key = state.keys.get_mut(&resolved).ok_or_else(|| {
2500            AwsServiceError::aws_error(
2501                StatusCode::BAD_REQUEST,
2502                "NotFoundException",
2503                format!("Key '{key_id}' does not exist"),
2504            )
2505        })?;
2506
2507        if !key.multi_region {
2508            return Err(AwsServiceError::aws_error(
2509                StatusCode::BAD_REQUEST,
2510                "UnsupportedOperationException",
2511                format!("Key '{}' is not a multi-Region key", key.arn),
2512            ));
2513        }
2514        key.primary_region = Some(primary_region.clone());
2515        // Update the ARN to reflect the new region
2516        key.arn = format!(
2517            "arn:aws:kms:{}:{}:key/{}",
2518            primary_region, account_id, key.key_id
2519        );
2520
2521        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2522    }
2523
2524    fn create_custom_key_store(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2525        let body = body_json(req);
2526
2527        let name = body["CustomKeyStoreName"]
2528            .as_str()
2529            .ok_or_else(|| {
2530                AwsServiceError::aws_error(
2531                    StatusCode::BAD_REQUEST,
2532                    "ValidationException",
2533                    "CustomKeyStoreName is required",
2534                )
2535            })?
2536            .to_string();
2537
2538        validate_string_length("customKeyStoreName", &name, 1, 256)?;
2539
2540        let store_type = body["CustomKeyStoreType"]
2541            .as_str()
2542            .unwrap_or("AWS_CLOUDHSM")
2543            .to_string();
2544
2545        validate_optional_enum(
2546            "customKeyStoreType",
2547            Some(store_type.as_str()),
2548            &["AWS_CLOUDHSM", "EXTERNAL_KEY_STORE"],
2549        )?;
2550
2551        let mut state = self.state.write();
2552
2553        // Name must be unique
2554        if state
2555            .custom_key_stores
2556            .values()
2557            .any(|s| s.custom_key_store_name == name)
2558        {
2559            return Err(AwsServiceError::aws_error(
2560                StatusCode::BAD_REQUEST,
2561                "CustomKeyStoreNameInUseException",
2562                format!("Custom key store name '{name}' is already in use"),
2563            ));
2564        }
2565
2566        let store_id = format!("cks-{}", Uuid::new_v4().as_simple());
2567        let now = Utc::now().timestamp() as f64;
2568
2569        let store = CustomKeyStore {
2570            custom_key_store_id: store_id.clone(),
2571            custom_key_store_name: name,
2572            custom_key_store_type: store_type,
2573            cloud_hsm_cluster_id: body["CloudHsmClusterId"].as_str().map(|s| s.to_string()),
2574            trust_anchor_certificate: body["TrustAnchorCertificate"]
2575                .as_str()
2576                .map(|s| s.to_string()),
2577            connection_state: "DISCONNECTED".to_string(),
2578            creation_date: now,
2579            xks_proxy_uri_endpoint: body["XksProxyUriEndpoint"].as_str().map(|s| s.to_string()),
2580            xks_proxy_uri_path: body["XksProxyUriPath"].as_str().map(|s| s.to_string()),
2581            xks_proxy_vpc_endpoint_service_name: body["XksProxyVpcEndpointServiceName"]
2582                .as_str()
2583                .map(|s| s.to_string()),
2584            xks_proxy_connectivity: body["XksProxyConnectivity"].as_str().map(|s| s.to_string()),
2585        };
2586
2587        state.custom_key_stores.insert(store_id.clone(), store);
2588
2589        Ok(AwsResponse::json(
2590            StatusCode::OK,
2591            serde_json::to_string(&json!({ "CustomKeyStoreId": store_id })).unwrap(),
2592        ))
2593    }
2594
2595    fn delete_custom_key_store(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2596        let body = body_json(req);
2597
2598        let store_id = body["CustomKeyStoreId"]
2599            .as_str()
2600            .ok_or_else(|| {
2601                AwsServiceError::aws_error(
2602                    StatusCode::BAD_REQUEST,
2603                    "ValidationException",
2604                    "CustomKeyStoreId is required",
2605                )
2606            })?
2607            .to_string();
2608
2609        let mut state = self.state.write();
2610
2611        let store = state.custom_key_stores.get(&store_id).ok_or_else(|| {
2612            AwsServiceError::aws_error(
2613                StatusCode::BAD_REQUEST,
2614                "CustomKeyStoreNotFoundException",
2615                format!("Custom key store '{store_id}' does not exist"),
2616            )
2617        })?;
2618
2619        if store.connection_state == "CONNECTED" {
2620            return Err(AwsServiceError::aws_error(
2621                StatusCode::BAD_REQUEST,
2622                "CustomKeyStoreHasCMKsException",
2623                "Cannot delete a connected custom key store. Disconnect it first.",
2624            ));
2625        }
2626
2627        state.custom_key_stores.remove(&store_id);
2628
2629        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2630    }
2631
2632    fn describe_custom_key_stores(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2633        let body = body_json(req);
2634        validate_optional_string_length(
2635            "customKeyStoreName",
2636            body["CustomKeyStoreName"].as_str(),
2637            1,
2638            256,
2639        )?;
2640        validate_optional_range_i64("limit", body["Limit"].as_i64(), 1, 1000)?;
2641        validate_optional_string_length("marker", body["Marker"].as_str(), 1, 1024)?;
2642
2643        let filter_id = body["CustomKeyStoreId"].as_str();
2644        let filter_name = body["CustomKeyStoreName"].as_str();
2645        let limit = body["Limit"].as_u64().unwrap_or(1000) as usize;
2646        let marker = body["Marker"].as_str();
2647
2648        let state = self.state.read();
2649
2650        let mut stores: Vec<&CustomKeyStore> = state
2651            .custom_key_stores
2652            .values()
2653            .filter(|s| {
2654                if let Some(id) = filter_id {
2655                    return s.custom_key_store_id == id;
2656                }
2657                if let Some(name) = filter_name {
2658                    return s.custom_key_store_name == name;
2659                }
2660                true
2661            })
2662            .collect();
2663
2664        stores.sort_by(|a, b| a.custom_key_store_id.cmp(&b.custom_key_store_id));
2665
2666        // If filtering by ID and not found, return error
2667        if let Some(id) = filter_id {
2668            if stores.is_empty() {
2669                return Err(AwsServiceError::aws_error(
2670                    StatusCode::BAD_REQUEST,
2671                    "CustomKeyStoreNotFoundException",
2672                    format!("Custom key store '{id}' does not exist"),
2673                ));
2674            }
2675        }
2676
2677        let start = marker
2678            .and_then(|m| {
2679                stores
2680                    .iter()
2681                    .position(|s| s.custom_key_store_id == m)
2682                    .map(|p| p + 1)
2683            })
2684            .unwrap_or(0);
2685
2686        let page: Vec<_> = stores.iter().skip(start).take(limit).collect();
2687        let truncated = start + page.len() < stores.len();
2688
2689        let entries: Vec<Value> = page.iter().map(|s| custom_key_store_json(s)).collect();
2690
2691        let mut resp = json!({ "CustomKeyStores": entries, "Truncated": truncated });
2692        if truncated {
2693            if let Some(last) = page.last() {
2694                resp["NextMarker"] = json!(last.custom_key_store_id);
2695            }
2696        }
2697
2698        Ok(AwsResponse::json(
2699            StatusCode::OK,
2700            serde_json::to_string(&resp).unwrap(),
2701        ))
2702    }
2703
2704    fn connect_custom_key_store(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2705        let body = body_json(req);
2706
2707        let store_id = body["CustomKeyStoreId"]
2708            .as_str()
2709            .ok_or_else(|| {
2710                AwsServiceError::aws_error(
2711                    StatusCode::BAD_REQUEST,
2712                    "ValidationException",
2713                    "CustomKeyStoreId is required",
2714                )
2715            })?
2716            .to_string();
2717
2718        let mut state = self.state.write();
2719
2720        let store = state.custom_key_stores.get_mut(&store_id).ok_or_else(|| {
2721            AwsServiceError::aws_error(
2722                StatusCode::BAD_REQUEST,
2723                "CustomKeyStoreNotFoundException",
2724                format!("Custom key store '{store_id}' does not exist"),
2725            )
2726        })?;
2727
2728        store.connection_state = "CONNECTED".to_string();
2729
2730        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2731    }
2732
2733    fn disconnect_custom_key_store(
2734        &self,
2735        req: &AwsRequest,
2736    ) -> Result<AwsResponse, AwsServiceError> {
2737        let body = body_json(req);
2738
2739        let store_id = body["CustomKeyStoreId"]
2740            .as_str()
2741            .ok_or_else(|| {
2742                AwsServiceError::aws_error(
2743                    StatusCode::BAD_REQUEST,
2744                    "ValidationException",
2745                    "CustomKeyStoreId is required",
2746                )
2747            })?
2748            .to_string();
2749
2750        let mut state = self.state.write();
2751
2752        let store = state.custom_key_stores.get_mut(&store_id).ok_or_else(|| {
2753            AwsServiceError::aws_error(
2754                StatusCode::BAD_REQUEST,
2755                "CustomKeyStoreNotFoundException",
2756                format!("Custom key store '{store_id}' does not exist"),
2757            )
2758        })?;
2759
2760        store.connection_state = "DISCONNECTED".to_string();
2761
2762        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2763    }
2764
2765    fn update_custom_key_store(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2766        let body = body_json(req);
2767
2768        let store_id = body["CustomKeyStoreId"]
2769            .as_str()
2770            .ok_or_else(|| {
2771                AwsServiceError::aws_error(
2772                    StatusCode::BAD_REQUEST,
2773                    "ValidationException",
2774                    "CustomKeyStoreId is required",
2775                )
2776            })?
2777            .to_string();
2778
2779        let mut state = self.state.write();
2780
2781        // Check uniqueness of new name before borrowing store mutably
2782        if let Some(new_name) = body["NewCustomKeyStoreName"].as_str() {
2783            if state
2784                .custom_key_stores
2785                .values()
2786                .any(|s| s.custom_key_store_name == new_name && s.custom_key_store_id != store_id)
2787            {
2788                return Err(AwsServiceError::aws_error(
2789                    StatusCode::BAD_REQUEST,
2790                    "CustomKeyStoreNameInUseException",
2791                    format!("Custom key store name '{new_name}' is already in use"),
2792                ));
2793            }
2794        }
2795
2796        let store = state.custom_key_stores.get_mut(&store_id).ok_or_else(|| {
2797            AwsServiceError::aws_error(
2798                StatusCode::BAD_REQUEST,
2799                "CustomKeyStoreNotFoundException",
2800                format!("Custom key store '{store_id}' does not exist"),
2801            )
2802        })?;
2803
2804        if let Some(new_name) = body["NewCustomKeyStoreName"].as_str() {
2805            store.custom_key_store_name = new_name.to_string();
2806        }
2807        if let Some(v) = body["CloudHsmClusterId"].as_str() {
2808            store.cloud_hsm_cluster_id = Some(v.to_string());
2809        }
2810        if let Some(v) = body["KeyStorePassword"].as_str() {
2811            // In a real implementation this would update the password;
2812            // we just accept it silently.
2813            let _ = v;
2814        }
2815        if let Some(v) = body["XksProxyUriEndpoint"].as_str() {
2816            store.xks_proxy_uri_endpoint = Some(v.to_string());
2817        }
2818        if let Some(v) = body["XksProxyUriPath"].as_str() {
2819            store.xks_proxy_uri_path = Some(v.to_string());
2820        }
2821        if let Some(v) = body["XksProxyVpcEndpointServiceName"].as_str() {
2822            store.xks_proxy_vpc_endpoint_service_name = Some(v.to_string());
2823        }
2824        if let Some(v) = body["XksProxyConnectivity"].as_str() {
2825            store.xks_proxy_connectivity = Some(v.to_string());
2826        }
2827
2828        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2829    }
2830}
2831
2832fn custom_key_store_json(store: &CustomKeyStore) -> Value {
2833    let mut obj = json!({
2834        "CustomKeyStoreId": store.custom_key_store_id,
2835        "CustomKeyStoreName": store.custom_key_store_name,
2836        "CustomKeyStoreType": store.custom_key_store_type,
2837        "ConnectionState": store.connection_state,
2838        "CreationDate": store.creation_date,
2839    });
2840    if let Some(ref v) = store.cloud_hsm_cluster_id {
2841        obj["CloudHsmClusterId"] = json!(v);
2842    }
2843    if let Some(ref v) = store.trust_anchor_certificate {
2844        obj["TrustAnchorCertificate"] = json!(v);
2845    }
2846    if let Some(ref v) = store.xks_proxy_uri_endpoint {
2847        obj["XksProxyConfiguration"] = json!({});
2848        obj["XksProxyConfiguration"]["UriEndpoint"] = json!(v);
2849        if let Some(ref p) = store.xks_proxy_uri_path {
2850            obj["XksProxyConfiguration"]["UriPath"] = json!(p);
2851        }
2852        if let Some(ref c) = store.xks_proxy_connectivity {
2853            obj["XksProxyConfiguration"]["Connectivity"] = json!(c);
2854        }
2855        if let Some(ref s) = store.xks_proxy_vpc_endpoint_service_name {
2856            obj["XksProxyConfiguration"]["VpcEndpointServiceName"] = json!(s);
2857        }
2858    }
2859    obj
2860}
2861
2862fn key_metadata_json(key: &KmsKey, account_id: &str) -> Value {
2863    let mut meta = json!({
2864        "KeyId": key.key_id,
2865        "Arn": key.arn,
2866        "AWSAccountId": account_id,
2867        "CreationDate": key.creation_date,
2868        "Description": key.description,
2869        "Enabled": key.enabled,
2870        "KeyUsage": key.key_usage,
2871        "KeySpec": key.key_spec,
2872        "CustomerMasterKeySpec": key.key_spec,
2873        "KeyManager": key.key_manager,
2874        "KeyState": key.key_state,
2875        "Origin": key.origin,
2876        "MultiRegion": key.multi_region,
2877    });
2878
2879    if let Some(ref enc_algs) = key.encryption_algorithms {
2880        meta["EncryptionAlgorithms"] = json!(enc_algs);
2881    }
2882    if let Some(ref sig_algs) = key.signing_algorithms {
2883        meta["SigningAlgorithms"] = json!(sig_algs);
2884    }
2885    if let Some(ref mac_algs) = key.mac_algorithms {
2886        meta["MacAlgorithms"] = json!(mac_algs);
2887    }
2888    if let Some(dd) = key.deletion_date {
2889        meta["DeletionDate"] = json!(dd);
2890    }
2891    if let Some(ref cks_id) = key.custom_key_store_id {
2892        meta["CustomKeyStoreId"] = json!(cks_id);
2893    }
2894
2895    if key.multi_region {
2896        // Add MultiRegionConfiguration for primary keys
2897        meta["MultiRegionConfiguration"] = json!({
2898            "MultiRegionKeyType": "PRIMARY",
2899            "PrimaryKey": {
2900                "Arn": key.arn,
2901                "Region": key.arn.split(':').nth(3).unwrap_or("us-east-1"),
2902            },
2903            "ReplicaKeys": [],
2904        });
2905    }
2906
2907    meta
2908}
2909
2910fn fmt_enum_set(items: &[String]) -> String {
2911    let inner: Vec<String> = items.iter().map(|s| format!("'{s}'")).collect();
2912    format!("[{}]", inner.join(", "))
2913}
2914
2915fn grant_to_json(grant: &KmsGrant) -> Value {
2916    let mut v = json!({
2917        "KeyId": grant.key_id,
2918        "GrantId": grant.grant_id,
2919        "GranteePrincipal": grant.grantee_principal,
2920        "Operations": grant.operations,
2921        "IssuingAccount": format!("arn:aws:iam::root"),
2922        "CreationDate": grant.creation_date,
2923    });
2924
2925    if let Some(ref rp) = grant.retiring_principal {
2926        v["RetiringPrincipal"] = json!(rp);
2927    }
2928    if let Some(ref c) = grant.constraints {
2929        v["Constraints"] = c.clone();
2930    }
2931    if let Some(ref n) = grant.name {
2932        v["Name"] = json!(n);
2933    }
2934
2935    v
2936}
2937
2938fn data_key_size_from_body(body: &Value) -> Result<usize, AwsServiceError> {
2939    let key_spec = body["KeySpec"].as_str();
2940    let number_of_bytes = body["NumberOfBytes"].as_u64();
2941
2942    match (key_spec, number_of_bytes) {
2943        (Some(_), Some(_)) => Err(AwsServiceError::aws_error(
2944            StatusCode::BAD_REQUEST,
2945            "ValidationException",
2946            "KeySpec and NumberOfBytes are mutually exclusive",
2947        )),
2948        (Some("AES_256"), None) => Ok(32),
2949        (Some("AES_128"), None) => Ok(16),
2950        (Some(spec), None) => Err(AwsServiceError::aws_error(
2951            StatusCode::BAD_REQUEST,
2952            "ValidationException",
2953            format!("1 validation error detected: Value '{spec}' at 'keySpec' failed to satisfy constraint: Member must satisfy enum value set: [AES_256, AES_128]"),
2954        )),
2955        (None, Some(n)) => {
2956            if n > 1024 {
2957                Err(AwsServiceError::aws_error(
2958                    StatusCode::BAD_REQUEST,
2959                    "ValidationException",
2960                    format!("1 validation error detected: Value '{n}' at 'numberOfBytes' failed to satisfy constraint: Member must have value less than or equal to 1024"),
2961                ))
2962            } else {
2963                Ok(n as usize)
2964            }
2965        }
2966        (None, None) => Err(AwsServiceError::aws_error(
2967            StatusCode::BAD_REQUEST,
2968            "ValidationException",
2969            "KeySpec or NumberOfBytes is required",
2970        )),
2971    }
2972}
2973
2974fn generate_fake_public_key(key_spec: &str) -> Vec<u8> {
2975    // Return a minimal but valid-looking DER-encoded SubjectPublicKeyInfo
2976    // This is a fake RSA 2048-bit public key structure for testing
2977    match key_spec {
2978        "RSA_2048" | "RSA_3072" | "RSA_4096" => {
2979            // A minimal ASN.1 DER structure for RSA public key
2980            let mut key = vec![
2981                0x30, 0x82, 0x01, 0x22, // SEQUENCE, length 290
2982                0x30, 0x0d, // SEQUENCE, length 13
2983                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
2984                0x01, // OID rsaEncryption
2985                0x05, 0x00, // NULL
2986                0x03, 0x82, 0x01, 0x0f, // BIT STRING, length 271
2987                0x00, // unused bits
2988                0x30, 0x82, 0x01, 0x0a, // SEQUENCE, length 266
2989                0x02, 0x82, 0x01, 0x01, // INTEGER, length 257
2990            ];
2991            // Fake modulus (257 bytes: 0x00 + 256 bytes of random-looking data)
2992            key.push(0x00);
2993            key.extend_from_slice(&rand_bytes(256));
2994            // Exponent
2995            key.extend_from_slice(&[0x02, 0x03, 0x01, 0x00, 0x01]); // 65537
2996            key
2997        }
2998        "ECC_NIST_P256" | "ECC_SECG_P256K1" => {
2999            // Minimal EC public key for P-256
3000            let mut key = vec![
3001                0x30, 0x59, // SEQUENCE, length 89
3002                0x30, 0x13, // SEQUENCE, length 19
3003                0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // OID ecPublicKey
3004                0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, // OID prime256v1
3005                0x03, 0x42, // BIT STRING, length 66
3006                0x00, // unused bits
3007                0x04, // uncompressed point
3008            ];
3009            key.extend_from_slice(&rand_bytes(64)); // x and y coordinates
3010            key
3011        }
3012        "ECC_NIST_P384" => {
3013            let mut key = vec![
3014                0x30, 0x76, // SEQUENCE, length 118
3015                0x30, 0x10, // SEQUENCE, length 16
3016                0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // OID ecPublicKey
3017                0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, // OID secp384r1
3018                0x03, 0x62, // BIT STRING, length 98
3019                0x00, // unused bits
3020                0x04, // uncompressed point
3021            ];
3022            key.extend_from_slice(&rand_bytes(96)); // x and y coordinates
3023            key
3024        }
3025        "ECC_NIST_P521" => {
3026            let mut key = vec![
3027                0x30, 0x81, 0x9b, // SEQUENCE, length 155
3028                0x30, 0x10, // SEQUENCE, length 16
3029                0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // OID ecPublicKey
3030                0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, // OID secp521r1
3031                0x03, 0x81, 0x86, // BIT STRING, length 134
3032                0x00, // unused bits
3033                0x04, // uncompressed point
3034            ];
3035            key.extend_from_slice(&rand_bytes(132)); // x and y coordinates
3036            key
3037        }
3038        _ => rand_bytes(32),
3039    }
3040}
3041
3042fn check_policy_deny(key: &KmsKey, action: &str) -> Result<(), AwsServiceError> {
3043    // Parse the policy and check for Deny statements
3044    let policy: Value = match serde_json::from_str(&key.policy) {
3045        Ok(v) => v,
3046        Err(_) => return Ok(()), // If policy can't be parsed, allow
3047    };
3048
3049    let statements = match policy["Statement"].as_array() {
3050        Some(s) => s,
3051        None => return Ok(()),
3052    };
3053
3054    for stmt in statements {
3055        let effect = stmt["Effect"].as_str().unwrap_or("");
3056        if !effect.eq_ignore_ascii_case("deny") {
3057            continue;
3058        }
3059
3060        // Check Resource - only deny if resource is "*"
3061        let resource = &stmt["Resource"];
3062        let resource_matches = if let Some(r) = resource.as_str() {
3063            r == "*"
3064        } else if let Some(arr) = resource.as_array() {
3065            arr.iter().any(|r| r.as_str() == Some("*"))
3066        } else {
3067            false
3068        };
3069
3070        if !resource_matches {
3071            continue;
3072        }
3073
3074        // Check Action
3075        let actions = if let Some(a) = stmt["Action"].as_str() {
3076            vec![a.to_string()]
3077        } else if let Some(arr) = stmt["Action"].as_array() {
3078            arr.iter()
3079                .filter_map(|a| a.as_str().map(|s| s.to_string()))
3080                .collect()
3081        } else {
3082            continue;
3083        };
3084
3085        for policy_action in &actions {
3086            if action_matches(policy_action, action) {
3087                return Err(AwsServiceError::aws_error(
3088                    StatusCode::BAD_REQUEST,
3089                    "AccessDeniedException",
3090                    format!(
3091                        "User is not authorized to perform: {} on resource: {}",
3092                        action, key.arn
3093                    ),
3094                ));
3095            }
3096        }
3097    }
3098
3099    Ok(())
3100}
3101
3102fn action_matches(policy_action: &str, requested_action: &str) -> bool {
3103    if policy_action == "kms:*" {
3104        return true;
3105    }
3106    if policy_action == requested_action {
3107        return true;
3108    }
3109    // Wildcard matching: "kms:Describe*" matches "kms:DescribeKey"
3110    if let Some(prefix) = policy_action.strip_suffix('*') {
3111        if requested_action.starts_with(prefix) {
3112            return true;
3113        }
3114    }
3115    false
3116}
3117
3118#[cfg(test)]
3119mod tests {
3120    use super::*;
3121    use parking_lot::RwLock;
3122    use serde_json::json;
3123    use std::collections::HashMap;
3124    use std::sync::Arc;
3125
3126    fn make_service() -> KmsService {
3127        let state: SharedKmsState = Arc::new(RwLock::new(crate::state::KmsState::new(
3128            "123456789012",
3129            "us-east-1",
3130        )));
3131        KmsService::new(state)
3132    }
3133
3134    fn make_request(action: &str, body: Value) -> AwsRequest {
3135        AwsRequest {
3136            service: "kms".to_string(),
3137            action: action.to_string(),
3138            region: "us-east-1".to_string(),
3139            account_id: "123456789012".to_string(),
3140            request_id: "test-id".to_string(),
3141            headers: http::HeaderMap::new(),
3142            query_params: HashMap::new(),
3143            body: serde_json::to_vec(&body).unwrap().into(),
3144            path_segments: vec![],
3145            raw_path: "/".to_string(),
3146            method: http::Method::POST,
3147            is_query_protocol: false,
3148            access_key_id: None,
3149        }
3150    }
3151
3152    fn create_key(svc: &KmsService) -> String {
3153        let req = make_request("CreateKey", json!({}));
3154        let resp = svc.create_key(&req).unwrap();
3155        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3156        body["KeyMetadata"]["KeyId"].as_str().unwrap().to_string()
3157    }
3158
3159    #[test]
3160    fn list_keys_pagination_no_duplicates() {
3161        let svc = make_service();
3162        let mut all_key_ids: Vec<String> = Vec::new();
3163        for _ in 0..5 {
3164            all_key_ids.push(create_key(&svc));
3165        }
3166
3167        let mut collected_ids: Vec<String> = Vec::new();
3168        let mut marker: Option<String> = None;
3169
3170        loop {
3171            let mut body = json!({ "Limit": 2 });
3172            if let Some(ref m) = marker {
3173                body["Marker"] = json!(m);
3174            }
3175            let req = make_request("ListKeys", body);
3176            let resp = svc.list_keys(&req).unwrap();
3177            let resp_body: Value = serde_json::from_slice(&resp.body).unwrap();
3178
3179            for key in resp_body["Keys"].as_array().unwrap() {
3180                collected_ids.push(key["KeyId"].as_str().unwrap().to_string());
3181            }
3182
3183            if resp_body["Truncated"].as_bool().unwrap_or(false) {
3184                marker = resp_body["NextMarker"].as_str().map(|s| s.to_string());
3185            } else {
3186                break;
3187            }
3188        }
3189
3190        // Verify no duplicates
3191        let mut deduped = collected_ids.clone();
3192        deduped.sort();
3193        deduped.dedup();
3194        assert_eq!(
3195            collected_ids.len(),
3196            deduped.len(),
3197            "pagination produced duplicate keys"
3198        );
3199
3200        // Verify all keys returned
3201        for kid in &all_key_ids {
3202            assert!(
3203                collected_ids.contains(kid),
3204                "key {kid} missing from paginated results"
3205            );
3206        }
3207    }
3208
3209    #[test]
3210    fn list_retirable_grants_pagination() {
3211        let svc = make_service();
3212        let key_id = create_key(&svc);
3213        let retiring = "arn:aws:iam::123456789012:user/retiring-user";
3214
3215        // Create 5 grants with the same retiring principal
3216        for i in 0..5 {
3217            let req = make_request(
3218                "CreateGrant",
3219                json!({
3220                    "KeyId": key_id,
3221                    "GranteePrincipal": format!("arn:aws:iam::123456789012:user/grantee-{i}"),
3222                    "RetiringPrincipal": retiring,
3223                    "Operations": ["Encrypt"]
3224                }),
3225            );
3226            svc.create_grant(&req).unwrap();
3227        }
3228
3229        let mut collected_ids: Vec<String> = Vec::new();
3230        let mut marker: Option<String> = None;
3231
3232        loop {
3233            let mut body = json!({
3234                "RetiringPrincipal": retiring,
3235                "Limit": 2
3236            });
3237            if let Some(ref m) = marker {
3238                body["Marker"] = json!(m);
3239            }
3240            let req = make_request("ListRetirableGrants", body);
3241            let resp = svc.list_retirable_grants(&req).unwrap();
3242            let resp_body: Value = serde_json::from_slice(&resp.body).unwrap();
3243
3244            for grant in resp_body["Grants"].as_array().unwrap() {
3245                collected_ids.push(grant["GrantId"].as_str().unwrap().to_string());
3246            }
3247
3248            if resp_body["Truncated"].as_bool().unwrap_or(false) {
3249                marker = resp_body["NextMarker"].as_str().map(|s| s.to_string());
3250            } else {
3251                break;
3252            }
3253        }
3254
3255        // Verify no duplicates
3256        let mut deduped = collected_ids.clone();
3257        deduped.sort();
3258        deduped.dedup();
3259        assert_eq!(
3260            collected_ids.len(),
3261            deduped.len(),
3262            "pagination produced duplicate grants"
3263        );
3264
3265        // All 5 grants returned
3266        assert_eq!(collected_ids.len(), 5, "expected 5 grants total");
3267    }
3268
3269    fn create_key_with_opts(svc: &KmsService, body: Value) -> String {
3270        let req = make_request("CreateKey", body);
3271        let resp = svc.create_key(&req).unwrap();
3272        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3273        body["KeyMetadata"]["KeyId"].as_str().unwrap().to_string()
3274    }
3275
3276    #[test]
3277    fn generate_data_key_pair_returns_all_fields() {
3278        let svc = make_service();
3279        let key_id = create_key(&svc);
3280
3281        let req = make_request(
3282            "GenerateDataKeyPair",
3283            json!({ "KeyId": key_id, "KeyPairSpec": "RSA_2048" }),
3284        );
3285        let resp = svc.generate_data_key_pair(&req).unwrap();
3286        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3287
3288        assert!(body["PublicKey"].as_str().is_some());
3289        assert!(body["PrivateKeyPlaintext"].as_str().is_some());
3290        assert!(body["PrivateKeyCiphertextBlob"].as_str().is_some());
3291        assert_eq!(body["KeyPairSpec"].as_str().unwrap(), "RSA_2048");
3292        assert!(body["KeyId"].as_str().unwrap().contains(":key/"));
3293    }
3294
3295    #[test]
3296    fn generate_data_key_pair_disabled_key_fails() {
3297        let svc = make_service();
3298        let key_id = create_key(&svc);
3299
3300        let disable_req = make_request("DisableKey", json!({ "KeyId": key_id }));
3301        svc.disable_key(&disable_req).unwrap();
3302
3303        let req = make_request(
3304            "GenerateDataKeyPair",
3305            json!({ "KeyId": key_id, "KeyPairSpec": "RSA_2048" }),
3306        );
3307        assert!(svc.generate_data_key_pair(&req).is_err());
3308    }
3309
3310    #[test]
3311    fn generate_data_key_pair_without_plaintext_omits_private_plaintext() {
3312        let svc = make_service();
3313        let key_id = create_key(&svc);
3314
3315        let req = make_request(
3316            "GenerateDataKeyPairWithoutPlaintext",
3317            json!({ "KeyId": key_id, "KeyPairSpec": "ECC_NIST_P256" }),
3318        );
3319        let resp = svc.generate_data_key_pair_without_plaintext(&req).unwrap();
3320        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3321
3322        assert!(body["PublicKey"].as_str().is_some());
3323        assert!(body["PrivateKeyCiphertextBlob"].as_str().is_some());
3324        assert!(body.get("PrivateKeyPlaintext").is_none());
3325        assert_eq!(body["KeyPairSpec"].as_str().unwrap(), "ECC_NIST_P256");
3326    }
3327
3328    #[test]
3329    fn derive_shared_secret_success() {
3330        let svc = make_service();
3331        let key_id = create_key_with_opts(
3332            &svc,
3333            json!({
3334                "KeyUsage": "KEY_AGREEMENT",
3335                "KeySpec": "ECC_NIST_P256"
3336            }),
3337        );
3338
3339        let fake_pub = base64::engine::general_purpose::STANDARD.encode(b"fake-public-key");
3340        let req = make_request(
3341            "DeriveSharedSecret",
3342            json!({
3343                "KeyId": key_id,
3344                "KeyAgreementAlgorithm": "ECDH",
3345                "PublicKey": fake_pub
3346            }),
3347        );
3348        let resp = svc.derive_shared_secret(&req).unwrap();
3349        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3350
3351        assert!(body["SharedSecret"].as_str().is_some());
3352        assert!(body["KeyId"].as_str().unwrap().contains(":key/"));
3353        assert_eq!(body["KeyAgreementAlgorithm"].as_str().unwrap(), "ECDH");
3354    }
3355
3356    #[test]
3357    fn derive_shared_secret_wrong_usage_fails() {
3358        let svc = make_service();
3359        let key_id = create_key(&svc); // Default is ENCRYPT_DECRYPT
3360
3361        let fake_pub = base64::engine::general_purpose::STANDARD.encode(b"fake-public-key");
3362        let req = make_request(
3363            "DeriveSharedSecret",
3364            json!({
3365                "KeyId": key_id,
3366                "KeyAgreementAlgorithm": "ECDH",
3367                "PublicKey": fake_pub
3368            }),
3369        );
3370        assert!(svc.derive_shared_secret(&req).is_err());
3371    }
3372
3373    #[test]
3374    fn get_parameters_for_import_success() {
3375        let svc = make_service();
3376        let key_id = create_key_with_opts(&svc, json!({ "Origin": "EXTERNAL" }));
3377
3378        let req = make_request(
3379            "GetParametersForImport",
3380            json!({ "KeyId": key_id, "WrappingAlgorithm": "RSAES_OAEP_SHA_256", "WrappingKeySpec": "RSA_2048" }),
3381        );
3382        let resp = svc.get_parameters_for_import(&req).unwrap();
3383        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3384
3385        assert!(body["ImportToken"].as_str().is_some());
3386        assert!(body["PublicKey"].as_str().is_some());
3387        assert!(body["ParametersValidTo"].as_f64().is_some());
3388        assert!(body["KeyId"].as_str().unwrap().contains(":key/"));
3389    }
3390
3391    #[test]
3392    fn get_parameters_for_import_non_external_fails() {
3393        let svc = make_service();
3394        let key_id = create_key(&svc); // Default origin is AWS_KMS
3395
3396        let req = make_request("GetParametersForImport", json!({ "KeyId": key_id }));
3397        assert!(svc.get_parameters_for_import(&req).is_err());
3398    }
3399
3400    #[test]
3401    fn import_key_material_lifecycle() {
3402        let svc = make_service();
3403        let key_id = create_key_with_opts(&svc, json!({ "Origin": "EXTERNAL" }));
3404
3405        let fake_token = base64::engine::general_purpose::STANDARD.encode(b"token");
3406        let fake_material = base64::engine::general_purpose::STANDARD.encode(b"material");
3407
3408        // Import
3409        let req = make_request(
3410            "ImportKeyMaterial",
3411            json!({
3412                "KeyId": key_id,
3413                "ImportToken": fake_token,
3414                "EncryptedKeyMaterial": fake_material,
3415                "ExpirationModel": "KEY_MATERIAL_DOES_NOT_EXPIRE"
3416            }),
3417        );
3418        svc.import_key_material(&req).unwrap();
3419
3420        // Key should be enabled
3421        {
3422            let state = svc.state.read();
3423            let key = state.keys.get(&key_id).unwrap();
3424            assert!(key.imported_key_material);
3425            assert!(key.enabled);
3426        }
3427
3428        // Delete imported material
3429        let req = make_request("DeleteImportedKeyMaterial", json!({ "KeyId": key_id }));
3430        svc.delete_imported_key_material(&req).unwrap();
3431
3432        // Key should be disabled and pending import
3433        {
3434            let state = svc.state.read();
3435            let key = state.keys.get(&key_id).unwrap();
3436            assert!(!key.imported_key_material);
3437            assert!(!key.enabled);
3438            assert_eq!(key.key_state, "PendingImport");
3439        }
3440    }
3441
3442    #[test]
3443    fn import_key_material_non_external_fails() {
3444        let svc = make_service();
3445        let key_id = create_key(&svc);
3446
3447        let fake_token = base64::engine::general_purpose::STANDARD.encode(b"token");
3448        let fake_material = base64::engine::general_purpose::STANDARD.encode(b"material");
3449
3450        let req = make_request(
3451            "ImportKeyMaterial",
3452            json!({
3453                "KeyId": key_id,
3454                "ImportToken": fake_token,
3455                "EncryptedKeyMaterial": fake_material
3456            }),
3457        );
3458        assert!(svc.import_key_material(&req).is_err());
3459    }
3460
3461    #[test]
3462    fn delete_imported_key_material_non_external_fails() {
3463        let svc = make_service();
3464        let key_id = create_key(&svc);
3465
3466        let req = make_request("DeleteImportedKeyMaterial", json!({ "KeyId": key_id }));
3467        assert!(svc.delete_imported_key_material(&req).is_err());
3468    }
3469
3470    #[test]
3471    fn update_primary_region_success() {
3472        let svc = make_service();
3473        let key_id = create_key_with_opts(&svc, json!({ "MultiRegion": true }));
3474
3475        let req = make_request(
3476            "UpdatePrimaryRegion",
3477            json!({ "KeyId": key_id, "PrimaryRegion": "eu-west-1" }),
3478        );
3479        svc.update_primary_region(&req).unwrap();
3480
3481        let state = svc.state.read();
3482        let key = state.keys.get(&key_id).unwrap();
3483        assert_eq!(key.primary_region.as_deref(), Some("eu-west-1"));
3484        assert!(key.arn.contains("eu-west-1"));
3485    }
3486
3487    #[test]
3488    fn update_primary_region_non_multi_region_fails() {
3489        let svc = make_service();
3490        let key_id = create_key(&svc); // Not multi-region
3491
3492        let req = make_request(
3493            "UpdatePrimaryRegion",
3494            json!({ "KeyId": key_id, "PrimaryRegion": "eu-west-1" }),
3495        );
3496        assert!(svc.update_primary_region(&req).is_err());
3497    }
3498
3499    #[test]
3500    fn custom_key_store_lifecycle() {
3501        let svc = make_service();
3502
3503        // Create
3504        let req = make_request(
3505            "CreateCustomKeyStore",
3506            json!({
3507                "CustomKeyStoreName": "my-store",
3508                "CloudHsmClusterId": "cluster-1234",
3509                "TrustAnchorCertificate": "cert-data",
3510                "KeyStorePassword": "password123"
3511            }),
3512        );
3513        let resp = svc.create_custom_key_store(&req).unwrap();
3514        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3515        let store_id = body["CustomKeyStoreId"].as_str().unwrap().to_string();
3516        assert!(store_id.starts_with("cks-"));
3517
3518        // Describe
3519        let req = make_request(
3520            "DescribeCustomKeyStores",
3521            json!({ "CustomKeyStoreId": store_id }),
3522        );
3523        let resp = svc.describe_custom_key_stores(&req).unwrap();
3524        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3525        let stores = body["CustomKeyStores"].as_array().unwrap();
3526        assert_eq!(stores.len(), 1);
3527        assert_eq!(
3528            stores[0]["CustomKeyStoreName"].as_str().unwrap(),
3529            "my-store"
3530        );
3531        assert_eq!(
3532            stores[0]["ConnectionState"].as_str().unwrap(),
3533            "DISCONNECTED"
3534        );
3535        assert_eq!(
3536            stores[0]["CloudHsmClusterId"].as_str().unwrap(),
3537            "cluster-1234"
3538        );
3539
3540        // Connect
3541        let req = make_request(
3542            "ConnectCustomKeyStore",
3543            json!({ "CustomKeyStoreId": store_id }),
3544        );
3545        svc.connect_custom_key_store(&req).unwrap();
3546
3547        // Verify connected
3548        let req = make_request(
3549            "DescribeCustomKeyStores",
3550            json!({ "CustomKeyStoreId": store_id }),
3551        );
3552        let resp = svc.describe_custom_key_stores(&req).unwrap();
3553        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3554        assert_eq!(
3555            body["CustomKeyStores"][0]["ConnectionState"]
3556                .as_str()
3557                .unwrap(),
3558            "CONNECTED"
3559        );
3560
3561        // Cannot delete when connected
3562        let req = make_request(
3563            "DeleteCustomKeyStore",
3564            json!({ "CustomKeyStoreId": store_id }),
3565        );
3566        assert!(svc.delete_custom_key_store(&req).is_err());
3567
3568        // Disconnect
3569        let req = make_request(
3570            "DisconnectCustomKeyStore",
3571            json!({ "CustomKeyStoreId": store_id }),
3572        );
3573        svc.disconnect_custom_key_store(&req).unwrap();
3574
3575        // Update name
3576        let req = make_request(
3577            "UpdateCustomKeyStore",
3578            json!({
3579                "CustomKeyStoreId": store_id,
3580                "NewCustomKeyStoreName": "renamed-store"
3581            }),
3582        );
3583        svc.update_custom_key_store(&req).unwrap();
3584
3585        // Verify update
3586        let req = make_request(
3587            "DescribeCustomKeyStores",
3588            json!({ "CustomKeyStoreId": store_id }),
3589        );
3590        let resp = svc.describe_custom_key_stores(&req).unwrap();
3591        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3592        assert_eq!(
3593            body["CustomKeyStores"][0]["CustomKeyStoreName"]
3594                .as_str()
3595                .unwrap(),
3596            "renamed-store"
3597        );
3598
3599        // Delete
3600        let req = make_request(
3601            "DeleteCustomKeyStore",
3602            json!({ "CustomKeyStoreId": store_id }),
3603        );
3604        svc.delete_custom_key_store(&req).unwrap();
3605
3606        // Describe all should return empty
3607        let req = make_request("DescribeCustomKeyStores", json!({}));
3608        let resp = svc.describe_custom_key_stores(&req).unwrap();
3609        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3610        assert!(body["CustomKeyStores"].as_array().unwrap().is_empty());
3611    }
3612
3613    #[test]
3614    fn custom_key_store_duplicate_name_fails() {
3615        let svc = make_service();
3616
3617        let req = make_request(
3618            "CreateCustomKeyStore",
3619            json!({ "CustomKeyStoreName": "dup-store" }),
3620        );
3621        svc.create_custom_key_store(&req).unwrap();
3622
3623        let req = make_request(
3624            "CreateCustomKeyStore",
3625            json!({ "CustomKeyStoreName": "dup-store" }),
3626        );
3627        assert!(svc.create_custom_key_store(&req).is_err());
3628    }
3629
3630    #[test]
3631    fn describe_custom_key_store_not_found() {
3632        let svc = make_service();
3633
3634        let req = make_request(
3635            "DescribeCustomKeyStores",
3636            json!({ "CustomKeyStoreId": "cks-nonexistent" }),
3637        );
3638        assert!(svc.describe_custom_key_stores(&req).is_err());
3639    }
3640
3641    #[test]
3642    fn delete_nonexistent_custom_key_store_fails() {
3643        let svc = make_service();
3644
3645        let req = make_request(
3646            "DeleteCustomKeyStore",
3647            json!({ "CustomKeyStoreId": "cks-nonexistent" }),
3648        );
3649        assert!(svc.delete_custom_key_store(&req).is_err());
3650    }
3651
3652    #[test]
3653    fn connect_nonexistent_custom_key_store_fails() {
3654        let svc = make_service();
3655
3656        let req = make_request(
3657            "ConnectCustomKeyStore",
3658            json!({ "CustomKeyStoreId": "cks-nonexistent" }),
3659        );
3660        assert!(svc.connect_custom_key_store(&req).is_err());
3661    }
3662
3663    #[test]
3664    fn describe_custom_key_stores_by_name() {
3665        let svc = make_service();
3666
3667        let req = make_request(
3668            "CreateCustomKeyStore",
3669            json!({ "CustomKeyStoreName": "store-a" }),
3670        );
3671        svc.create_custom_key_store(&req).unwrap();
3672
3673        let req = make_request(
3674            "CreateCustomKeyStore",
3675            json!({ "CustomKeyStoreName": "store-b" }),
3676        );
3677        svc.create_custom_key_store(&req).unwrap();
3678
3679        // Filter by name
3680        let req = make_request(
3681            "DescribeCustomKeyStores",
3682            json!({ "CustomKeyStoreName": "store-a" }),
3683        );
3684        let resp = svc.describe_custom_key_stores(&req).unwrap();
3685        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3686        let stores = body["CustomKeyStores"].as_array().unwrap();
3687        assert_eq!(stores.len(), 1);
3688        assert_eq!(stores[0]["CustomKeyStoreName"].as_str().unwrap(), "store-a");
3689    }
3690
3691    #[test]
3692    fn update_custom_key_store_name_conflict() {
3693        let svc = make_service();
3694
3695        let req = make_request(
3696            "CreateCustomKeyStore",
3697            json!({ "CustomKeyStoreName": "store-x" }),
3698        );
3699        svc.create_custom_key_store(&req).unwrap();
3700
3701        let req = make_request(
3702            "CreateCustomKeyStore",
3703            json!({ "CustomKeyStoreName": "store-y" }),
3704        );
3705        let resp = svc.create_custom_key_store(&req).unwrap();
3706        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3707        let store_y_id = body["CustomKeyStoreId"].as_str().unwrap().to_string();
3708
3709        // Try to rename store-y to store-x
3710        let req = make_request(
3711            "UpdateCustomKeyStore",
3712            json!({
3713                "CustomKeyStoreId": store_y_id,
3714                "NewCustomKeyStoreName": "store-x"
3715            }),
3716        );
3717        assert!(svc.update_custom_key_store(&req).is_err());
3718    }
3719}