Repository: localstack/localstack

Issue:
bug: KMS import key material fails
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

By using a Pro version in the docker compose,  I'm trying to import key material in accordance to official [AWS step by step guide](https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-create-cmk.html).
And at the very last step (kms import-key-material) I'm constantly getting error.


### Expected Behavior

It is expected that import key material will be successful by using the comprehensive verity of AWS officially supported parameters such as padding, algorithms, etc.

### How are you starting LocalStack?

With a docker-compose file

### Steps To Reproduce

#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)

    docker run localstack/localstack

#### Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

Script to reproduce (OS X brew):
```shell
#!/usr/bin/env sh

# KMS import key material with AWS CLI
# https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-create-cmk.html#importing-keys-create-cmk-console
#

OPEN_SSL_PATH=/usr/local/opt/openssl@3/bin/
OPENSSL_VERSION=`${OPEN_SSL_PATH}openssl version`
if case $OPENSSL_VERSION in OpenSSL*) false;; *) ;; esac; then
  echo
  echo "This script requires openssl, whereas '${OPENSSL_VERSION}' is installed, "
  echo "please install correct openssl version and ensure that it will be used."
  echo
  echo "On OS X: brew install openssl@3 && brew link --force openssl@3"
  exit 1
fi

OPENSSL=${OPEN_SSL_PATH}openssl
echo "OpenSSL:  ${OPENSSL_VERSION}"


AWS_CLI="aws --profile=localstack --endpoint-url=http://localhost:4566"

check_retval() {
  if [ $? -ne 0 ]; then
    echo
    echo "!!! ERROR !!!"
    echo
    exit 1;
  fi
}

WORK_DIR="$(pwd)/kms-import-key"
rm -f -R "${WORK_DIR}"
mkdir "${WORK_DIR}"

key_id=$(${AWS_CLI} kms create-key --origin EXTERNAL --tags TagKey=Purpose,TagValue=Lab --description "test key to import key material" | jq -r .KeyMetadata.KeyId)
check_retval

echo
echo "AWS KMS Key has been created: KeyId:  ${key_id}"

raw_import_params=$(${AWS_CLI} kms get-parameters-for-import \
    --key-id "${key_id}" \
    --wrapping-algorithm RSAES_OAEP_SHA_1 \
    --wrapping-key-spec RSA_2048
)
check_retval

import_token=$( echo "${raw_import_params}" | jq -r .ImportToken )
check_retval

import_pubk=$( echo "${raw_import_params}" | jq -r .PublicKey )
check_retval

echo "${import_token}" >> "${WORK_DIR}/Token.b64"
echo "${import_pubk}" >> "${WORK_DIR}/PublicKey.b64"


${OPENSSL} enc -d -base64 -A -in "${WORK_DIR}/Token.b64" -out "${WORK_DIR}/Token.bin"
check_retval

${OPENSSL} enc -d -base64 -A -in "${WORK_DIR}/PublicKey.b64" -out "${WORK_DIR}/PublicKey.bin"
check_retval

${OPENSSL} rand -out "${WORK_DIR}/PlaintextKeyMaterial.bin" 32
check_retval

# The command rsautl was deprecated in version 3.0. Use 'pkeyutl' instead.
${OPENSSL} rsautl -encrypt \
    -in "${WORK_DIR}/PlaintextKeyMaterial.bin" \
    -oaep \
    -inkey "${WORK_DIR}/PublicKey.bin" \
    -keyform DER \
    -pubin \
    -out "${WORK_DIR}/EncryptedKeyMaterial.bin"
check_retval

$(${AWS_CLI} kms import-key-material --key-id "${key_id}" \
                              --encrypted-key-material "fileb://${WORK_DIR}/EncryptedKeyMaterial.bin" \
                              --import-token "fileb://${WORK_DIR}/Token.bin" \
                              --expiration-model KEY_MATERIAL_DOES_NOT_EXPIRE
)
```


### Environment

