Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
53a2865
chore: s3ec v3 transtion and v4 improved tests
imabhichow Oct 17, 2025
1e5b2ea
comment cpp checkout
imabhichow Oct 27, 2025
e0e7ab3
bump s3ec-java commits
imabhichow Oct 27, 2025
5dbb019
chore: add duvet reports for s3ec-java (transition & improved)
imabhichow Sep 30, 2025
ddfdb9b
format
imabhichow Oct 27, 2025
009d1b2
git-ignore
imabhichow Oct 27, 2025
e12fa7d
Merge branch 'fireegg-test-servers' into imabhichow/java-v4-extended-…
imabhichow Oct 27, 2025
db6c65d
Merge branch 'fireegg-test-servers' into imabhichow/java-v4-extended-…
imabhichow Oct 29, 2025
a570537
update java submodule
imabhichow Oct 27, 2025
39fc548
fix configuration
imabhichow Oct 29, 2025
c755778
Revert "chore: reenable c++ (#52)"
imabhichow Oct 29, 2025
d72d851
remove java transiton for now
imabhichow Oct 30, 2025
0dc303f
fix configuration
imabhichow Oct 30, 2025
88c2bc5
fix configuration
imabhichow Oct 30, 2025
edd534e
Update test configuration
imabhichow Oct 30, 2025
12614dc
Duvet
imabhichow Nov 5, 2025
76387f0
Merge remote-tracking branch 'origin/fireegg-test-servers' into imabh…
imabhichow Nov 5, 2025
d0457ad
Rebase
imabhichow Nov 5, 2025
ec3dabf
Merge branch 'fireegg-test-servers' into imabhichow/java-v4-extended-…
imabhichow Nov 6, 2025
131d905
nit - format
imabhichow Nov 6, 2025
ebdaa64
Merge remote-tracking branch 'origin/fireegg-test-servers' into imabh…
imabhichow Nov 7, 2025
9acf8ad
Change java-v4-port
imabhichow Nov 7, 2025
398fc4e
duvet changes
imabhichow Nov 7, 2025
cd342a1
Dotnet change
imabhichow Nov 7, 2025
a8a025b
Merge branch 'fireegg-test-servers' into imabhichow/java-v4-extended-…
imabhichow Nov 7, 2025
2b1b810
remove symlink
imabhichow Nov 7, 2025
e0ee483
Fix Tests
imabhichow Nov 7, 2025
87b3bb1
chore: enable java-v3-transition test server
imabhichow Nov 10, 2025
4ccaab4
chore: enable java-v3-transition test server
imabhichow Nov 10, 2025
ff8e92b
update .gitmodule branch
imabhichow Nov 10, 2025
2d477a6
Merge remote-tracking branch 'origin/fireegg-test-servers' into imabh…
imabhichow Nov 10, 2025
3769f83
Merge branch 'fireegg-test-servers' into imabhichow/java-test-server-v3
imabhichow Nov 10, 2025
d290f89
Merge remote-tracking branch 'origin/fireegg-test-servers' into imabh…
imabhichow Nov 12, 2025
f85bf2e
Merge branch 'fireegg-test-servers' into imabhichow/java-test-server-v3
imabhichow Nov 13, 2025
09d339d
Merge Conflicts
imabhichow Nov 13, 2025
4c820d9
Merge branch 'fireegg-test-servers' into imabhichow/java-test-server-v3
imabhichow Nov 13, 2025
2c80cd5
Merge branch 'fireegg-test-servers' into imabhichow/java-test-server-v3
imabhichow Nov 13, 2025
e5ba4f6
chore: update client configuration to allow for default.
imabhichow Nov 13, 2025
3a117c6
point iv's changes commit
imabhichow Nov 13, 2025
97b95eb
Merge branch 'fireegg-test-servers' into imabhichow/java-test-server-v3
imabhichow Nov 13, 2025
b99808b
Apply suggestion from @rishav-karanjit
imabhichow Nov 13, 2025
88a57ee
allow java
imabhichow Nov 13, 2025
e5313cf
fix duvet
imabhichow Nov 13, 2025
c672dcf
Merge branch 'fireegg-test-servers' into imabhichow/java-test-server-v3
imabhichow Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,27 +156,27 @@ jobs:
aws-region: us-west-2

