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
2635        let filter_id = body["CustomKeyStoreId"].as_str();
2636        let filter_name = body["CustomKeyStoreName"].as_str();
2637        let limit = body["Limit"].as_u64().unwrap_or(1000) as usize;
2638        let marker = body["Marker"].as_str();
2639
2640        let state = self.state.read();
2641
2642        let mut stores: Vec<&CustomKeyStore> = state
2643            .custom_key_stores
2644            .values()
2645            .filter(|s| {
2646                if let Some(id) = filter_id {
2647                    return s.custom_key_store_id == id;
2648                }
2649                if let Some(name) = filter_name {
2650                    return s.custom_key_store_name == name;
2651                }
2652                true
2653            })
2654            .collect();
2655
2656        stores.sort_by(|a, b| a.custom_key_store_id.cmp(&b.custom_key_store_id));
2657
2658        // If filtering by ID and not found, return error
2659        if let Some(id) = filter_id {
2660            if stores.is_empty() {
2661                return Err(AwsServiceError::aws_error(
2662                    StatusCode::BAD_REQUEST,
2663                    "CustomKeyStoreNotFoundException",
2664                    format!("Custom key store '{id}' does not exist"),
2665                ));
2666            }
2667        }
2668
2669        let start = marker
2670            .and_then(|m| {
2671                stores
2672                    .iter()
2673                    .position(|s| s.custom_key_store_id == m)
2674                    .map(|p| p + 1)
2675            })
2676            .unwrap_or(0);
2677
2678        let page: Vec<_> = stores.iter().skip(start).take(limit).collect();
2679        let truncated = start + page.len() < stores.len();
2680
2681        let entries: Vec<Value> = page.iter().map(|s| custom_key_store_json(s)).collect();
2682
2683        let mut resp = json!({ "CustomKeyStores": entries, "Truncated": truncated });
2684        if truncated {
2685            if let Some(last) = page.last() {
2686                resp["NextMarker"] = json!(last.custom_key_store_id);
2687            }
2688        }
2689
2690        Ok(AwsResponse::json(
2691            StatusCode::OK,
2692            serde_json::to_string(&resp).unwrap(),
2693        ))
2694    }
2695
2696    fn connect_custom_key_store(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2697        let body = body_json(req);
2698
2699        let store_id = body["CustomKeyStoreId"]
2700            .as_str()
2701            .ok_or_else(|| {
2702                AwsServiceError::aws_error(
2703                    StatusCode::BAD_REQUEST,
2704                    "ValidationException",
2705                    "CustomKeyStoreId is required",
2706                )
2707            })?
2708            .to_string();
2709
2710        let mut state = self.state.write();
2711
2712        let store = state.custom_key_stores.get_mut(&store_id).ok_or_else(|| {
2713            AwsServiceError::aws_error(
2714                StatusCode::BAD_REQUEST,
2715                "CustomKeyStoreNotFoundException",
2716                format!("Custom key store '{store_id}' does not exist"),
2717            )
2718        })?;
2719
2720        store.connection_state = "CONNECTED".to_string();
2721
2722        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2723    }
2724
2725    fn disconnect_custom_key_store(
2726        &self,
2727        req: &AwsRequest,
2728    ) -> Result<AwsResponse, AwsServiceError> {
2729        let body = body_json(req);
2730
2731        let store_id = body["CustomKeyStoreId"]
2732            .as_str()
2733            .ok_or_else(|| {
2734                AwsServiceError::aws_error(
2735                    StatusCode::BAD_REQUEST,
2736                    "ValidationException",
2737                    "CustomKeyStoreId is required",
2738                )
2739            })?
2740            .to_string();
2741
2742        let mut state = self.state.write();
2743
2744        let store = state.custom_key_stores.get_mut(&store_id).ok_or_else(|| {
2745            AwsServiceError::aws_error(
2746                StatusCode::BAD_REQUEST,
2747                "CustomKeyStoreNotFoundException",
2748                format!("Custom key store '{store_id}' does not exist"),
2749            )
2750        })?;
2751
2752        store.connection_state = "DISCONNECTED".to_string();
2753
2754        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2755    }
2756
2757    fn update_custom_key_store(&self, req: &AwsRequest) -> Result<AwsResponse, AwsServiceError> {
2758        let body = body_json(req);
2759
2760        let store_id = body["CustomKeyStoreId"]
2761            .as_str()
2762            .ok_or_else(|| {
2763                AwsServiceError::aws_error(
2764                    StatusCode::BAD_REQUEST,
2765                    "ValidationException",
2766                    "CustomKeyStoreId is required",
2767                )
2768            })?
2769            .to_string();
2770
2771        let mut state = self.state.write();
2772
2773        // Check uniqueness of new name before borrowing store mutably
2774        if let Some(new_name) = body["NewCustomKeyStoreName"].as_str() {
2775            if state
2776                .custom_key_stores
2777                .values()
2778                .any(|s| s.custom_key_store_name == new_name && s.custom_key_store_id != store_id)
2779            {
2780                return Err(AwsServiceError::aws_error(
2781                    StatusCode::BAD_REQUEST,
2782                    "CustomKeyStoreNameInUseException",
2783                    format!("Custom key store name '{new_name}' is already in use"),
2784                ));
2785            }
2786        }
2787
2788        let store = state.custom_key_stores.get_mut(&store_id).ok_or_else(|| {
2789            AwsServiceError::aws_error(
2790                StatusCode::BAD_REQUEST,
2791                "CustomKeyStoreNotFoundException",
2792                format!("Custom key store '{store_id}' does not exist"),
2793            )
2794        })?;
2795
2796        if let Some(new_name) = body["NewCustomKeyStoreName"].as_str() {
2797            store.custom_key_store_name = new_name.to_string();
2798        }
2799        if let Some(v) = body["CloudHsmClusterId"].as_str() {
2800            store.cloud_hsm_cluster_id = Some(v.to_string());
2801        }
2802        if let Some(v) = body["KeyStorePassword"].as_str() {
2803            // In a real implementation this would update the password;
2804            // we just accept it silently.
2805            let _ = v;
2806        }
2807        if let Some(v) = body["XksProxyUriEndpoint"].as_str() {
2808            store.xks_proxy_uri_endpoint = Some(v.to_string());
2809        }
2810        if let Some(v) = body["XksProxyUriPath"].as_str() {
2811            store.xks_proxy_uri_path = Some(v.to_string());
2812        }
2813        if let Some(v) = body["XksProxyVpcEndpointServiceName"].as_str() {
2814            store.xks_proxy_vpc_endpoint_service_name = Some(v.to_string());
2815        }
2816        if let Some(v) = body["XksProxyConnectivity"].as_str() {
2817            store.xks_proxy_connectivity = Some(v.to_string());
2818        }
2819
2820        Ok(AwsResponse::json(StatusCode::OK, "{}"))
2821    }
2822}
2823
2824fn custom_key_store_json(store: &CustomKeyStore) -> Value {
2825    let mut obj = json!({
2826        "CustomKeyStoreId": store.custom_key_store_id,
2827        "CustomKeyStoreName": store.custom_key_store_name,
2828        "CustomKeyStoreType": store.custom_key_store_type,
2829        "ConnectionState": store.connection_state,
2830        "CreationDate": store.creation_date,
2831    });
2832    if let Some(ref v) = store.cloud_hsm_cluster_id {
2833        obj["CloudHsmClusterId"] = json!(v);
2834    }
2835    if let Some(ref v) = store.trust_anchor_certificate {
2836        obj["TrustAnchorCertificate"] = json!(v);
2837    }
2838    if let Some(ref v) = store.xks_proxy_uri_endpoint {
2839        obj["XksProxyConfiguration"] = json!({});
2840        obj["XksProxyConfiguration"]["UriEndpoint"] = json!(v);
2841        if let Some(ref p) = store.xks_proxy_uri_path {
2842            obj["XksProxyConfiguration"]["UriPath"] = json!(p);
2843        }
2844        if let Some(ref c) = store.xks_proxy_connectivity {
2845            obj["XksProxyConfiguration"]["Connectivity"] = json!(c);
2846        }
2847        if let Some(ref s) = store.xks_proxy_vpc_endpoint_service_name {
2848            obj["XksProxyConfiguration"]["VpcEndpointServiceName"] = json!(s);
2849        }
2850    }
2851    obj
2852}
2853
2854fn key_metadata_json(key: &KmsKey, account_id: &str) -> Value {
2855    let mut meta = json!({
2856        "KeyId": key.key_id,
2857        "Arn": key.arn,
2858        "AWSAccountId": account_id,
2859        "CreationDate": key.creation_date,
2860        "Description": key.description,
2861        "Enabled": key.enabled,
2862        "KeyUsage": key.key_usage,
2863        "KeySpec": key.key_spec,
2864        "CustomerMasterKeySpec": key.key_spec,
2865        "KeyManager": key.key_manager,
2866        "KeyState": key.key_state,
2867        "Origin": key.origin,
2868        "MultiRegion": key.multi_region,
2869    });
2870
2871    if let Some(ref enc_algs) = key.encryption_algorithms {
2872        meta["EncryptionAlgorithms"] = json!(enc_algs);
2873    }
2874    if let Some(ref sig_algs) = key.signing_algorithms {
2875        meta["SigningAlgorithms"] = json!(sig_algs);
2876    }
2877    if let Some(ref mac_algs) = key.mac_algorithms {
2878        meta["MacAlgorithms"] = json!(mac_algs);
2879    }
2880    if let Some(dd) = key.deletion_date {
2881        meta["DeletionDate"] = json!(dd);
2882    }
2883    if let Some(ref cks_id) = key.custom_key_store_id {
2884        meta["CustomKeyStoreId"] = json!(cks_id);
2885    }
2886
2887    if key.multi_region {
2888        // Add MultiRegionConfiguration for primary keys
2889        meta["MultiRegionConfiguration"] = json!({
2890            "MultiRegionKeyType": "PRIMARY",
2891            "PrimaryKey": {
2892                "Arn": key.arn,
2893                "Region": key.arn.split(':').nth(3).unwrap_or("us-east-1"),
2894            },
2895            "ReplicaKeys": [],
2896        });
2897    }
2898
2899    meta
2900}
2901
2902fn fmt_enum_set(items: &[String]) -> String {
2903    let inner: Vec<String> = items.iter().map(|s| format!("'{s}'")).collect();
2904    format!("[{}]", inner.join(", "))
2905}
2906
2907fn grant_to_json(grant: &KmsGrant) -> Value {
2908    let mut v = json!({
2909        "KeyId": grant.key_id,
2910        "GrantId": grant.grant_id,
2911        "GranteePrincipal": grant.grantee_principal,
2912        "Operations": grant.operations,
2913        "IssuingAccount": format!("arn:aws:iam::root"),
2914        "CreationDate": grant.creation_date,
2915    });
2916
2917    if let Some(ref rp) = grant.retiring_principal {
2918        v["RetiringPrincipal"] = json!(rp);
2919    }
2920    if let Some(ref c) = grant.constraints {
2921        v["Constraints"] = c.clone();
2922    }
2923    if let Some(ref n) = grant.name {
2924        v["Name"] = json!(n);
2925    }
2926
2927    v
2928}
2929
2930fn data_key_size_from_body(body: &Value) -> Result<usize, AwsServiceError> {
2931    let key_spec = body["KeySpec"].as_str();
2932    let number_of_bytes = body["NumberOfBytes"].as_u64();
2933
2934    match (key_spec, number_of_bytes) {
2935        (Some(_), Some(_)) => Err(AwsServiceError::aws_error(
2936            StatusCode::BAD_REQUEST,
2937            "ValidationException",
2938            "KeySpec and NumberOfBytes are mutually exclusive",
2939        )),
2940        (Some("AES_256"), None) => Ok(32),
2941        (Some("AES_128"), None) => Ok(16),
2942        (Some(spec), None) => Err(AwsServiceError::aws_error(
2943            StatusCode::BAD_REQUEST,
2944            "ValidationException",
2945            format!("1 validation error detected: Value '{spec}' at 'keySpec' failed to satisfy constraint: Member must satisfy enum value set: [AES_256, AES_128]"),
2946        )),
2947        (None, Some(n)) => {
2948            if n > 1024 {
2949                Err(AwsServiceError::aws_error(
2950                    StatusCode::BAD_REQUEST,
2951                    "ValidationException",
2952                    format!("1 validation error detected: Value '{n}' at 'numberOfBytes' failed to satisfy constraint: Member must have value less than or equal to 1024"),
2953                ))
2954            } else {
2955                Ok(n as usize)
2956            }
2957        }
2958        (None, None) => Err(AwsServiceError::aws_error(
2959            StatusCode::BAD_REQUEST,
2960            "ValidationException",
2961            "KeySpec or NumberOfBytes is required",
2962        )),
2963    }
2964}
2965
2966fn generate_fake_public_key(key_spec: &str) -> Vec<u8> {
2967    // Return a minimal but valid-looking DER-encoded SubjectPublicKeyInfo
2968    // This is a fake RSA 2048-bit public key structure for testing
2969    match key_spec {
2970        "RSA_2048" | "RSA_3072" | "RSA_4096" => {
2971            // A minimal ASN.1 DER structure for RSA public key
2972            let mut key = vec![
2973                0x30, 0x82, 0x01, 0x22, // SEQUENCE, length 290
2974                0x30, 0x0d, // SEQUENCE, length 13
2975                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
2976                0x01, // OID rsaEncryption
2977                0x05, 0x00, // NULL
2978                0x03, 0x82, 0x01, 0x0f, // BIT STRING, length 271
2979                0x00, // unused bits
2980                0x30, 0x82, 0x01, 0x0a, // SEQUENCE, length 266
2981                0x02, 0x82, 0x01, 0x01, // INTEGER, length 257
2982            ];
2983            // Fake modulus (257 bytes: 0x00 + 256 bytes of random-looking data)
2984            key.push(0x00);
2985            key.extend_from_slice(&rand_bytes(256));
2986            // Exponent
2987            key.extend_from_slice(&[0x02, 0x03, 0x01, 0x00, 0x01]); // 65537
2988            key
2989        }
2990        "ECC_NIST_P256" | "ECC_SECG_P256K1" => {
2991            // Minimal EC public key for P-256
2992            let mut key = vec![
2993                0x30, 0x59, // SEQUENCE, length 89
2994                0x30, 0x13, // SEQUENCE, length 19
2995                0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // OID ecPublicKey
2996                0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, // OID prime256v1
2997                0x03, 0x42, // BIT STRING, length 66
2998                0x00, // unused bits
2999                0x04, // uncompressed point
3000            ];
3001            key.extend_from_slice(&rand_bytes(64)); // x and y coordinates
3002            key
3003        }
3004        "ECC_NIST_P384" => {
3005            let mut key = vec![
3006                0x30, 0x76, // SEQUENCE, length 118
3007                0x30, 0x10, // SEQUENCE, length 16
3008                0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // OID ecPublicKey
3009                0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, // OID secp384r1
3010                0x03, 0x62, // BIT STRING, length 98
3011                0x00, // unused bits
3012                0x04, // uncompressed point
3013            ];
3014            key.extend_from_slice(&rand_bytes(96)); // x and y coordinates
3015            key
3016        }
3017        "ECC_NIST_P521" => {
3018            let mut key = vec![
3019                0x30, 0x81, 0x9b, // SEQUENCE, length 155
3020                0x30, 0x10, // SEQUENCE, length 16
3021                0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // OID ecPublicKey
3022                0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, // OID secp521r1
3023                0x03, 0x81, 0x86, // BIT STRING, length 134
3024                0x00, // unused bits
3025                0x04, // uncompressed point
3026            ];
3027            key.extend_from_slice(&rand_bytes(132)); // x and y coordinates
3028            key
3029        }
3030        _ => rand_bytes(32),
3031    }
3032}
3033
3034fn check_policy_deny(key: &KmsKey, action: &str) -> Result<(), AwsServiceError> {
3035    // Parse the policy and check for Deny statements
3036    let policy: Value = match serde_json::from_str(&key.policy) {
3037        Ok(v) => v,
3038        Err(_) => return Ok(()), // If policy can't be parsed, allow
3039    };
3040
3041    let statements = match policy["Statement"].as_array() {
3042        Some(s) => s,
3043        None => return Ok(()),
3044    };
3045
3046    for stmt in statements {
3047        let effect = stmt["Effect"].as_str().unwrap_or("");
3048        if !effect.eq_ignore_ascii_case("deny") {
3049            continue;
3050        }
3051
3052        // Check Resource - only deny if resource is "*"
3053        let resource = &stmt["Resource"];
3054        let resource_matches = if let Some(r) = resource.as_str() {
3055            r == "*"
3056        } else if let Some(arr) = resource.as_array() {
3057            arr.iter().any(|r| r.as_str() == Some("*"))
3058        } else {
3059            false
3060        };
3061
3062        if !resource_matches {
3063            continue;
3064        }
3065
3066        // Check Action
3067        let actions = if let Some(a) = stmt["Action"].as_str() {
3068            vec![a.to_string()]
3069        } else if let Some(arr) = stmt["Action"].as_array() {
3070            arr.iter()
3071                .filter_map(|a| a.as_str().map(|s| s.to_string()))
3072                .collect()
3073        } else {
3074            continue;
3075        };
3076
3077        for policy_action in &actions {
3078            if action_matches(policy_action, action) {
3079                return Err(AwsServiceError::aws_error(
3080                    StatusCode::BAD_REQUEST,
3081                    "AccessDeniedException",
3082                    format!(
3083                        "User is not authorized to perform: {} on resource: {}",
3084                        action, key.arn
3085                    ),
3086                ));
3087            }
3088        }
3089    }
3090
3091    Ok(())
3092}
3093
3094fn action_matches(policy_action: &str, requested_action: &str) -> bool {
3095    if policy_action == "kms:*" {
3096        return true;
3097    }
3098    if policy_action == requested_action {
3099        return true;
3100    }
3101    // Wildcard matching: "kms:Describe*" matches "kms:DescribeKey"
3102    if let Some(prefix) = policy_action.strip_suffix('*') {
3103        if requested_action.starts_with(prefix) {
3104            return true;
3105        }
3106    }
3107    false
3108}
3109
3110#[cfg(test)]
3111mod tests {
3112    use super::*;
3113    use parking_lot::RwLock;
3114    use serde_json::json;
3115    use std::collections::HashMap;
3116    use std::sync::Arc;
3117
3118    fn make_service() -> KmsService {
3119        let state: SharedKmsState = Arc::new(RwLock::new(crate::state::KmsState::new(
3120            "123456789012",
3121            "us-east-1",
3122        )));
3123        KmsService::new(state)
3124    }
3125
3126    fn make_request(action: &str, body: Value) -> AwsRequest {
3127        AwsRequest {
3128            service: "kms".to_string(),
3129            action: action.to_string(),
3130            region: "us-east-1".to_string(),
3131            account_id: "123456789012".to_string(),
3132            request_id: "test-id".to_string(),
3133            headers: http::HeaderMap::new(),
3134            query_params: HashMap::new(),
3135            body: serde_json::to_vec(&body).unwrap().into(),
3136            path_segments: vec![],
3137            raw_path: "/".to_string(),
3138            method: http::Method::POST,
3139            is_query_protocol: false,
3140            access_key_id: None,
3141        }
3142    }
3143
3144    fn create_key(svc: &KmsService) -> String {
3145        let req = make_request("CreateKey", json!({}));
3146        let resp = svc.create_key(&req).unwrap();
3147        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3148        body["KeyMetadata"]["KeyId"].as_str().unwrap().to_string()
3149    }
3150
3151    #[test]
3152    fn list_keys_pagination_no_duplicates() {
3153        let svc = make_service();
3154        let mut all_key_ids: Vec<String> = Vec::new();
3155        for _ in 0..5 {
3156            all_key_ids.push(create_key(&svc));
3157        }
3158
3159        let mut collected_ids: Vec<String> = Vec::new();
3160        let mut marker: Option<String> = None;
3161
3162        loop {
3163            let mut body = json!({ "Limit": 2 });
3164            if let Some(ref m) = marker {
3165                body["Marker"] = json!(m);
3166            }
3167            let req = make_request("ListKeys", body);
3168            let resp = svc.list_keys(&req).unwrap();
3169            let resp_body: Value = serde_json::from_slice(&resp.body).unwrap();
3170
3171            for key in resp_body["Keys"].as_array().unwrap() {
3172                collected_ids.push(key["KeyId"].as_str().unwrap().to_string());
3173            }
3174
3175            if resp_body["Truncated"].as_bool().unwrap_or(false) {
3176                marker = resp_body["NextMarker"].as_str().map(|s| s.to_string());
3177            } else {
3178                break;
3179            }
3180        }
3181
3182        // Verify no duplicates
3183        let mut deduped = collected_ids.clone();
3184        deduped.sort();
3185        deduped.dedup();
3186        assert_eq!(
3187            collected_ids.len(),
3188            deduped.len(),
3189            "pagination produced duplicate keys"
3190        );
3191
3192        // Verify all keys returned
3193        for kid in &all_key_ids {
3194            assert!(
3195                collected_ids.contains(kid),
3196                "key {kid} missing from paginated results"
3197            );
3198        }
3199    }
3200
3201    #[test]
3202    fn list_retirable_grants_pagination() {
3203        let svc = make_service();
3204        let key_id = create_key(&svc);
3205        let retiring = "arn:aws:iam::123456789012:user/retiring-user";
3206
3207        // Create 5 grants with the same retiring principal
3208        for i in 0..5 {
3209            let req = make_request(
3210                "CreateGrant",
3211                json!({
3212                    "KeyId": key_id,
3213                    "GranteePrincipal": format!("arn:aws:iam::123456789012:user/grantee-{i}"),
3214                    "RetiringPrincipal": retiring,
3215                    "Operations": ["Encrypt"]
3216                }),
3217            );
3218            svc.create_grant(&req).unwrap();
3219        }
3220
3221        let mut collected_ids: Vec<String> = Vec::new();
3222        let mut marker: Option<String> = None;
3223
3224        loop {
3225            let mut body = json!({
3226                "RetiringPrincipal": retiring,
3227                "Limit": 2
3228            });
3229            if let Some(ref m) = marker {
3230                body["Marker"] = json!(m);
3231            }
3232            let req = make_request("ListRetirableGrants", body);
3233            let resp = svc.list_retirable_grants(&req).unwrap();
3234            let resp_body: Value = serde_json::from_slice(&resp.body).unwrap();
3235
3236            for grant in resp_body["Grants"].as_array().unwrap() {
3237                collected_ids.push(grant["GrantId"].as_str().unwrap().to_string());
3238            }
3239
3240            if resp_body["Truncated"].as_bool().unwrap_or(false) {
3241                marker = resp_body["NextMarker"].as_str().map(|s| s.to_string());
3242            } else {
3243                break;
3244            }
3245        }
3246
3247        // Verify no duplicates
3248        let mut deduped = collected_ids.clone();
3249        deduped.sort();
3250        deduped.dedup();
3251        assert_eq!(
3252            collected_ids.len(),
3253            deduped.len(),
3254            "pagination produced duplicate grants"
3255        );
3256
3257        // All 5 grants returned
3258        assert_eq!(collected_ids.len(), 5, "expected 5 grants total");
3259    }
3260
3261    fn create_key_with_opts(svc: &KmsService, body: Value) -> String {
3262        let req = make_request("CreateKey", body);
3263        let resp = svc.create_key(&req).unwrap();
3264        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3265        body["KeyMetadata"]["KeyId"].as_str().unwrap().to_string()
3266    }
3267
3268    #[test]
3269    fn generate_data_key_pair_returns_all_fields() {
3270        let svc = make_service();
3271        let key_id = create_key(&svc);
3272
3273        let req = make_request(
3274            "GenerateDataKeyPair",
3275            json!({ "KeyId": key_id, "KeyPairSpec": "RSA_2048" }),
3276        );
3277        let resp = svc.generate_data_key_pair(&req).unwrap();
3278        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3279
3280        assert!(body["PublicKey"].as_str().is_some());
3281        assert!(body["PrivateKeyPlaintext"].as_str().is_some());
3282        assert!(body["PrivateKeyCiphertextBlob"].as_str().is_some());
3283        assert_eq!(body["KeyPairSpec"].as_str().unwrap(), "RSA_2048");
3284        assert!(body["KeyId"].as_str().unwrap().contains(":key/"));
3285    }
3286
3287    #[test]
3288    fn generate_data_key_pair_disabled_key_fails() {
3289        let svc = make_service();
3290        let key_id = create_key(&svc);
3291
3292        let disable_req = make_request("DisableKey", json!({ "KeyId": key_id }));
3293        svc.disable_key(&disable_req).unwrap();
3294
3295        let req = make_request(
3296            "GenerateDataKeyPair",
3297            json!({ "KeyId": key_id, "KeyPairSpec": "RSA_2048" }),
3298        );
3299        assert!(svc.generate_data_key_pair(&req).is_err());
3300    }
3301
3302    #[test]
3303    fn generate_data_key_pair_without_plaintext_omits_private_plaintext() {
3304        let svc = make_service();
3305        let key_id = create_key(&svc);
3306
3307        let req = make_request(
3308            "GenerateDataKeyPairWithoutPlaintext",
3309            json!({ "KeyId": key_id, "KeyPairSpec": "ECC_NIST_P256" }),
3310        );
3311        let resp = svc.generate_data_key_pair_without_plaintext(&req).unwrap();
3312        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3313
3314        assert!(body["PublicKey"].as_str().is_some());
3315        assert!(body["PrivateKeyCiphertextBlob"].as_str().is_some());
3316        assert!(body.get("PrivateKeyPlaintext").is_none());
3317        assert_eq!(body["KeyPairSpec"].as_str().unwrap(), "ECC_NIST_P256");
3318    }
3319
3320    #[test]
3321    fn derive_shared_secret_success() {
3322        let svc = make_service();
3323        let key_id = create_key_with_opts(
3324            &svc,
3325            json!({
3326                "KeyUsage": "KEY_AGREEMENT",
3327                "KeySpec": "ECC_NIST_P256"
3328            }),
3329        );
3330
3331        let fake_pub = base64::engine::general_purpose::STANDARD.encode(b"fake-public-key");
3332        let req = make_request(
3333            "DeriveSharedSecret",
3334            json!({
3335                "KeyId": key_id,
3336                "KeyAgreementAlgorithm": "ECDH",
3337                "PublicKey": fake_pub
3338            }),
3339        );
3340        let resp = svc.derive_shared_secret(&req).unwrap();
3341        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3342
3343        assert!(body["SharedSecret"].as_str().is_some());
3344        assert!(body["KeyId"].as_str().unwrap().contains(":key/"));
3345        assert_eq!(body["KeyAgreementAlgorithm"].as_str().unwrap(), "ECDH");
3346    }
3347
3348    #[test]
3349    fn derive_shared_secret_wrong_usage_fails() {
3350        let svc = make_service();
3351        let key_id = create_key(&svc); // Default is ENCRYPT_DECRYPT
3352
3353        let fake_pub = base64::engine::general_purpose::STANDARD.encode(b"fake-public-key");
3354        let req = make_request(
3355            "DeriveSharedSecret",
3356            json!({
3357                "KeyId": key_id,
3358                "KeyAgreementAlgorithm": "ECDH",
3359                "PublicKey": fake_pub
3360            }),
3361        );
3362        assert!(svc.derive_shared_secret(&req).is_err());
3363    }
3364
3365    #[test]
3366    fn get_parameters_for_import_success() {
3367        let svc = make_service();
3368        let key_id = create_key_with_opts(&svc, json!({ "Origin": "EXTERNAL" }));
3369
3370        let req = make_request(
3371            "GetParametersForImport",
3372            json!({ "KeyId": key_id, "WrappingAlgorithm": "RSAES_OAEP_SHA_256", "WrappingKeySpec": "RSA_2048" }),
3373        );
3374        let resp = svc.get_parameters_for_import(&req).unwrap();
3375        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3376
3377        assert!(body["ImportToken"].as_str().is_some());
3378        assert!(body["PublicKey"].as_str().is_some());
3379        assert!(body["ParametersValidTo"].as_f64().is_some());
3380        assert!(body["KeyId"].as_str().unwrap().contains(":key/"));
3381    }
3382
3383    #[test]
3384    fn get_parameters_for_import_non_external_fails() {
3385        let svc = make_service();
3386        let key_id = create_key(&svc); // Default origin is AWS_KMS
3387
3388        let req = make_request("GetParametersForImport", json!({ "KeyId": key_id }));
3389        assert!(svc.get_parameters_for_import(&req).is_err());
3390    }
3391
3392    #[test]
3393    fn import_key_material_lifecycle() {
3394        let svc = make_service();
3395        let key_id = create_key_with_opts(&svc, json!({ "Origin": "EXTERNAL" }));
3396
3397        let fake_token = base64::engine::general_purpose::STANDARD.encode(b"token");
3398        let fake_material = base64::engine::general_purpose::STANDARD.encode(b"material");
3399
3400        // Import
3401        let req = make_request(
3402            "ImportKeyMaterial",
3403            json!({
3404                "KeyId": key_id,
3405                "ImportToken": fake_token,
3406                "EncryptedKeyMaterial": fake_material,
3407                "ExpirationModel": "KEY_MATERIAL_DOES_NOT_EXPIRE"
3408            }),
3409        );
3410        svc.import_key_material(&req).unwrap();
3411
3412        // Key should be enabled
3413        {
3414            let state = svc.state.read();
3415            let key = state.keys.get(&key_id).unwrap();
3416            assert!(key.imported_key_material);
3417            assert!(key.enabled);
3418        }
3419
3420        // Delete imported material
3421        let req = make_request("DeleteImportedKeyMaterial", json!({ "KeyId": key_id }));
3422        svc.delete_imported_key_material(&req).unwrap();
3423
3424        // Key should be disabled and pending import
3425        {
3426            let state = svc.state.read();
3427            let key = state.keys.get(&key_id).unwrap();
3428            assert!(!key.imported_key_material);
3429            assert!(!key.enabled);
3430            assert_eq!(key.key_state, "PendingImport");
3431        }
3432    }
3433
3434    #[test]
3435    fn import_key_material_non_external_fails() {
3436        let svc = make_service();
3437        let key_id = create_key(&svc);
3438
3439        let fake_token = base64::engine::general_purpose::STANDARD.encode(b"token");
3440        let fake_material = base64::engine::general_purpose::STANDARD.encode(b"material");
3441
3442        let req = make_request(
3443            "ImportKeyMaterial",
3444            json!({
3445                "KeyId": key_id,
3446                "ImportToken": fake_token,
3447                "EncryptedKeyMaterial": fake_material
3448            }),
3449        );
3450        assert!(svc.import_key_material(&req).is_err());
3451    }
3452
3453    #[test]
3454    fn delete_imported_key_material_non_external_fails() {
3455        let svc = make_service();
3456        let key_id = create_key(&svc);
3457
3458        let req = make_request("DeleteImportedKeyMaterial", json!({ "KeyId": key_id }));
3459        assert!(svc.delete_imported_key_material(&req).is_err());
3460    }
3461
3462    #[test]
3463    fn update_primary_region_success() {
3464        let svc = make_service();
3465        let key_id = create_key_with_opts(&svc, json!({ "MultiRegion": true }));
3466
3467        let req = make_request(
3468            "UpdatePrimaryRegion",
3469            json!({ "KeyId": key_id, "PrimaryRegion": "eu-west-1" }),
3470        );
3471        svc.update_primary_region(&req).unwrap();
3472
3473        let state = svc.state.read();
3474        let key = state.keys.get(&key_id).unwrap();
3475        assert_eq!(key.primary_region.as_deref(), Some("eu-west-1"));
3476        assert!(key.arn.contains("eu-west-1"));
3477    }
3478
3479    #[test]
3480    fn update_primary_region_non_multi_region_fails() {
3481        let svc = make_service();
3482        let key_id = create_key(&svc); // Not multi-region
3483
3484        let req = make_request(
3485            "UpdatePrimaryRegion",
3486            json!({ "KeyId": key_id, "PrimaryRegion": "eu-west-1" }),
3487        );
3488        assert!(svc.update_primary_region(&req).is_err());
3489    }
3490
3491    #[test]
3492    fn custom_key_store_lifecycle() {
3493        let svc = make_service();
3494
3495        // Create
3496        let req = make_request(
3497            "CreateCustomKeyStore",
3498            json!({
3499                "CustomKeyStoreName": "my-store",
3500                "CloudHsmClusterId": "cluster-1234",
3501                "TrustAnchorCertificate": "cert-data",
3502                "KeyStorePassword": "password123"
3503            }),
3504        );
3505        let resp = svc.create_custom_key_store(&req).unwrap();
3506        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3507        let store_id = body["CustomKeyStoreId"].as_str().unwrap().to_string();
3508        assert!(store_id.starts_with("cks-"));
3509
3510        // Describe
3511        let req = make_request(
3512            "DescribeCustomKeyStores",
3513            json!({ "CustomKeyStoreId": store_id }),
3514        );
3515        let resp = svc.describe_custom_key_stores(&req).unwrap();
3516        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3517        let stores = body["CustomKeyStores"].as_array().unwrap();
3518        assert_eq!(stores.len(), 1);
3519        assert_eq!(
3520            stores[0]["CustomKeyStoreName"].as_str().unwrap(),
3521            "my-store"
3522        );
3523        assert_eq!(
3524            stores[0]["ConnectionState"].as_str().unwrap(),
3525            "DISCONNECTED"
3526        );
3527        assert_eq!(
3528            stores[0]["CloudHsmClusterId"].as_str().unwrap(),
3529            "cluster-1234"
3530        );
3531
3532        // Connect
3533        let req = make_request(
3534            "ConnectCustomKeyStore",
3535            json!({ "CustomKeyStoreId": store_id }),
3536        );
3537        svc.connect_custom_key_store(&req).unwrap();
3538
3539        // Verify connected
3540        let req = make_request(
3541            "DescribeCustomKeyStores",
3542            json!({ "CustomKeyStoreId": store_id }),
3543        );
3544        let resp = svc.describe_custom_key_stores(&req).unwrap();
3545        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3546        assert_eq!(
3547            body["CustomKeyStores"][0]["ConnectionState"]
3548                .as_str()
3549                .unwrap(),
3550            "CONNECTED"
3551        );
3552
3553        // Cannot delete when connected
3554        let req = make_request(
3555            "DeleteCustomKeyStore",
3556            json!({ "CustomKeyStoreId": store_id }),
3557        );
3558        assert!(svc.delete_custom_key_store(&req).is_err());
3559
3560        // Disconnect
3561        let req = make_request(
3562            "DisconnectCustomKeyStore",
3563            json!({ "CustomKeyStoreId": store_id }),
3564        );
3565        svc.disconnect_custom_key_store(&req).unwrap();
3566
3567        // Update name
3568        let req = make_request(
3569            "UpdateCustomKeyStore",
3570            json!({
3571                "CustomKeyStoreId": store_id,
3572                "NewCustomKeyStoreName": "renamed-store"
3573            }),
3574        );
3575        svc.update_custom_key_store(&req).unwrap();
3576
3577        // Verify update
3578        let req = make_request(
3579            "DescribeCustomKeyStores",
3580            json!({ "CustomKeyStoreId": store_id }),
3581        );
3582        let resp = svc.describe_custom_key_stores(&req).unwrap();
3583        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3584        assert_eq!(
3585            body["CustomKeyStores"][0]["CustomKeyStoreName"]
3586                .as_str()
3587                .unwrap(),
3588            "renamed-store"
3589        );
3590
3591        // Delete
3592        let req = make_request(
3593            "DeleteCustomKeyStore",
3594            json!({ "CustomKeyStoreId": store_id }),
3595        );
3596        svc.delete_custom_key_store(&req).unwrap();
3597
3598        // Describe all should return empty
3599        let req = make_request("DescribeCustomKeyStores", json!({}));
3600        let resp = svc.describe_custom_key_stores(&req).unwrap();
3601        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3602        assert!(body["CustomKeyStores"].as_array().unwrap().is_empty());
3603    }
3604
3605    #[test]
3606    fn custom_key_store_duplicate_name_fails() {
3607        let svc = make_service();
3608
3609        let req = make_request(
3610            "CreateCustomKeyStore",
3611            json!({ "CustomKeyStoreName": "dup-store" }),
3612        );
3613        svc.create_custom_key_store(&req).unwrap();
3614
3615        let req = make_request(
3616            "CreateCustomKeyStore",
3617            json!({ "CustomKeyStoreName": "dup-store" }),
3618        );
3619        assert!(svc.create_custom_key_store(&req).is_err());
3620    }
3621
3622    #[test]
3623    fn describe_custom_key_store_not_found() {
3624        let svc = make_service();
3625
3626        let req = make_request(
3627            "DescribeCustomKeyStores",
3628            json!({ "CustomKeyStoreId": "cks-nonexistent" }),
3629        );
3630        assert!(svc.describe_custom_key_stores(&req).is_err());
3631    }
3632
3633    #[test]
3634    fn delete_nonexistent_custom_key_store_fails() {
3635        let svc = make_service();
3636
3637        let req = make_request(
3638            "DeleteCustomKeyStore",
3639            json!({ "CustomKeyStoreId": "cks-nonexistent" }),
3640        );
3641        assert!(svc.delete_custom_key_store(&req).is_err());
3642    }
3643
3644    #[test]
3645    fn connect_nonexistent_custom_key_store_fails() {
3646        let svc = make_service();
3647
3648        let req = make_request(
3649            "ConnectCustomKeyStore",
3650            json!({ "CustomKeyStoreId": "cks-nonexistent" }),
3651        );
3652        assert!(svc.connect_custom_key_store(&req).is_err());
3653    }
3654
3655    #[test]
3656    fn describe_custom_key_stores_by_name() {
3657        let svc = make_service();
3658
3659        let req = make_request(
3660            "CreateCustomKeyStore",
3661            json!({ "CustomKeyStoreName": "store-a" }),
3662        );
3663        svc.create_custom_key_store(&req).unwrap();
3664
3665        let req = make_request(
3666            "CreateCustomKeyStore",
3667            json!({ "CustomKeyStoreName": "store-b" }),
3668        );
3669        svc.create_custom_key_store(&req).unwrap();
3670
3671        // Filter by name
3672        let req = make_request(
3673            "DescribeCustomKeyStores",
3674            json!({ "CustomKeyStoreName": "store-a" }),
3675        );
3676        let resp = svc.describe_custom_key_stores(&req).unwrap();
3677        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3678        let stores = body["CustomKeyStores"].as_array().unwrap();
3679        assert_eq!(stores.len(), 1);
3680        assert_eq!(stores[0]["CustomKeyStoreName"].as_str().unwrap(), "store-a");
3681    }
3682
3683    #[test]
3684    fn update_custom_key_store_name_conflict() {
3685        let svc = make_service();
3686
3687        let req = make_request(
3688            "CreateCustomKeyStore",
3689            json!({ "CustomKeyStoreName": "store-x" }),
3690        );
3691        svc.create_custom_key_store(&req).unwrap();
3692
3693        let req = make_request(
3694            "CreateCustomKeyStore",
3695            json!({ "CustomKeyStoreName": "store-y" }),
3696        );
3697        let resp = svc.create_custom_key_store(&req).unwrap();
3698        let body: Value = serde_json::from_slice(&resp.body).unwrap();
3699        let store_y_id = body["CustomKeyStoreId"].as_str().unwrap().to_string();
3700
3701        // Try to rename store-y to store-x
3702        let req = make_request(
3703            "UpdateCustomKeyStore",
3704            json!({
3705                "CustomKeyStoreId": store_y_id,
3706                "NewCustomKeyStoreName": "store-x"
3707            }),
3708        );
3709        assert!(svc.update_custom_key_store(&req).is_err());
3710    }
3711}