```markdown
- OS: OS X
- LocalStack: latest Pro version

     LocalStack version: 0.14.4.dev
     LocalStack Docker container id: f0d4882ec7e2
     LocalStack build date: 2022-06-25
     LocalStack build git hash: 0ae805df 
     2022-07-06T13:18:15.524:INFO:localstack_ext.bootstrap.licensing: Successfully activated API key

- OpenSSL 3.0.5 5 Jul 2022 (Library: OpenSSL 3.0.5 5 Jul 2022)
```

### Anything else?

From  the error log I see that `padding.PKCS1v15()` is used, 

```
 key_material = import_state.key_obj.decrypt(encrypted_key_material, padding.PKCS1v15())
```

, whereas, originally, in accordance to the AWS guide, I was requesting Import params for:
```shell
raw_import_params=$(${AWS_CLI} kms get-parameters-for-import \
    --key-id "${key_id}" \
    --wrapping-algorithm RSAES_OAEP_SHA_1 \
    --wrapping-key-spec RSA_2048
)
```

It seems like the original request parameters are ignored, whereas they should be tied to import token and used later during the actual  import key material operation.

Here is the complete error from the logs:

```
aws-stack_1       | 2022-07-06T12:58:37.790:WARNING:localstack.utils.server.http2_server: Error in proxy handler for request POST http://localhost:4566/: Encryption/decryption failed. Traceback (most recent call last):
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/server/http2_server.py", line 185, in index
aws-stack_1       |     result = await run_sync(handler, request, data)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/asyncio.py", line 85, in run_sync
aws-stack_1       |     return await loop.run_in_executor(thread_pool, copy_context().run, func_wrapped)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/threads.py", line 39, in run
aws-stack_1       |     result = self.func(self.params, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/asyncio.py", line 30, in _run
aws-stack_1       |     return fn(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 993, in handler
aws-stack_1       |     return modify_and_forward(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 534, in wrapper
aws-stack_1       |     value = func(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 614, in modify_and_forward
aws-stack_1       |     listener_result = listener.forward_request(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 170, in forward_request
aws-stack_1       |     result = do_forward_request(api, method, path, data, headers, port=port)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/patch.py", line 38, in proxy
aws-stack_1       |     return new(target, *args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/localstack_ext/services/edge.py.enc", line 71, in E
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 225, in do_forward_request
aws-stack_1       |     result = do_forward_request_inmem(api, method, path, data, headers, port=port)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 249, in do_forward_request_inmem
aws-stack_1       |     response = modify_and_forward(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 534, in wrapper
aws-stack_1       |     value = func(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 614, in modify_and_forward
aws-stack_1       |     listener_result = listener.forward_request(
aws-stack_1       |   File "/opt/code/localstack/localstack/http/adapters.py", line 51, in forward_request
aws-stack_1       |     response = self.request(request)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/proxy.py", line 43, in request
aws-stack_1       |     return self.skeleton.invoke(context)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 153, in invoke
aws-stack_1       |     return self.dispatch_request(context, instance)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 165, in dispatch_request
aws-stack_1       |     result = handler(context, instance) or {}
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/forwarder.py", line 57, in _call
aws-stack_1       |     return handler(context, req)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 117, in __call__
aws-stack_1       |     return self.fn(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/kms/provider.py", line 451, in import_key_material
aws-stack_1       |     key_material = import_state.key_obj.decrypt(encrypted_key_material, padding.PKCS1v15())
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 424, in decrypt
aws-stack_1       |     return _enc_dec_rsa(self._backend, self, ciphertext, padding)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 98, in _enc_dec_rsa
aws-stack_1       |     return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 164, in _enc_dec_rsa_pkey_ctx
aws-stack_1       |     raise ValueError("Encryption/decryption failed.")
aws-stack_1       | ValueError: Encryption/decryption failed.
aws-stack_1       | 
aws-stack_1       | 2022-07-06T12:58:38.109:WARNING:localstack.utils.server.http2_server: Error in proxy handler for request POST http://localhost:4566/: Encryption/decryption failed. Traceback (most recent call last):
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/server/http2_server.py", line 185, in index
aws-stack_1       |     result = await run_sync(handler, request, data)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/asyncio.py", line 85, in run_sync
aws-stack_1       |     return await loop.run_in_executor(thread_pool, copy_context().run, func_wrapped)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/threads.py", line 39, in run
aws-stack_1       |     result = self.func(self.params, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/asyncio.py", line 30, in _run
aws-stack_1       |     return fn(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 993, in handler
aws-stack_1       |     return modify_and_forward(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 534, in wrapper
aws-stack_1       |     value = func(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 614, in modify_and_forward
aws-stack_1       |     listener_result = listener.forward_request(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 170, in forward_request
aws-stack_1       |     result = do_forward_request(api, method, path, data, headers, port=port)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/patch.py", line 38, in proxy
aws-stack_1       |     return new(target, *args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/localstack_ext/services/edge.py.enc", line 71, in E
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 225, in do_forward_request
aws-stack_1       |     result = do_forward_request_inmem(api, method, path, data, headers, port=port)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 249, in do_forward_request_inmem
aws-stack_1       |     response = modify_and_forward(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 534, in wrapper
aws-stack_1       |     value = func(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 614, in modify_and_forward
aws-stack_1       |     listener_result = listener.forward_request(
aws-stack_1       |   File "/opt/code/localstack/localstack/http/adapters.py", line 51, in forward_request
aws-stack_1       |     response = self.request(request)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/proxy.py", line 43, in request
aws-stack_1       |     return self.skeleton.invoke(context)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 153, in invoke
aws-stack_1       |     return self.dispatch_request(context, instance)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 165, in dispatch_request
aws-stack_1       |     result = handler(context, instance) or {}
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/forwarder.py", line 57, in _call
aws-stack_1       |     return handler(context, req)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 117, in __call__
aws-stack_1       |     return self.fn(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/kms/provider.py", line 451, in import_key_material
aws-stack_1       |     key_material = import_state.key_obj.decrypt(encrypted_key_material, padding.PKCS1v15())
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 424, in decrypt
aws-stack_1       |     return _enc_dec_rsa(self._backend, self, ciphertext, padding)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 98, in _enc_dec_rsa
aws-stack_1       |     return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 164, in _enc_dec_rsa_pkey_ctx
aws-stack_1       |     raise ValueError("Encryption/decryption failed.")
aws-stack_1       | ValueError: Encryption/decryption failed.
aws-stack_1       | 
aws-stack_1       | 2022-07-06T12:58:39.359:WARNING:localstack.utils.server.http2_server: Error in proxy handler for request POST http://localhost:4566/: Encryption/decryption failed. Traceback (most recent call last):
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/server/http2_server.py", line 185, in index
aws-stack_1       |     result = await run_sync(handler, request, data)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/asyncio.py", line 85, in run_sync
aws-stack_1       |     return await loop.run_in_executor(thread_pool, copy_context().run, func_wrapped)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/threads.py", line 39, in run
aws-stack_1       |     result = self.func(self.params, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/asyncio.py", line 30, in _run
aws-stack_1       |     return fn(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 993, in handler
aws-stack_1       |     return modify_and_forward(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 534, in wrapper
aws-stack_1       |     value = func(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 614, in modify_and_forward
aws-stack_1       |     listener_result = listener.forward_request(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 170, in forward_request
aws-stack_1       |     result = do_forward_request(api, method, path, data, headers, port=port)
aws-stack_1       |   File "/opt/code/localstack/localstack/utils/patch.py", line 38, in proxy
aws-stack_1       |     return new(target, *args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/localstack_ext/services/edge.py.enc", line 71, in E
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 225, in do_forward_request
aws-stack_1       |     result = do_forward_request_inmem(api, method, path, data, headers, port=port)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/edge.py", line 249, in do_forward_request_inmem
aws-stack_1       |     response = modify_and_forward(
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 534, in wrapper
aws-stack_1       |     value = func(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 614, in modify_and_forward
aws-stack_1       |     listener_result = listener.forward_request(
aws-stack_1       |   File "/opt/code/localstack/localstack/http/adapters.py", line 51, in forward_request
aws-stack_1       |     response = self.request(request)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/proxy.py", line 43, in request
aws-stack_1       |     return self.skeleton.invoke(context)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 153, in invoke
aws-stack_1       |     return self.dispatch_request(context, instance)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 165, in dispatch_request
aws-stack_1       |     result = handler(context, instance) or {}
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/forwarder.py", line 57, in _call
aws-stack_1       |     return handler(context, req)
aws-stack_1       |   File "/opt/code/localstack/localstack/aws/skeleton.py", line 117, in __call__
aws-stack_1       |     return self.fn(*args, **kwargs)
aws-stack_1       |   File "/opt/code/localstack/localstack/services/kms/provider.py", line 451, in import_key_material
aws-stack_1       |     key_material = import_state.key_obj.decrypt(encrypted_key_material, padding.PKCS1v15())
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 424, in decrypt
aws-stack_1       |     return _enc_dec_rsa(self._backend, self, ciphertext, padding)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 98, in _enc_dec_rsa
aws-stack_1       |     return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding)
aws-stack_1       |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/cryptography/hazmat/backends/openssl/rsa.py", line 164, in _enc_dec_rsa_pkey_ctx
aws-stack_1       |     raise ValueError("Encryption/decryption failed.")
aws-stack_1       | ValueError: Encryption/decryption faile
```