- name: Build the servers
run: cd test-server && make build-all-servers FILTER=ruby,go,cpp,php
run: cd test-server && make build-all-servers FILTER=ruby,go,cpp,php,java
env:
MAKEFLAGS: -j${{ steps.cpu-count.outputs.count }}
AWS_REGION: us-west-2

- name: Start the servers
run: cd test-server && make start-all-servers FILTER=ruby,go,cpp,php
run: cd test-server && make start-all-servers FILTER=ruby,go,cpp,php,java
env:
AWS_REGION: us-west-2
TEST_SERVER_S3_BUCKET: ${{ vars.TEST_SERVER_S3_BUCKET }}
TEST_SERVER_KMS_KEY_ARN: ${{ vars.TEST_SERVER_KMS_KEY_ARN }}

- name: Wait for servers to start
run: cd test-server && make wait-all-servers FILTER=ruby,go,cpp,php
run: cd test-server && make wait-all-servers FILTER=ruby,go,cpp,php,java
env:
AWS_REGION: us-west-2
TEST_SERVER_S3_BUCKET: ${{ vars.TEST_SERVER_S3_BUCKET }}
TEST_SERVER_KMS_KEY_ARN: ${{ vars.TEST_SERVER_KMS_KEY_ARN }}

- name: Run run-tests
run: cd test-server && make run-tests FILTER=ruby,go,cpp,php
run: cd test-server && make run-tests FILTER=ruby,go,cpp,php,java
env:
AWS_REGION: us-west-2
TEST_SERVER_S3_BUCKET: ${{ vars.TEST_SERVER_S3_BUCKET }}
Expand All @@ -194,7 +194,7 @@ jobs:
test-server/*/net-v3-server.log

- name: Stop the servers
run: cd test-server && make stop-servers FILTER=ruby,go,cpp,php
run: cd test-server && make stop-servers FILTER=ruby,go,cpp,php,java

- name: Upload results
if: always()
Expand Down
3 changes: 1 addition & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
[submodule "test-server/java-v3-transition-server/s3ec-staging"]
path = test-server/java-v3-transition-server/s3ec-staging
url = git@github.com:aws/private-amazon-s3-encryption-client-java-staging.git
branch = imabhichow/s3ec-transition
branch = imabhichow/transition-read-kc
[submodule "test-server/java-v4-server/s3ec-staging"]
path = test-server/java-v4-server/s3ec-staging
url = git@github.com:aws/private-amazon-s3-encryption-client-java-staging.git
branch = imabhichow/add-kc
; branch = s3ec/improved
[submodule "test-server/specification"]
path = test-server/specification
url = git@github.com:awslabs/private-aws-encryption-sdk-specification-staging.git
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public class TestUtils {

public static final Set<String> TRANSITION_VERSIONS =
Set.of(
// JAVA_V3_TRANSITION,
JAVA_V3_TRANSITION,
GO_V3_TRANSITION,
// NET_V2_TRANSITION,
NET_V3_TRANSITION,
Expand Down Expand Up @@ -172,8 +172,7 @@ public class TestUtils {
servers.put(NET_V4, new LanguageServerTarget(NET_V4, "8090"));
servers.put(RUBY_V3, new LanguageServerTarget(RUBY_V3, "8092"));
servers.put(PHP_V3, new LanguageServerTarget(PHP_V3, "8093"));
// TODO: Create and add transition servers
// servers.put(JAVA_V3_TRANSITION, new LanguageServerTarget(JAVA_V3_TRANSITION, "8094"));
servers.put(JAVA_V3_TRANSITION, new LanguageServerTarget(JAVA_V3_TRANSITION, "8094"));
servers.put(GO_V3_TRANSITION, new LanguageServerTarget(GO_V3_TRANSITION, "8095"));
// servers.put(NET_V2_TRANSITION, new LanguageServerTarget(NET_V2_TRANSITION, "8096"));
servers.put(RUBY_V2_TRANSITION, new LanguageServerTarget(RUBY_V2_TRANSITION, "8098"));
Expand Down
2 changes: 1 addition & 1 deletion test-server/java-v3-server/.duvet/config.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json"

[[source]]
pattern = "s3ec-staging/*.java"
pattern = "s3ec-staging/**/*.java"

