Skip to content

Translate CompletionException to GeneralSecurityException in AwsKmsAead - #7

Open
stevenwarejones wants to merge 3 commits into
tink-crypto:mainfrom
stevenwarejones:fix-completion-exception-leak
Open

Translate CompletionException to GeneralSecurityException in AwsKmsAead#7
stevenwarejones wants to merge 3 commits into
tink-crypto:mainfrom
stevenwarejones:fix-completion-exception-leak

Conversation

@stevenwarejones

@stevenwarejones stevenwarejones commented Aug 20, 2026

Copy link
Copy Markdown

Fixes #5.

AwsKmsAead.encrypt/decrypt only catch SdkClientException | KmsException, but the AWS SDK's internal synchronous credential resolution (AwsCredentialsAuthorizationStrategy.resolveCredentials -> identityProvider.resolveIdentity() -> CompletableFutureUtils.joinLikeSync) leaves a failed future's CompletionException wrapped -- rather than unwrapping it to the cause -- whenever that cause is not itself a RuntimeException. A credentials provider that legitimately fails credential resolution with a checked exception (e.g. a failed STS call wrapped as GeneralSecurityException) therefore surfaces as a raw CompletionException out of encrypt/decrypt instead of preserving the declared checked-failure path (GeneralSecurityException) these methods otherwise honor.

This adds a catch (CompletionException e) to both methods that translates a checked-exception cause into a new GeneralSecurityException, consistent with the existing SdkClientException/KmsException handling. A null, RuntimeException, or Error cause means this isn't that shape, so the CompletionException itself is rethrown unchanged rather than being unwrapped or otherwise guessed at.

Added regression tests covering both methods: a checked cause (GeneralSecurityException, and separately IOException to confirm this isn't specific to one checked type) is translated; a RuntimeException cause, an Error cause, and a causeless CompletionException all propagate unchanged. Verified each new case fails without this change and passes with it.

Downstream impact: common-jvm#399 wraps this library's client in CompletionExceptionTranslatingKmsClient, whose only job is to translate this specific CompletionException leak. A release containing this fix will let that wrapper be deleted entirely.

AwsKmsAead.encrypt/decrypt only catch SdkClientException and KmsException,
but the AWS SDK's internal synchronous credential resolution
(AwsCredentialsAuthorizationStrategy -> CompletableFutureUtils.joinLikeSync)
leaves a failed future's CompletionException wrapped, rather than unwrapping
it, whenever its cause is not itself a RuntimeException -- which is exactly
what happens when a credentials provider fails with a checked exception.
That CompletionException then escapes encrypt/decrypt uncaught, breaking the
Aead contract that only GeneralSecurityException is thrown.

Fixes tink-crypto#5
@stevenwarejones
stevenwarejones force-pushed the fix-completion-exception-leak branch from 6cc7987 to bc303e3 Compare August 20, 2026 15:10
@stevenwarejones

Copy link
Copy Markdown
Author

@juergw @morambro -- would appreciate a look when you have a chance. Related to #5, with a downstream project (common-jvm) hitting this in practice.

Only wrap a CompletionException in GeneralSecurityException when its
cause is a checked exception -- the one specific shape AWS SDK v2s
internal synchronous credential resolution can leave wrapped
(AwsCredentialsAuthorizationStrategy -> CompletableFutureUtils.joinLikeSync
only unwraps RuntimeException causes). A null, RuntimeException, or Error
cause means this is not that shape, so the CompletionException itself is
rethrown unchanged instead of being unwrapped or otherwise guessed at.

Adds tests proving a checked cause is translated, and that
CompletionException wrapping a RuntimeException, an Error, or nothing
all propagate unchanged.
…anslated

The existing checked-cause test only used GeneralSecurityException.
Adds an IOException case to make explicit that any checked exception is
translated, not just GeneralSecurityException specifically.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AwsKmsAead can leak CompletionException instead of GeneralSecurityException

1 participant