From 25ec63df3868a204d2e6e57780a7ed262bd79400 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Fri, 12 Dec 2025 10:42:55 -0800 Subject: [PATCH 1/5] chore: add instruction file manipulation test --- .../encryption/s3/InstructionFileFailures.java | 12 +++++------- test-server/php-v3-server/local-php-sdk | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java index 0096a8bf..4b2b9606 100644 --- a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java +++ b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java @@ -5,9 +5,11 @@ package software.amazon.encryption.s3; +import static org.junit.jupiter.api.Assertions.assertEquals; import static software.amazon.encryption.s3.TestUtils.*; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.util.ArrayList; @@ -21,6 +23,7 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -32,6 +35,7 @@ import org.opentest4j.TestAbortedException; import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectResponse; @@ -39,13 +43,7 @@ import software.amazon.encryption.s3.TestUtils.LanguageServerTarget; import software.amazon.encryption.s3.client.S3ECTestServerClient; -import software.amazon.encryption.s3.model.CommitmentPolicy; -import software.amazon.encryption.s3.model.CreateClientInput; -import software.amazon.encryption.s3.model.CreateClientOutput; -import software.amazon.encryption.s3.model.EncryptionAlgorithm; -import software.amazon.encryption.s3.model.InstructionFileConfig; -import software.amazon.encryption.s3.model.KeyMaterial; -import software.amazon.encryption.s3.model.S3ECConfig; +import software.amazon.encryption.s3.model.*; /** * Instruction File Failures Test Suite diff --git a/test-server/php-v3-server/local-php-sdk b/test-server/php-v3-server/local-php-sdk index 3acb3ad4..d0225ba1 160000 --- a/test-server/php-v3-server/local-php-sdk +++ b/test-server/php-v3-server/local-php-sdk @@ -1 +1 @@ -Subproject commit 3acb3ad4d98debcfc2148290cd6fcea83962fe08 +Subproject commit d0225ba1f566474b1f872ec747276a22350afd65 From 5281701e51ba4cdc44d5372d33f71b90a0170b51 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Fri, 12 Dec 2025 15:07:16 -0800 Subject: [PATCH 2/5] ok, try thi --- .../s3/InstructionFileFailures.java | 250 +++++++++++++++++- 1 file changed, 241 insertions(+), 9 deletions(-) diff --git a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java index 4b2b9606..ba5d06a1 100644 --- a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java +++ b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java @@ -9,13 +9,9 @@ import static software.amazon.encryption.s3.TestUtils.*; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -23,19 +19,15 @@ import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.opentest4j.TestAbortedException; import software.amazon.awssdk.core.ResponseBytes; -import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectResponse; @@ -64,6 +56,8 @@ public class InstructionFileFailures { private static final String SUFFIX_GOOD_COPY = "-good-copy"; private static final String SUFFIX_BAD_BOTH_META_AND_INSTRUCTION = "-bad-both-meta-and-instruction"; private static final String SUFFIX_BAD_ONLY_INSTRUCTION = "-bad-only-instruction"; + private static final String SUFFIX_BAD_JSON_INSTRUCTION = "-manipulated-bad-json-instruction"; + private static final String SUFFIX_MANIPULATED_INSTRUCTION = "-manipuldate-incorrect-key-instruction"; /** * Encryption Tests - Encrypt Phase @@ -93,6 +87,10 @@ class EncryptTests { Collections.synchronizedList(new ArrayList<>()); private static final List crossLanguageObjectsInstructionFileDeleted = Collections.synchronizedList(new ArrayList<>()); + private static final List crossLanguageObjectsV3InstructionFileManipulated = + Collections.synchronizedList(new ArrayList<>()); + private static final List crossLanguageObjectsV2InstructionFileManipulated = + Collections.synchronizedList(new ArrayList<>()); private static KeyMaterial RSA_KEY; private static KeyMaterial AES_KEY; @@ -151,6 +149,15 @@ static List getCrossLanguageObjectsInstructionFileDeleted() { return new ArrayList<>(crossLanguageObjectsInstructionFileDeleted); } + static List getCrossLanguageObjectsInstructionFileManipulatedV3() { + return new ArrayList<>(crossLanguageObjectsV3InstructionFileManipulated); + } + + static List getCrossLanguageObjectsInstructionFileManipulatedV2() { + return new ArrayList<>(crossLanguageObjectsV2InstructionFileManipulated); + } + + public static Stream improvedClientsCanPutKMSWithInstructionFile() { return improvedClientsForTest() .filter(target -> !INSTRUCTION_FILE_PUT_UNSUPPORTED.contains(((LanguageServerTarget) target.get()[0]).getLanguageName())) @@ -295,6 +302,60 @@ void encryptWithInstructionFileForDeletionRsaKcGcm(TestUtils.LanguageServerTarge ); } + @ParameterizedTest(name = "{0}: Encrypt KMS KC-GCM (V3) with instruction file for manipulation test") + @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$EncryptTests#improvedClientsCanPutKMSWithInstructionFile") + void encryptWithInstructionFileV3ForManipulationKmsKcGcm(TestUtils.LanguageServerTarget language) { + S3ECTestServerClient client = TestUtils.testServerClientFor(language); + // Encrypt with instruction file, will be manipulated later on. + CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() + .config(S3ECConfig.builder() + .keyMaterial(kmsKeyArn) + .instructionFileConfig( + InstructionFileConfig.builder() + .enableInstructionFilePutObject(true) + .build() + ) + .build()) + .build()); + String S3ECId = clientOutput.getClientId(); + + TestUtils.Encrypt( + client, + S3ECId, + appendTestSuffix(sharedObjectKeyBaseMetaDataMode + "-envelope-manipulation-instruction-" + language.getLanguageName()), + crossLanguageObjectsV3InstructionFileManipulated, + EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY + ); + } + + @ParameterizedTest(name = "{0}: Encrypt KMS (V2) with instruction file for manipulation test") + @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$EncryptTests#improvedClientsCanPutKMSWithInstructionFile") + void encryptWithInstructionFileV2ForManipulationKms(TestUtils.LanguageServerTarget language) { + S3ECTestServerClient client = TestUtils.testServerClientFor(language); + // Encrypt with instruction file, will be manipulated later on. + CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() + .config(S3ECConfig.builder() + .keyMaterial(kmsKeyArn) + .commitmentPolicy(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT) + .instructionFileConfig( + InstructionFileConfig.builder() + .enableInstructionFilePutObject(true) + .build() + ) + .build()) + .build()); + String S3ECId = clientOutput.getClientId(); + + TestUtils.Encrypt( + client, + S3ECId, + appendTestSuffix(sharedObjectKeyBaseMetaDataMode + "-envelope-manipulation-instruction-" + language.getLanguageName()), + crossLanguageObjectsV2InstructionFileManipulated, + EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF + ); + } + + static void makeCopiesToVerifyThings() throws Exception { // Create a plaintext S3 client to copy objects with instruction files try (S3Client ptS3Client = S3Client.create()) { @@ -369,6 +430,101 @@ static void makeCopiesToVerifyThings() throws Exception { // Ignore if file doesn't exist } } + + // manipulate V3 instruction files + for (String objectKey: crossLanguageObjectsV3InstructionFileManipulated) { + // Get the encrypted object + ResponseBytes encryptedObject = ptS3Client.getObjectAsBytes(builder -> builder + .bucket(TestUtils.BUCKET) + .key(objectKey) + .build()); + + // Get the instruction file + String instructionFileKey = objectKey + ".instruction"; + ResponseBytes instructionFile = ptS3Client.getObjectAsBytes(builder -> builder + .bucket(TestUtils.BUCKET) + .key(instructionFileKey) + .build()); + + String instructionFileJson = instructionFile.asUtf8String(); + Map objectMetadata = encryptedObject.response().metadata(); + + ObjectMapper mapper = new ObjectMapper(); + Map instructionFileMap = mapper.readValue(instructionFileJson, Map.class); + + instructionFileMap.put("x-amz-c-v2", objectMetadata.get("x-amz-c")); + instructionFileMap.remove("x-amz-c"); + + Map invalidInstructionFileMap = new HashMap<>(); + invalidInstructionFileMap.put("invalid", "json"); + + String invalidInstructionFile = mapper.writeValueAsString(invalidInstructionFileMap); + String badKeyInstructionFile = mapper.writeValueAsString(instructionFileMap); + + // Put instruction files that should fail: + putObjectWithInstructionFile( + ptS3Client, + objectKey + SUFFIX_BAD_JSON_INSTRUCTION + "-v3", + encryptedObject.asByteArray(), + objectMetadata, + invalidInstructionFile + ); + + putObjectWithInstructionFile( + ptS3Client, + objectKey + SUFFIX_MANIPULATED_INSTRUCTION + "-v3", + encryptedObject.asByteArray(), + objectMetadata, + badKeyInstructionFile + ); + } + + // manipulate V2 instruction files + for (String objectKey: crossLanguageObjectsV2InstructionFileManipulated) { + // Get the encrypted object + ResponseBytes encryptedObject = ptS3Client.getObjectAsBytes(builder -> builder + .bucket(TestUtils.BUCKET) + .key(objectKey) + .build()); + + // Get the instruction file + String instructionFileKey = objectKey + ".instruction"; + ResponseBytes instructionFile = ptS3Client.getObjectAsBytes(builder -> builder + .bucket(TestUtils.BUCKET) + .key(instructionFileKey) + .build()); + + String instructionFileJson = instructionFile.asUtf8String(); + Map objectMetadata = encryptedObject.response().metadata(); + + ObjectMapper mapper = new ObjectMapper(); + Map instructionFileMap = mapper.readValue(instructionFileJson, Map.class); + + instructionFileMap.replace("x-amz-key-v2", "x-amz-key-v2-tampered"); + + Map invalidInstructionFileMap = new HashMap<>(); + invalidInstructionFileMap.put("invalid", "json"); + + String invalidInstructionFile = mapper.writeValueAsString(invalidInstructionFileMap); + String badKeyInstructionFile = mapper.writeValueAsString(instructionFileMap); + + // Put instruction files that should fail: + putObjectWithInstructionFile( + ptS3Client, + objectKey + SUFFIX_BAD_JSON_INSTRUCTION + "-v2", + encryptedObject.asByteArray(), + objectMetadata, + invalidInstructionFile + ); + + putObjectWithInstructionFile( + ptS3Client, + objectKey + SUFFIX_MANIPULATED_INSTRUCTION + "-v2", + encryptedObject.asByteArray(), + objectMetadata, + badKeyInstructionFile + ); + } } } @@ -420,6 +576,8 @@ class DecryptTests { private static List crossLanguageObjectsAes; private static List crossLanguageObjectsMetadataOnly; private static List crossLanguageObjectsInstructionFileDeleted; + private static List crossLanguageObjectsInstructionFileManipulatedV3; + private static List crossLanguageObjectsInstructionFileManipulatedV2; private static KeyMaterial kmsKeyArn; private static KeyMaterial RSA_KEY; private static KeyMaterial AES_KEY; @@ -435,6 +593,8 @@ static void setup() throws InterruptedException { crossLanguageObjectsAes = EncryptTests.getCrossLanguageObjectsAes(); crossLanguageObjectsMetadataOnly = EncryptTests.getCrossLanguageObjectsMetadataOnly(); crossLanguageObjectsInstructionFileDeleted = EncryptTests.getCrossLanguageObjectsInstructionFileDeleted(); + crossLanguageObjectsInstructionFileManipulatedV3 = EncryptTests.getCrossLanguageObjectsInstructionFileManipulatedV3(); + crossLanguageObjectsInstructionFileManipulatedV2 = EncryptTests.getCrossLanguageObjectsInstructionFileManipulatedV2(); kmsKeyArn = EncryptTests.getKmsKeyArn(); RSA_KEY = EncryptTests.getRsaKey(); AES_KEY = EncryptTests.getAesKey(); @@ -943,5 +1103,77 @@ void decryptWithInstructionFileConfigWhenFileDeletedFails(TestUtils.LanguageServ EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY ); } + + @ParameterizedTest(name = "{0}: Fail to decrypt with manipulated V3 Instruction File") + @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$DecryptTests#clientsCanGetKMSWithInstructionFile") + void decryptWithManipulatedInstructionFileV3ImprovedClients(TestUtils.LanguageServerTarget language) { + if (crossLanguageObjectsInstructionFileManipulatedV3.isEmpty()) return; + + S3ECTestServerClient client = TestUtils.testServerClientFor(language); + CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() + .config(S3ECConfig.builder() + .keyMaterial(kmsKeyArn) + .commitmentPolicy(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT) + .encryptionAlgorithm(EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY) + .build()) + .build()); + String S3ECId = clientOutput.getClientId(); + + TestUtils.Decrypt_fails( + client, + S3ECId, + crossLanguageObjectsInstructionFileManipulatedV3 + .stream() + .map(key -> key + SUFFIX_BAD_JSON_INSTRUCTION + "-v3") + .collect(Collectors.toList()), + EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY + ); + + TestUtils.Decrypt_fails( + client, + S3ECId, + crossLanguageObjectsInstructionFileManipulatedV3 + .stream() + .map(key -> key + SUFFIX_MANIPULATED_INSTRUCTION + "-v3") + .collect(Collectors.toList()), + EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY + ); + } + + @ParameterizedTest(name = "{0}: Fail to decrypt with manipulated V2 Instruction File") + @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$DecryptTests#clientsCanGetKMSWithInstructionFile") + void decryptWithManipulatedInstructionFileV2ImprovedClients(TestUtils.LanguageServerTarget language) { + if (crossLanguageObjectsInstructionFileManipulatedV2.isEmpty()) return; + + S3ECTestServerClient client = TestUtils.testServerClientFor(language); + CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() + .config(S3ECConfig.builder() + .keyMaterial(kmsKeyArn) + .commitmentPolicy(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT) + .encryptionAlgorithm(EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF) + .build()) + .build()); + String S3ECId = clientOutput.getClientId(); + + TestUtils.Decrypt_fails( + client, + S3ECId, + crossLanguageObjectsInstructionFileManipulatedV2 + .stream() + .map(key -> key + SUFFIX_BAD_JSON_INSTRUCTION + "-v2") + .collect(Collectors.toList()), + EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF + ); + + TestUtils.Decrypt_fails( + client, + S3ECId, + crossLanguageObjectsInstructionFileManipulatedV3 + .stream() + .map(key -> key + SUFFIX_MANIPULATED_INSTRUCTION + "-v2") + .collect(Collectors.toList()), + EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF + ); + } } } From 0064b9e4d9ebdebe750d24422751d7f2b59466c1 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Fri, 12 Dec 2025 15:55:15 -0800 Subject: [PATCH 3/5] remove --- .../amazon/encryption/s3/InstructionFileFailures.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java index ba5d06a1..9b1e4a10 100644 --- a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java +++ b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java @@ -1107,8 +1107,6 @@ void decryptWithInstructionFileConfigWhenFileDeletedFails(TestUtils.LanguageServ @ParameterizedTest(name = "{0}: Fail to decrypt with manipulated V3 Instruction File") @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$DecryptTests#clientsCanGetKMSWithInstructionFile") void decryptWithManipulatedInstructionFileV3ImprovedClients(TestUtils.LanguageServerTarget language) { - if (crossLanguageObjectsInstructionFileManipulatedV3.isEmpty()) return; - S3ECTestServerClient client = TestUtils.testServerClientFor(language); CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() .config(S3ECConfig.builder() @@ -1143,8 +1141,6 @@ void decryptWithManipulatedInstructionFileV3ImprovedClients(TestUtils.LanguageSe @ParameterizedTest(name = "{0}: Fail to decrypt with manipulated V2 Instruction File") @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$DecryptTests#clientsCanGetKMSWithInstructionFile") void decryptWithManipulatedInstructionFileV2ImprovedClients(TestUtils.LanguageServerTarget language) { - if (crossLanguageObjectsInstructionFileManipulatedV2.isEmpty()) return; - S3ECTestServerClient client = TestUtils.testServerClientFor(language); CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() .config(S3ECConfig.builder() From 8f3c69260f60a6f60e37e53965d1188f25382201 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Fri, 12 Dec 2025 18:07:44 -0800 Subject: [PATCH 4/5] fix --- .../s3/InstructionFileFailures.java | 57 +++---------------- .../src/get_object.php | 2 + test-server/php-v3-server/local-php-sdk | 2 +- test-server/php-v3-server/src/get_object.php | 2 + 4 files changed, 14 insertions(+), 49 deletions(-) diff --git a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java index 9b1e4a10..18ebca47 100644 --- a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java +++ b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/InstructionFileFailures.java @@ -310,6 +310,7 @@ void encryptWithInstructionFileV3ForManipulationKmsKcGcm(TestUtils.LanguageServe CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() .config(S3ECConfig.builder() .keyMaterial(kmsKeyArn) + .commitmentPolicy(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT) .instructionFileConfig( InstructionFileConfig.builder() .enableInstructionFilePutObject(true) @@ -337,6 +338,7 @@ void encryptWithInstructionFileV2ForManipulationKms(TestUtils.LanguageServerTarg .config(S3ECConfig.builder() .keyMaterial(kmsKeyArn) .commitmentPolicy(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT) + .encryptionAlgorithm(EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF) .instructionFileConfig( InstructionFileConfig.builder() .enableInstructionFilePutObject(true) @@ -450,16 +452,11 @@ static void makeCopiesToVerifyThings() throws Exception { Map objectMetadata = encryptedObject.response().metadata(); ObjectMapper mapper = new ObjectMapper(); - Map instructionFileMap = mapper.readValue(instructionFileJson, Map.class); - - instructionFileMap.put("x-amz-c-v2", objectMetadata.get("x-amz-c")); - instructionFileMap.remove("x-amz-c"); Map invalidInstructionFileMap = new HashMap<>(); invalidInstructionFileMap.put("invalid", "json"); String invalidInstructionFile = mapper.writeValueAsString(invalidInstructionFileMap); - String badKeyInstructionFile = mapper.writeValueAsString(instructionFileMap); // Put instruction files that should fail: putObjectWithInstructionFile( @@ -469,14 +466,6 @@ static void makeCopiesToVerifyThings() throws Exception { objectMetadata, invalidInstructionFile ); - - putObjectWithInstructionFile( - ptS3Client, - objectKey + SUFFIX_MANIPULATED_INSTRUCTION + "-v3", - encryptedObject.asByteArray(), - objectMetadata, - badKeyInstructionFile - ); } // manipulate V2 instruction files @@ -500,23 +489,12 @@ static void makeCopiesToVerifyThings() throws Exception { ObjectMapper mapper = new ObjectMapper(); Map instructionFileMap = mapper.readValue(instructionFileJson, Map.class); - instructionFileMap.replace("x-amz-key-v2", "x-amz-key-v2-tampered"); + instructionFileMap.put("x-amz-key-v2-tampered", instructionFileMap.get("x-amz-key-v2")); + instructionFileMap.remove("x-amz-key-v2"); - Map invalidInstructionFileMap = new HashMap<>(); - invalidInstructionFileMap.put("invalid", "json"); - - String invalidInstructionFile = mapper.writeValueAsString(invalidInstructionFileMap); String badKeyInstructionFile = mapper.writeValueAsString(instructionFileMap); // Put instruction files that should fail: - putObjectWithInstructionFile( - ptS3Client, - objectKey + SUFFIX_BAD_JSON_INSTRUCTION + "-v2", - encryptedObject.asByteArray(), - objectMetadata, - invalidInstructionFile - ); - putObjectWithInstructionFile( ptS3Client, objectKey + SUFFIX_MANIPULATED_INSTRUCTION + "-v2", @@ -1107,12 +1085,15 @@ void decryptWithInstructionFileConfigWhenFileDeletedFails(TestUtils.LanguageServ @ParameterizedTest(name = "{0}: Fail to decrypt with manipulated V3 Instruction File") @MethodSource("software.amazon.encryption.s3.InstructionFileFailures$DecryptTests#clientsCanGetKMSWithInstructionFile") void decryptWithManipulatedInstructionFileV3ImprovedClients(TestUtils.LanguageServerTarget language) { + if (TRANSITION_VERSIONS.contains(language.getLanguageName())) { + return; + } + S3ECTestServerClient client = TestUtils.testServerClientFor(language); CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() .config(S3ECConfig.builder() .keyMaterial(kmsKeyArn) .commitmentPolicy(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT) - .encryptionAlgorithm(EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY) .build()) .build()); String S3ECId = clientOutput.getClientId(); @@ -1126,16 +1107,6 @@ void decryptWithManipulatedInstructionFileV3ImprovedClients(TestUtils.LanguageSe .collect(Collectors.toList()), EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY ); - - TestUtils.Decrypt_fails( - client, - S3ECId, - crossLanguageObjectsInstructionFileManipulatedV3 - .stream() - .map(key -> key + SUFFIX_MANIPULATED_INSTRUCTION + "-v3") - .collect(Collectors.toList()), - EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY - ); } @ParameterizedTest(name = "{0}: Fail to decrypt with manipulated V2 Instruction File") @@ -1145,7 +1116,7 @@ void decryptWithManipulatedInstructionFileV2ImprovedClients(TestUtils.LanguageSe CreateClientOutput clientOutput = client.createClient(CreateClientInput.builder() .config(S3ECConfig.builder() .keyMaterial(kmsKeyArn) - .commitmentPolicy(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT) + .commitmentPolicy(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT) .encryptionAlgorithm(EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF) .build()) .build()); @@ -1155,16 +1126,6 @@ void decryptWithManipulatedInstructionFileV2ImprovedClients(TestUtils.LanguageSe client, S3ECId, crossLanguageObjectsInstructionFileManipulatedV2 - .stream() - .map(key -> key + SUFFIX_BAD_JSON_INSTRUCTION + "-v2") - .collect(Collectors.toList()), - EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF - ); - - TestUtils.Decrypt_fails( - client, - S3ECId, - crossLanguageObjectsInstructionFileManipulatedV3 .stream() .map(key -> key + SUFFIX_MANIPULATED_INSTRUCTION + "-v2") .collect(Collectors.toList()), diff --git a/test-server/php-v2-transition-server/src/get_object.php b/test-server/php-v2-transition-server/src/get_object.php index 847fa9e3..656a337a 100644 --- a/test-server/php-v2-transition-server/src/get_object.php +++ b/test-server/php-v2-transition-server/src/get_object.php @@ -94,6 +94,8 @@ function handleGetObject($params) return S3EncryptionClientError($e->getMessage()); } elseif (strpos($e->getMessage(), "Expected a V3 envelope but was unable to constuct one.") !== false) { return S3EncryptionClientError($e->getMessage()); + } elseif (strpos($e->getMessage(), "Malformed metadata envelope.") !== false) { + return S3EncryptionClientError($e->getMessage()); } else { error_log("This is the error: " . $e->getMessage()); return GenericServerError("Server error: " . $e->getMessage(), 500); diff --git a/test-server/php-v3-server/local-php-sdk b/test-server/php-v3-server/local-php-sdk index d0225ba1..e8822dff 160000 --- a/test-server/php-v3-server/local-php-sdk +++ b/test-server/php-v3-server/local-php-sdk @@ -1 +1 @@ -Subproject commit d0225ba1f566474b1f872ec747276a22350afd65 +Subproject commit e8822dff8544f30dbd9ce36f6a57026882a185ec diff --git a/test-server/php-v3-server/src/get_object.php b/test-server/php-v3-server/src/get_object.php index 25a88a02..fbd42f7a 100644 --- a/test-server/php-v3-server/src/get_object.php +++ b/test-server/php-v3-server/src/get_object.php @@ -98,6 +98,8 @@ function handleGetObject($params) return S3EncryptionClientError($e->getMessage()); } elseif (strpos($e->getMessage(), "Expected a V3 envelope but was unable to constuct one.") !== false) { return S3EncryptionClientError($e->getMessage()); + } elseif (strpos($e->getMessage(), "Malformed metadata envelope.") !== false) { + return S3EncryptionClientError($e->getMessage()); } else { error_log("This is the error: " . $e->getMessage()); return GenericServerError("Server argument: " . $e->getMessage(), 500); From 16f28e4dda8396a6eff41d767e5d08b104e02afa Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Sun, 14 Dec 2025 12:06:05 -0800 Subject: [PATCH 5/5] newer sdk --- test-server/php-v3-server/local-php-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-server/php-v3-server/local-php-sdk b/test-server/php-v3-server/local-php-sdk index e8822dff..163fe386 160000 --- a/test-server/php-v3-server/local-php-sdk +++ b/test-server/php-v3-server/local-php-sdk @@ -1 +1 @@ -Subproject commit e8822dff8544f30dbd9ce36f6a57026882a185ec +Subproject commit 163fe3866e7122d6cd1dbff6f121302db8d98aae