Discussion:
Welcome to LocalStack! Thanks for reporting your first issue and our team will be working towards fixing the issue for you or reach out for more background information. We recommend joining our [Slack Community](https://localstack.cloud/contact/) for real-time help and drop a message to LocalStack Pro Support if you are a Pro user! If you are willing to contribute towards fixing this issue, please have a look at our [contributing guidelines](https://github.com/localstack/.github/blob/main/CONTRIBUTING.md) and our [developer guide](https://docs.localstack.cloud/developer-guide/).

Resolving patch:
diff --git a/localstack/services/kms/provider.py b/localstack/services/kms/provider.py
--- a/localstack/services/kms/provider.py
+++ b/localstack/services/kms/provider.py
@@ -38,6 +38,7 @@
     InvalidGrantTokenException,
     KeyIdType,
     KmsApi,
+    KMSInvalidStateException,
     LimitType,
     ListAliasesResponse,
     ListGrantsRequest,
@@ -448,7 +449,19 @@ def import_key_material(
         key_obj = kms_backends[context.region].keys.get(key_id)
         if not key_obj:
             raise NotFoundException(f"Unable to find key '{key_id}'")
-        key_material = import_state.key_obj.decrypt(encrypted_key_material, padding.PKCS1v15())
+
+        if import_state.wrapping_algo == AlgorithmSpec.RSAES_PKCS1_V1_5:
+            decrypt_padding = padding.PKCS1v15()
+        elif import_state.wrapping_algo == AlgorithmSpec.RSAES_OAEP_SHA_1:
+            decrypt_padding = padding.OAEP(padding.MGF1(hashes.SHA1()), hashes.SHA1(), None)
+        elif import_state.wrapping_algo == AlgorithmSpec.RSAES_OAEP_SHA_256:
+            decrypt_padding = padding.OAEP(padding.MGF1(hashes.SHA256()), hashes.SHA256(), None)
+        else:
+            raise KMSInvalidStateException(
+                f"Unsupported padding, requested wrapping algorithm:'{import_state.wrapping_algo}'"
+            )
+
+        key_material = import_state.key_obj.decrypt(encrypted_key_material, decrypt_padding)
         key_obj.key_material = key_material
         return ImportKeyMaterialResponse()
 


Test patch: