diff --git a/pom.xml b/pom.xml index de793bbb9..98159fd1d 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ software.amazon.awssdk bom - 2.31.14 + 2.43.0 true pom import @@ -68,13 +68,13 @@ software.amazon.awssdk s3 - 2.31.14 + 2.43.0 software.amazon.awssdk kms - 2.31.14 + 2.43.0 @@ -82,7 +82,7 @@ software.amazon.awssdk.crt aws-crt true - 0.37.0 + 0.45.1 @@ -169,7 +169,7 @@ software.amazon.awssdk sts - 2.31.14 + 2.43.0 true test diff --git a/src/main/java/software/amazon/encryption/s3/internal/PutEncryptedObjectPipeline.java b/src/main/java/software/amazon/encryption/s3/internal/PutEncryptedObjectPipeline.java index fb2ddbae3..96be243d3 100644 --- a/src/main/java/software/amazon/encryption/s3/internal/PutEncryptedObjectPipeline.java +++ b/src/main/java/software/amazon/encryption/s3/internal/PutEncryptedObjectPipeline.java @@ -84,7 +84,7 @@ public CompletableFuture putObject(PutObjectRequest request, .overrideConfiguration(API_NAME_INTERCEPTOR) .contentLength(encryptedContent.getCiphertextLength()) .build(); - return _s3AsyncClient.putObject(encryptedPutRequest, encryptedContent.getAsyncCiphertext()); + return _s3AsyncClient.putObject(encryptedPutRequest, new NoRetriesAsyncRequestBody(encryptedContent.getAsyncCiphertext())); } public static class Builder { diff --git a/src/test/java/software/amazon/encryption/s3/S3AsyncEncryptionClientTest.java b/src/test/java/software/amazon/encryption/s3/S3AsyncEncryptionClientTest.java index 4a9aa9483..141e3f5ca 100644 --- a/src/test/java/software/amazon/encryption/s3/S3AsyncEncryptionClientTest.java +++ b/src/test/java/software/amazon/encryption/s3/S3AsyncEncryptionClientTest.java @@ -46,6 +46,7 @@ import software.amazon.awssdk.services.s3.multipart.MultipartConfiguration; import software.amazon.encryption.s3.algorithms.AlgorithmSuite; import software.amazon.encryption.s3.internal.InstructionFileConfig; +import software.amazon.encryption.s3.materials.AesKeyring; import software.amazon.encryption.s3.materials.KmsKeyring; import software.amazon.encryption.s3.utils.BoundedInputStream; import software.amazon.encryption.s3.utils.S3EncryptionClientTestResources; @@ -53,6 +54,7 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchAlgorithmException; @@ -349,6 +351,31 @@ public void asyncTopLevelConfigurationWrongRegion() { } } + @RetryingTest(3) + public void roundTripWithCrossRegionAccessEnabled() { + final String objectKey = appendTestSuffix("roundTripWithCrossRegionAccessEnabled-async-s3ec"); + SecretKeySpec aesKey = new SecretKeySpec(new byte[32], "AES"); + AesKeyring keyRing = AesKeyring.builder().wrappingKey(aesKey).build(); + + S3AsyncClient s3Client = S3AsyncEncryptionClient.builderV4() + .region(Region.EU_CENTRAL_1) + .crossRegionAccessEnabled(true) + .keyring(keyRing) + .build(); + + try { + PutObjectRequest request = PutObjectRequest.builder().bucket(BUCKET).key(objectKey).build(); + CompletionException ex = assertThrows(CompletionException.class, () -> + s3Client.putObject(request, AsyncRequestBody.fromBytes("test".getBytes())).join()); + // Cross-region redirect causes the SDK to re-subscribe to the request body. + // NoRetriesAsyncRequestBody blocks this to prevent GCM cipher key/IV reuse. + assertTrue(ex.getCause() instanceof S3EncryptionClientException); + assertTrue(ex.getCause().getMessage().contains("Re-subscription is not supported")); + } finally { + s3Client.close(); + } + } + @RetryingTest(3) public void asyncTopLevelConfigurationNullCreds() { final String objectKey = appendTestSuffix("wrapped-s3-client-with-null-credentials-async"); diff --git a/src/test/java/software/amazon/encryption/s3/S3EncryptionClientTest.java b/src/test/java/software/amazon/encryption/s3/S3EncryptionClientTest.java index ea46b7e1d..356ddbdff 100644 --- a/src/test/java/software/amazon/encryption/s3/S3EncryptionClientTest.java +++ b/src/test/java/software/amazon/encryption/s3/S3EncryptionClientTest.java @@ -42,6 +42,7 @@ import software.amazon.encryption.s3.algorithms.AlgorithmSuite; import software.amazon.encryption.s3.internal.InstructionFileConfig; import software.amazon.encryption.s3.internal.MetadataKeyConstants; +import software.amazon.encryption.s3.materials.AesKeyring; import software.amazon.encryption.s3.materials.CryptographicMaterialsManager; import software.amazon.encryption.s3.materials.DefaultCryptoMaterialsManager; import software.amazon.encryption.s3.materials.KmsKeyring; @@ -52,6 +53,7 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; @@ -964,6 +966,30 @@ public void s3EncryptionClientTopLevelCredentialsWrongRegion() { } } + @RetryingTest(3) + public void roundTripWithCrossRegionAccessEnabled() { + final String objectKey = appendTestSuffix("roundTripWithCrossRegionAccessEnabled-sync-s3ec"); + SecretKeySpec aesKey = new SecretKeySpec(new byte[32], "AES"); + AesKeyring keyRing = AesKeyring.builder().wrappingKey(aesKey).build(); + + S3Client s3 = S3EncryptionClient.builderV4() + .region(Region.EU_CENTRAL_1) + .crossRegionAccessEnabled(true) + .keyring(keyRing) + .build(); + + try { + PutObjectRequest request = PutObjectRequest.builder().bucket(BUCKET).key(objectKey).build(); + S3EncryptionClientException ex = assertThrows(S3EncryptionClientException.class, () -> + s3.putObject(request, RequestBody.fromBytes("test".getBytes()))); + // Cross-region redirect causes the SDK to re-subscribe to the request body. + // S3EC blocks this to prevent GCM cipher key/IV reuse. + assertTrue(ex.getCause().getMessage().contains("Re-subscription is not supported")); + } finally { + s3.close(); + } + } + @RetryingTest(3) public void s3EncryptionClientTopLevelCredentialsNullCreds() { final String objectKey = appendTestSuffix("wrapped-s3-client-with-null-credentials");