# Include required specifications here
[[specification]]
Expand Down
2 changes: 1 addition & 1 deletion test-server/java-v3-transition-server/.duvet/config.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json"

[[source]]
pattern = "s3ec-staging/*.java"
pattern = "s3ec-staging/**/*.java"

# Include required specifications here
[[specification]]
Expand Down
2 changes: 1 addition & 1 deletion test-server/java-v3-transition-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies {
implementation("software.amazon.smithy.java:aws-server-restjson:$smithyJavaVersion")

// S3EC from local Maven repository (installed by mvn install)
implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.4.0-TRANSITION")
implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.4.0-read-kc")
}

// Use that application plugin to start the service via the `run` task.
Expand Down
2 changes: 1 addition & 1 deletion test-server/java-v3-transition-server/s3ec-staging
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package software.amazon.encryption.s3;

import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
import software.amazon.encryption.s3.internal.InstructionFileConfig;
import software.amazon.encryption.s3.S3EncryptionClient;
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
import software.amazon.encryption.s3.materials.AesKeyring;
import software.amazon.encryption.s3.materials.Keyring;
import software.amazon.encryption.s3.materials.KmsKeyring;
Expand Down Expand Up @@ -31,148 +30,150 @@
import java.util.UUID;

import static software.amazon.encryption.s3.CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT;
import static software.amazon.encryption.s3.model.EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY;
import static software.amazon.encryption.s3.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT;
import static software.amazon.encryption.s3.CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT;

public class CreateClientOperationImpl implements CreateClientOperation {
private Map<String, S3Client> clientCache_;

public CreateClientOperationImpl(Map<String, S3Client> clientCache) {
clientCache_ = clientCache;
}

// Copied from S3EC.
private boolean onlyOneNonNull(Object... values) {
boolean haveOneNonNull = false;
for (Object o : values) {
if (o != null) {
if (haveOneNonNull) {
return false;
private final Map<String, S3Client> clientCache_;

public CreateClientOperationImpl(Map<String, S3Client> clientCache) {
clientCache_ = clientCache;
}

// Copied from S3EC.
private boolean onlyOneNonNull(Object... values) {
boolean haveOneNonNull = false;
for (Object o : values) {
if (o != null) {
if (haveOneNonNull) {
return false;
}

haveOneNonNull = true;
}
}

haveOneNonNull = true;
}
return haveOneNonNull;
}

return haveOneNonNull;
}

@Override
public CreateClientOutput createClient(CreateClientInput input, RequestContext context) {
try {
KeyMaterial key = input.getConfig().getKeyMaterial();
if (!onlyOneNonNull(key.getAesKey(), key.getKmsKeyId(), key.getRsaKey())) {
throw new RuntimeException("KeyMaterial must be only one, non-null input!");
}
Keyring keyring;
if (key.getAesKey() != null) {
byte[] keyBytes = new byte[key.getAesKey().remaining()];
key.getAesKey().get(keyBytes);
keyring = AesKeyring.builder()
.wrappingKey(new SecretKeySpec(keyBytes, "AES"))
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.build();
} else if (key.getRsaKey() != null) {
@Override
public CreateClientOutput createClient(CreateClientInput input, RequestContext context) {
try {
byte[] keyBytes = new byte[key.getRsaKey().remaining()];
key.getRsaKey().get(keyBytes);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(
privateKey.getModulus(),
privateKey.getPublicExponent()
);

// Generate public key
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

keyring = RsaKeyring.builder()
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.wrappingKeyPair(PartialRsaKeyPair.builder()
.publicKey(publicKey)
.privateKey(privateKey).build())
.build();
} catch (NoSuchAlgorithmException | InvalidKeySpecException nse) {
throw GenericServerError.builder()
.message(nse.getMessage())
.build();
KeyMaterial key = input.getConfig().getKeyMaterial();
if (!onlyOneNonNull(key.getAesKey(), key.getKmsKeyId(), key.getRsaKey())) {
throw new RuntimeException("KeyMaterial must be only one, non-null input!");
}
Keyring keyring;
if (key.getAesKey() != null) {
byte[] keyBytes = new byte[key.getAesKey().remaining()];
key.getAesKey().get(keyBytes);
keyring = AesKeyring.builder()
.wrappingKey(new SecretKeySpec(keyBytes, "AES"))
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.build();
} else if (key.getRsaKey() != null) {
try {
byte[] keyBytes = new byte[key.getRsaKey().remaining()];
key.getRsaKey().get(keyBytes);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(
privateKey.getModulus(),
privateKey.getPublicExponent()
);

// Generate public key
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

keyring = RsaKeyring.builder()
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.wrappingKeyPair(PartialRsaKeyPair.builder()
.publicKey(publicKey)
.privateKey(privateKey).build())
.build();
} catch (NoSuchAlgorithmException | InvalidKeySpecException nse) {
throw GenericServerError.builder()
.message(nse.getMessage())
.build();
}
} else if (key.getKmsKeyId() != null) {
keyring = KmsKeyring.builder()
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.wrappingKeyId(key.getKmsKeyId())
.build();
} else {
throw new RuntimeException("No KeyMaterial found!");
}

// V3 Transition server configuration
// Existing Builder defaults to FORBID_ENCRYPT and ALG_AES_256_GCM_IV12_TAG16_NO_KDF
S3EncryptionClient.Builder s3ClientBuilder = S3EncryptionClient.builder()
.keyring(keyring)
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.enableLegacyUnauthenticatedModes(input.getConfig().isEnableLegacyUnauthenticatedModes());

// Instruction File Put Configuration
boolean instFilePut = false;
if (input.getConfig().getInstructionFileConfig() != null) {
instFilePut = input.getConfig().getInstructionFileConfig().isEnableInstructionFilePutObject();
s3ClientBuilder.instructionFileConfig(InstructionFileConfig.builder()
.instructionFileClient(S3Client.create())
.enableInstructionFilePutObject(instFilePut)
.build());
}

// Configure commitment policy if provided
if (input.getConfig().getCommitmentPolicy() != null) {
CommitmentPolicy policy = getCommitmentPolicy(input.getConfig().getCommitmentPolicy());
s3ClientBuilder.commitmentPolicy(policy);
}

// Configure encryption algorithm if provided
if (input.getConfig().getEncryptionAlgorithm() != null) {
AlgorithmSuite algorithm = getAlgorithmSuite(input.getConfig().getEncryptionAlgorithm());
s3ClientBuilder.encryptionAlgorithm(algorithm);
}

S3Client s3Client = s3ClientBuilder.build();

UUID uuid = UUID.randomUUID();
String uuidString = uuid.toString();
clientCache_.put(uuidString, s3Client);
return CreateClientOutput.builder()
.clientId(uuidString)
.build();
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
throw GenericServerError.builder()
.message(stackTrace)
.build();
}
} else if (key.getKmsKeyId() != null) {
keyring = KmsKeyring.builder()
.enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms())
.wrappingKeyId(key.getKmsKeyId())
.build();
} else {
throw new RuntimeException("No KeyMaterial found!");
}

boolean instFilePut = false;
if (input.getConfig().getInstructionFileConfig() != null) {
instFilePut = input.getConfig().getInstructionFileConfig().isEnableInstructionFilePutObject();
}

// V3-Transitional server configuration
S3EncryptionClient.Builder clientBuilder = S3EncryptionClient.builder()
.instructionFileConfig(InstructionFileConfig.builder()
.instructionFileClient(S3Client.create())
.enableInstructionFilePutObject(instFilePut)
.build())
.keyring(keyring);

// Configure commitment policy if provided ( feature)
if (input.getConfig().getCommitmentPolicy() != null) {
CommitmentPolicy policy = getCommitmentPolicy(input);
clientBuilder.commitmentPolicy(policy);
}
// V3-Transitional default: No commitment policy (null) for backward compatibility

// Configure encryption algorithm if provided ( feature)
if (input.getConfig().getEncryptionAlgorithm() != null) {
AlgorithmSuite algorithm = getAlgorithmSuite(input);
clientBuilder.encryptionAlgorithm(algorithm);
} else {
// V3-Transitional default: Legacy algorithm for backward compatibility
clientBuilder.encryptionAlgorithm(AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF);
}

S3Client s3Client = clientBuilder.build();
UUID uuid = UUID.randomUUID();
String uuidString = uuid.toString();
clientCache_.put(uuidString, s3Client);
return CreateClientOutput.builder()
.clientId(uuidString)
.build();
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
throw GenericServerError.builder()
.message(stackTrace)
.build();
}
}

private static AlgorithmSuite getAlgorithmSuite(CreateClientInput input) {
if (input.getConfig().getEncryptionAlgorithm().equals(EncryptionAlgorithm.ALG_AES_256_CBC_IV16_NO_KDF)) {
return AlgorithmSuite.ALG_AES_256_CBC_IV16_NO_KDF;
} else if (input.getConfig().getEncryptionAlgorithm().equals(EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF)) {
return AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF;
} else if (input.getConfig().getEncryptionAlgorithm().equals(EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY)) {
return AlgorithmSuite.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY;
} else {
throw new RuntimeException("Unknown encryption algorithm: " + input.getConfig().getEncryptionAlgorithm());

private static AlgorithmSuite getAlgorithmSuite(EncryptionAlgorithm input) {
if (input.equals(EncryptionAlgorithm.ALG_AES_256_CBC_IV16_NO_KDF)) {
return AlgorithmSuite.ALG_AES_256_CBC_IV16_NO_KDF;
} else if (input.equals(EncryptionAlgorithm.ALG_AES_256_GCM_IV12_TAG16_NO_KDF)) {
return AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF;
} else if (input.equals(EncryptionAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY)) {
return AlgorithmSuite.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY;
} else {
throw new RuntimeException("Unknown encryption algorithm: " + input);
}
}
}

private static software.amazon.encryption.s3.CommitmentPolicy getCommitmentPolicy(CreateClientInput input) {
if (input.getConfig().getCommitmentPolicy().equals(software.amazon.encryption.s3.model.CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT)) {
return FORBID_ENCRYPT_ALLOW_DECRYPT;
} else if (input.getConfig().getCommitmentPolicy().equals(software.amazon.encryption.s3.model.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT)) {
return null;
} else if (input.getConfig().getCommitmentPolicy().equals(software.amazon.encryption.s3.model.CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT)) {
return null;
} else {
throw new RuntimeException("Unknown commitment policy: " + input.getConfig().getCommitmentPolicy());

private static software.amazon.encryption.s3.CommitmentPolicy getCommitmentPolicy(software.amazon.encryption.s3.model.CommitmentPolicy input) {
if (input.equals(software.amazon.encryption.s3.model.CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT)) {
return FORBID_ENCRYPT_ALLOW_DECRYPT;
} else if (input.equals(software.amazon.encryption.s3.model.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT)) {
return REQUIRE_ENCRYPT_ALLOW_DECRYPT;
} else if (input.equals(software.amazon.encryption.s3.model.CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT)) {
return REQUIRE_ENCRYPT_REQUIRE_DECRYPT;
} else {
throw new RuntimeException("Unknown commitment policy: " + input);
}
}
}
}
Loading
Loading