Skip to content

Commit 3bc3775

Browse files
author
Anirav Kareddy
committed
enforceRotation feature implementation
1 parent dd202cf commit 3bc3775

File tree

4 files changed

+1792
-5
lines changed

4 files changed

+1792
-5
lines changed

src/main/java/software/amazon/encryption/s3/S3EncryptionClient.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ public static Consumer<AwsRequestOverrideConfiguration.Builder> withAdditionalCo
207207
* Key rotation scenarios:
208208
* - Legacy to V3: Can rotate same wrapping key from legacy wrapping algorithms to fully supported wrapping algorithms
209209
* - Within V3: When rotating the wrapping key, the new keyring must be different from the current keyring
210+
* - Enforce Rotation: When enabled, ensures old keyring cannot decrypt data encrypted by new keyring
210211
*
211212
* @param reEncryptInstructionFileRequest the request containing bucket, object key, new keyring, and optional instruction file suffix
212213
* @return ReEncryptInstructionFileResponse containing the bucket, object key, and instruction file suffix used
@@ -257,6 +258,11 @@ public ReEncryptInstructionFileResponse reEncryptInstructionFile(ReEncryptInstru
257258
throw new S3EncryptionClientException("New keyring must have new materials description!");
258259
}
259260

261+
// If enforceRotation is set to true, ensure that the old keyring cannot decrypt the newly encrypted data key
262+
if (reEncryptInstructionFileRequest.enforceRotation()) {
263+
enforceRotation(encryptedMaterials, request);
264+
}
265+
260266
//Create or update instruction file with the re-encrypted metadata while preserving IV
261267
ContentMetadataEncodingStrategy encodeStrategy = new ContentMetadataEncodingStrategy(_instructionFileConfig);
262268
encodeStrategy.encodeMetadata(encryptedMaterials, iv, PutObjectRequest.builder()
@@ -265,8 +271,23 @@ public ReEncryptInstructionFileResponse reEncryptInstructionFile(ReEncryptInstru
265271
.build(), reEncryptInstructionFileRequest.instructionFileSuffix());
266272

267273
return new ReEncryptInstructionFileResponse(reEncryptInstructionFileRequest.bucket(),
268-
reEncryptInstructionFileRequest.key(), reEncryptInstructionFileRequest.instructionFileSuffix());
274+
reEncryptInstructionFileRequest.key(), reEncryptInstructionFileRequest.instructionFileSuffix(), reEncryptInstructionFileRequest.enforceRotation());
275+
276+
}
269277

278+
private void enforceRotation(EncryptionMaterials newEncryptionMaterials, GetObjectRequest request) {
279+
try {
280+
DecryptionMaterials decryptedMaterials = this._cryptoMaterialsManager.decryptMaterials(
281+
DecryptMaterialsRequest.builder()
282+
.algorithmSuite(newEncryptionMaterials.algorithmSuite())
283+
.encryptedDataKeys(Collections.singletonList(newEncryptionMaterials.encryptedDataKeys()).get(0))
284+
.s3Request(request)
285+
.build()
286+
);
287+
} catch (S3EncryptionClientException e) {
288+
return;
289+
}
290+
throw new S3EncryptionClientException("Key rotation is not enforced! Old keyring is still able to decrypt the newly encrypted data key");
270291
}
271292

272293
/**

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ public class ReEncryptInstructionFileRequest {
1919
private final String key;
2020
private final RawKeyring newKeyring;
2121
private final String instructionFileSuffix;
22+
private final boolean enforceRotation;
2223

2324
private ReEncryptInstructionFileRequest(Builder builder) {
2425
bucket = builder.bucket;
2526
key = builder.key;
2627
newKeyring = builder.newKeyring;
2728
instructionFileSuffix = builder.instructionFileSuffix;
29+
enforceRotation = builder.enforceRotation;
30+
2831
}
2932

3033
/**
@@ -55,6 +58,11 @@ public String instructionFileSuffix() {
5558
return instructionFileSuffix;
5659
}
5760

61+
/**
62+
* @return whether to enforce rotation for the re-encrypted instruction file
63+
*/
64+
public boolean enforceRotation() { return enforceRotation; }
65+
5866
/**
5967
* Creates a builder that can be used to configure and create a {@link ReEncryptInstructionFileRequest}
6068
*
@@ -72,6 +80,7 @@ public static class Builder {
7280
private String key;
7381
private RawKeyring newKeyring;
7482
private String instructionFileSuffix = DEFAULT_INSTRUCTION_FILE_SUFFIX;
83+
private boolean enforceRotation = false;
7584

7685
/**
7786
* Sets the S3 bucket name for the re-encryption of instruction file.
@@ -120,6 +129,17 @@ public Builder instructionFileSuffix(String instructionFileSuffix) {
120129
return this;
121130
}
122131

132+
/**
133+
* Sets whether to enforce rotation for the re-encrypted instruction file.
134+
*
135+
* @param enforceRotation whether to enforce rotation
136+
* @return a reference to this object so that method calls can be chained together.
137+
*/
138+
public Builder enforceRotation(boolean enforceRotation) {
139+
this.enforceRotation = enforceRotation;
140+
return this;
141+
}
142+
123143
/**
124144
* Validates and builds the ReEncryptInstructionFileRequest according
125145
* to the configuration options passed to the Builder object.

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,27 @@
44

55
/**
66
* Response object returned after re-encrypting an instruction file in S3.
7-
* Contains the S3 bucket name, object key, and instruction file suffix used for the re-encrypted instruction file
7+
* Contains the S3 bucket name, object key, instruction file suffix, and rotation enforcement status for the re-encrypted instruction file
88
*/
99
public class ReEncryptInstructionFileResponse {
1010
private final String bucket;
1111
private final String key;
1212
private final String instructionFileSuffix;
13+
private final boolean enforceRotation;
1314

1415
/**
1516
* Creates a new ReEncryptInstructionFileResponse object with the specified parameters.
1617
*
1718
* @param bucket the S3 bucket containing the re-encrypted instruction file
1819
* @param key the S3 object key of the encrypted object in S3
1920
* @param instructionFileSuffix the suffix used for the instruction file
21+
* @param enforceRotation whether rotation was enforced for the re-encrypted instruction file
2022
*/
21-
public ReEncryptInstructionFileResponse(String bucket, String key, String instructionFileSuffix) {
23+
public ReEncryptInstructionFileResponse(String bucket, String key, String instructionFileSuffix, boolean enforceRotation) {
2224
this.bucket = bucket;
2325
this.key = key;
2426
this.instructionFileSuffix = instructionFileSuffix.substring(1);
27+
this.enforceRotation = enforceRotation;
2528
}
2629

2730
/**
@@ -38,6 +41,13 @@ public String key() {
3841
return key;
3942
}
4043

44+
/**
45+
* @return whether rotation was enforced for the re-encrypted instruction file
46+
*/
47+
public boolean enforceRotation() {
48+
return enforceRotation;
49+
}
50+
4151
/**
4252
* @return the instruction file suffix used for the instruction file
4353
*/

0 commit comments

Comments
 (0)