@@ -540,6 +540,78 @@ pub(crate) fn require_usable_key_state(key: &KmsKey) -> Result<(), AwsServiceErr
540540 ) )
541541}
542542
543+ /// The KeyUsage values compatible with a given KeySpec, per AWS KMS. An
544+ /// empty slice means the spec is unknown (leave validation to later paths).
545+ fn allowed_usages_for_key_spec ( key_spec : & str ) -> & ' static [ & ' static str ] {
546+ match key_spec {
547+ "SYMMETRIC_DEFAULT" => & [ "ENCRYPT_DECRYPT" ] ,
548+ s if s. starts_with ( "HMAC_" ) => & [ "GENERATE_VERIFY_MAC" ] ,
549+ s if s. starts_with ( "RSA_" ) => & [ "ENCRYPT_DECRYPT" , "SIGN_VERIFY" ] ,
550+ // NIST curves support signing and key agreement.
551+ "ECC_NIST_P256" | "ECC_NIST_P384" | "ECC_NIST_P521" => & [ "SIGN_VERIFY" , "KEY_AGREEMENT" ] ,
552+ // secp256k1 supports signing only.
553+ "ECC_SECG_P256K1" => & [ "SIGN_VERIFY" ] ,
554+ // SM2 (China regions) supports all three.
555+ "SM2" => & [ "SIGN_VERIFY" , "ENCRYPT_DECRYPT" , "KEY_AGREEMENT" ] ,
556+ _ => & [ ] ,
557+ }
558+ }
559+
560+ /// CreateKey must reject a KeyUsage that is incompatible with the KeySpec
561+ /// (e.g. HMAC_256 + ENCRYPT_DECRYPT), which would otherwise create a key that
562+ /// no crypto operation can use. AWS returns ValidationException.
563+ pub ( crate ) fn validate_key_spec_usage (
564+ key_spec : & str ,
565+ key_usage : & str ,
566+ ) -> Result < ( ) , AwsServiceError > {
567+ let allowed = allowed_usages_for_key_spec ( key_spec) ;
568+ if allowed. is_empty ( ) || allowed. contains ( & key_usage) {
569+ return Ok ( ( ) ) ;
570+ }
571+ Err ( AwsServiceError :: aws_error (
572+ StatusCode :: BAD_REQUEST ,
573+ "ValidationException" ,
574+ format ! ( "KeyUsage {key_usage} is not compatible with KeySpec {key_spec}" ) ,
575+ ) )
576+ }
577+
578+ /// EnableKey / DisableKey may only transition a key that is currently
579+ /// `Enabled` or `Disabled`. Any other lifecycle state
580+ /// (`PendingDeletion`, `PendingImport`, `Unavailable`, ...) is a
581+ /// `KMSInvalidStateException`; in particular a scheduled-for-deletion key must
582+ /// not be resurrected without CancelKeyDeletion.
583+ pub ( crate ) fn require_enable_disable_transition ( key : & KmsKey ) -> Result < ( ) , AwsServiceError > {
584+ if key. key_state == "Enabled" || key. key_state == "Disabled" {
585+ return Ok ( ( ) ) ;
586+ }
587+ Err ( AwsServiceError :: aws_error (
588+ StatusCode :: BAD_REQUEST ,
589+ "KMSInvalidStateException" ,
590+ format ! (
591+ "Key '{}' is not in a state that allows this operation (current state: {})" ,
592+ key. arn, key. key_state
593+ ) ,
594+ ) )
595+ }
596+
597+ /// GenerateDataKey / GenerateDataKeyPair (and their `WithoutPlaintext`
598+ /// variants) require an `ENCRYPT_DECRYPT` key. A SIGN_VERIFY /
599+ /// GENERATE_VERIFY_MAC / KEY_AGREEMENT key must be rejected with
600+ /// `InvalidKeyUsageException`, matching the Encrypt/ReEncrypt paths.
601+ pub ( crate ) fn require_key_usage_encrypt_decrypt ( key : & KmsKey ) -> Result < ( ) , AwsServiceError > {
602+ if key. key_usage != "ENCRYPT_DECRYPT" {
603+ return Err ( AwsServiceError :: aws_error (
604+ StatusCode :: BAD_REQUEST ,
605+ "InvalidKeyUsageException" ,
606+ format ! (
607+ "The operation failed because the KMS key {} is not enabled for the requested operation. The key usage must be ENCRYPT_DECRYPT but is {}." ,
608+ key. arn, key. key_usage
609+ ) ,
610+ ) ) ;
611+ }
612+ Ok ( ( ) )
613+ }
614+
543615pub ( crate ) fn validate_key_usage_signing (
544616 key : & KmsKey ,
545617 resolved : & str ,
@@ -923,3 +995,28 @@ pub(crate) fn action_matches(policy_action: &str, requested_action: &str) -> boo
923995 }
924996 false
925997}
998+
999+ #[ cfg( test) ]
1000+ mod key_spec_usage_tests {
1001+ use super :: validate_key_spec_usage;
1002+
1003+ #[ test]
1004+ fn compatible_combos_pass ( ) {
1005+ assert ! ( validate_key_spec_usage( "SYMMETRIC_DEFAULT" , "ENCRYPT_DECRYPT" ) . is_ok( ) ) ;
1006+ assert ! ( validate_key_spec_usage( "HMAC_256" , "GENERATE_VERIFY_MAC" ) . is_ok( ) ) ;
1007+ assert ! ( validate_key_spec_usage( "RSA_2048" , "SIGN_VERIFY" ) . is_ok( ) ) ;
1008+ assert ! ( validate_key_spec_usage( "RSA_2048" , "ENCRYPT_DECRYPT" ) . is_ok( ) ) ;
1009+ assert ! ( validate_key_spec_usage( "ECC_NIST_P256" , "KEY_AGREEMENT" ) . is_ok( ) ) ;
1010+ assert ! ( validate_key_spec_usage( "ECC_NIST_P256" , "SIGN_VERIFY" ) . is_ok( ) ) ;
1011+ }
1012+
1013+ #[ test]
1014+ fn incompatible_combos_rejected ( ) {
1015+ // HMAC key can't encrypt/decrypt.
1016+ assert ! ( validate_key_spec_usage( "HMAC_256" , "ENCRYPT_DECRYPT" ) . is_err( ) ) ;
1017+ // Symmetric key can't sign.
1018+ assert ! ( validate_key_spec_usage( "SYMMETRIC_DEFAULT" , "SIGN_VERIFY" ) . is_err( ) ) ;
1019+ // secp256k1 supports signing only.
1020+ assert ! ( validate_key_spec_usage( "ECC_SECG_P256K1" , "KEY_AGREEMENT" ) . is_err( ) ) ;
1021+ }
1022+ }
0 commit comments