Skip to content

Commit 53dc99d

Browse files
fix: throw S3EC error on GCM key/IV reuse (#513)
1 parent 2e04dab commit 53dc99d

4 files changed

Lines changed: 59 additions & 6 deletions

File tree

pom.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
<dependency>
5757
<groupId>software.amazon.awssdk</groupId>
5858
<artifactId>bom</artifactId>
59-
<version>2.31.14</version>
59+
<version>2.43.0</version>
6060
<optional>true</optional>
6161
<type>pom</type>
6262
<scope>import</scope>
@@ -68,21 +68,21 @@
6868
<dependency>
6969
<groupId>software.amazon.awssdk</groupId>
7070
<artifactId>s3</artifactId>
71-
<version>2.31.14</version>
71+
<version>2.43.0</version>
7272
</dependency>
7373

7474
<dependency>
7575
<groupId>software.amazon.awssdk</groupId>
7676
<artifactId>kms</artifactId>
77-
<version>2.31.14</version>
77+
<version>2.43.0</version>
7878
</dependency>
7979

8080
<!-- Used when enableMultipartPutObject is configured -->
8181
<dependency>
8282
<groupId>software.amazon.awssdk.crt</groupId>
8383
<artifactId>aws-crt</artifactId>
8484
<optional>true</optional>
85-
<version>0.37.0</version>
85+
<version>0.45.1</version>
8686
</dependency>
8787

8888
<dependency>
@@ -169,7 +169,7 @@
169169
<dependency>
170170
<groupId>software.amazon.awssdk</groupId>
171171
<artifactId>sts</artifactId>
172-
<version>2.31.14</version>
172+
<version>2.43.0</version>
173173
<optional>true</optional>
174174
<scope>test</scope>
175175
</dependency>

src/main/java/software/amazon/encryption/s3/internal/PutEncryptedObjectPipeline.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public CompletableFuture<PutObjectResponse> putObject(PutObjectRequest request,
8484
.overrideConfiguration(API_NAME_INTERCEPTOR)
8585
.contentLength(encryptedContent.getCiphertextLength())
8686
.build();
87-
return _s3AsyncClient.putObject(encryptedPutRequest, encryptedContent.getAsyncCiphertext());
87+
return _s3AsyncClient.putObject(encryptedPutRequest, new NoRetriesAsyncRequestBody(encryptedContent.getAsyncCiphertext()));
8888
}
8989

9090
public static class Builder {

src/test/java/software/amazon/encryption/s3/S3AsyncEncryptionClientTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,15 @@
4646
import software.amazon.awssdk.services.s3.multipart.MultipartConfiguration;
4747
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
4848
import software.amazon.encryption.s3.internal.InstructionFileConfig;
49+
import software.amazon.encryption.s3.materials.AesKeyring;
4950
import software.amazon.encryption.s3.materials.KmsKeyring;
5051
import software.amazon.encryption.s3.utils.BoundedInputStream;
5152
import software.amazon.encryption.s3.utils.S3EncryptionClientTestResources;
5253
import software.amazon.encryption.s3.utils.TinyBufferAsyncRequestBody;
5354

5455
import javax.crypto.KeyGenerator;
5556
import javax.crypto.SecretKey;
57+
import javax.crypto.spec.SecretKeySpec;
5658
import java.io.IOException;
5759
import java.io.InputStream;
5860
import java.security.NoSuchAlgorithmException;
@@ -349,6 +351,31 @@ public void asyncTopLevelConfigurationWrongRegion() {
349351
}
350352
}
351353

354+
@RetryingTest(3)
355+
public void roundTripWithCrossRegionAccessEnabled() {
356+
final String objectKey = appendTestSuffix("roundTripWithCrossRegionAccessEnabled-async-s3ec");
357+
SecretKeySpec aesKey = new SecretKeySpec(new byte[32], "AES");
358+
AesKeyring keyRing = AesKeyring.builder().wrappingKey(aesKey).build();
359+
360+
S3AsyncClient s3Client = S3AsyncEncryptionClient.builderV4()
361+
.region(Region.EU_CENTRAL_1)
362+
.crossRegionAccessEnabled(true)
363+
.keyring(keyRing)
364+
.build();
365+
366+
try {
367+
PutObjectRequest request = PutObjectRequest.builder().bucket(BUCKET).key(objectKey).build();
368+
CompletionException ex = assertThrows(CompletionException.class, () ->
369+
s3Client.putObject(request, AsyncRequestBody.fromBytes("test".getBytes())).join());
370+
// Cross-region redirect causes the SDK to re-subscribe to the request body.
371+
// NoRetriesAsyncRequestBody blocks this to prevent GCM cipher key/IV reuse.
372+
assertTrue(ex.getCause() instanceof S3EncryptionClientException);
373+
assertTrue(ex.getCause().getMessage().contains("Re-subscription is not supported"));
374+
} finally {
375+
s3Client.close();
376+
}
377+
}
378+
352379
@RetryingTest(3)
353380
public void asyncTopLevelConfigurationNullCreds() {
354381
final String objectKey = appendTestSuffix("wrapped-s3-client-with-null-credentials-async");

src/test/java/software/amazon/encryption/s3/S3EncryptionClientTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
4343
import software.amazon.encryption.s3.internal.InstructionFileConfig;
4444
import software.amazon.encryption.s3.internal.MetadataKeyConstants;
45+
import software.amazon.encryption.s3.materials.AesKeyring;
4546
import software.amazon.encryption.s3.materials.CryptographicMaterialsManager;
4647
import software.amazon.encryption.s3.materials.DefaultCryptoMaterialsManager;
4748
import software.amazon.encryption.s3.materials.KmsKeyring;
@@ -52,6 +53,7 @@
5253

5354
import javax.crypto.KeyGenerator;
5455
import javax.crypto.SecretKey;
56+
import javax.crypto.spec.SecretKeySpec;
5557
import java.security.KeyPair;
5658
import java.security.KeyPairGenerator;
5759
import java.security.NoSuchAlgorithmException;
@@ -964,6 +966,30 @@ public void s3EncryptionClientTopLevelCredentialsWrongRegion() {
964966
}
965967
}
966968

969+
@RetryingTest(3)
970+
public void roundTripWithCrossRegionAccessEnabled() {
971+
final String objectKey = appendTestSuffix("roundTripWithCrossRegionAccessEnabled-sync-s3ec");
972+
SecretKeySpec aesKey = new SecretKeySpec(new byte[32], "AES");
973+
AesKeyring keyRing = AesKeyring.builder().wrappingKey(aesKey).build();
974+
975+
S3Client s3 = S3EncryptionClient.builderV4()
976+
.region(Region.EU_CENTRAL_1)
977+
.crossRegionAccessEnabled(true)
978+
.keyring(keyRing)
979+
.build();
980+
981+
try {
982+
PutObjectRequest request = PutObjectRequest.builder().bucket(BUCKET).key(objectKey).build();
983+
S3EncryptionClientException ex = assertThrows(S3EncryptionClientException.class, () ->
984+
s3.putObject(request, RequestBody.fromBytes("test".getBytes())));
985+
// Cross-region redirect causes the SDK to re-subscribe to the request body.
986+
// S3EC blocks this to prevent GCM cipher key/IV reuse.
987+
assertTrue(ex.getCause().getMessage().contains("Re-subscription is not supported"));
988+
} finally {
989+
s3.close();
990+
}
991+
}
992+
967993
@RetryingTest(3)
968994
public void s3EncryptionClientTopLevelCredentialsNullCreds() {
969995
final String objectKey = appendTestSuffix("wrapped-s3-client-with-null-credentials");

0 commit comments

Comments
 (0)