Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ duvet_report:
report \
--spec-pattern "compliance/**/*.toml" \
--source-pattern "src/**/*.java" \
--source-pattern "compliance_exceptions/*.txt" \
--html specification_compliance_report.html
15 changes: 15 additions & 0 deletions compliance_exceptions/s3-kms-keyring.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// The KMS Keyring in S3EC Java v3 does not validate KMS Key IDs.
// Passing an invalid key ID will eventually lead to KMS Request failures.

//= specification/s3-encryption/materials/s3-kms-keyring.md#initialization
//= type=exception
//# The KmsKeyring MAY validate that the AWS KMS key identifier is not null or empty.
//= specification/s3-encryption/materials/s3-kms-keyring.md#initialization
//= type=exception
//# If the KmsKeyring validates that the AWS KMS key identifier is not null or empty, then it MUST throw an exception.
//= specification/s3-encryption/materials/s3-kms-keyring.md#initialization
//= type=exception
//# The KmsKeyring MAY validate that the AWS KMS key identifier is [a valid AWS KMS Key identifier](../../framework/aws-kms/aws-kms-key-arn.md#a-valid-aws-kms-identifier).
//= specification/s3-encryption/materials/s3-kms-keyring.md#initialization
//= type=exception
//# If the KmsKeyring validates that the AWS KMS key identifier is not a valid AWS KMS Key identifier, then it MUST throw an exception.
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public static Consumer<AwsRequestOverrideConfiguration.Builder> withAdditionalCo

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# ReEncryptInstructionFile MAY be implemented by the S3EC.
//# - ReEncryptInstructionFile MAY be implemented by the S3EC.
/**
* Re-encrypts an instruction file with a new keyring while preserving the original encrypted object in S3.
* This enables:
Expand Down Expand Up @@ -252,7 +252,7 @@ public ReEncryptInstructionFileResponse reEncryptInstructionFile(ReEncryptInstru
//Decrypt the data key using the current keyring
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# ReEncryptInstructionFile MUST decrypt the instruction file's encrypted data key for the given object using the client's CMM.
//# - ReEncryptInstructionFile MUST decrypt the instruction file's encrypted data key for the given object using the client's CMM.
DecryptionMaterials decryptedMaterials = this._cryptoMaterialsManager.decryptMaterials(
DecryptMaterialsRequest.builder()
.algorithmSuite(algorithmSuite)
Expand All @@ -273,7 +273,7 @@ public ReEncryptInstructionFileResponse reEncryptInstructionFile(ReEncryptInstru
//Re-encrypt the data key with the new keyring while preserving other cryptographic parameters
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# ReEncryptInstructionFile MUST re-encrypt the plaintext data key with a provided keyring.
//# - ReEncryptInstructionFile MUST re-encrypt the plaintext data key with a provided keyring.
RawKeyring newKeyring = reEncryptInstructionFileRequest.newKeyring();
EncryptionMaterials encryptedMaterials = newKeyring.onEncrypt(encryptionMaterials);

Expand Down Expand Up @@ -317,7 +317,7 @@ private void enforceRotation(EncryptionMaterials newEncryptionMaterials, GetObje

//= specification/s3-encryption/client.md#required-api-operations
//= type=implication
//# PutObject MUST be implemented by the S3EC.
//# - PutObject MUST be implemented by the S3EC.
/**
* See {@link S3EncryptionClient#putObject(PutObjectRequest, RequestBody)}.
* <p>
Expand Down Expand Up @@ -357,7 +357,7 @@ public PutObjectResponse putObject(PutObjectRequest putObjectRequest, RequestBod
try {
//= specification/s3-encryption/client.md#required-api-operations
//= type=implication
//# PutObject MUST encrypt its input data before it is uploaded to S3.
//# - PutObject MUST encrypt its input data before it is uploaded to S3.
CompletableFuture<PutObjectResponse> futurePut = pipeline.putObject(putObjectRequest,
AsyncRequestBody.fromInputStream(
requestBody.contentStreamProvider().newStream(),
Expand All @@ -384,7 +384,7 @@ public PutObjectResponse putObject(PutObjectRequest putObjectRequest, RequestBod

//= specification/s3-encryption/client.md#required-api-operations
//= type=implication
//# GetObject MUST be implemented by the S3EC.
//# - GetObject MUST be implemented by the S3EC.
/**
* See {@link S3EncryptionClient#getObject(GetObjectRequest, ResponseTransformer)}
* <p>
Expand All @@ -408,7 +408,7 @@ public <T> T getObject(GetObjectRequest getObjectRequest,

//= specification/s3-encryption/client.md#required-api-operations
//= type=implication
//# GetObject MUST decrypt data received from the S3 server and return it as plaintext.
//# - GetObject MUST decrypt data received from the S3 server and return it as plaintext.
GetEncryptedObjectPipeline pipeline = GetEncryptedObjectPipeline.builder()
.s3AsyncClient(_wrappedAsyncClient)
.cryptoMaterialsManager(_cryptoMaterialsManager)
Expand Down Expand Up @@ -518,7 +518,7 @@ private <T extends Throwable> T onAbort(UploadObjectObserver observer, T t) {

//= specification/s3-encryption/client.md#required-api-operations
//= type=implication
//# DeleteObject MUST be implemented by the S3EC.
//# - DeleteObject MUST be implemented by the S3EC.
/**
* See {@link S3Client#deleteObject(DeleteObjectRequest)}.
* <p>
Expand All @@ -538,11 +538,11 @@ public DeleteObjectResponse deleteObject(DeleteObjectRequest deleteObjectRequest
try {
//= specification/s3-encryption/client.md#required-api-operations
//= type=implementation
//# DeleteObject MUST delete the given object key.
//# - DeleteObject MUST delete the given object key.
DeleteObjectResponse deleteObjectResponse = _wrappedAsyncClient.deleteObject(actualRequest).join();
//= specification/s3-encryption/client.md#required-api-operations
//= type=implementation
//# DeleteObject MUST delete the associated instruction file using the default instruction file suffix.
//# - DeleteObject MUST delete the associated instruction file using the default instruction file suffix.
String instructionObjectKey = deleteObjectRequest.key() + DEFAULT_INSTRUCTION_FILE_SUFFIX;
_wrappedAsyncClient.deleteObject(builder -> builder
.overrideConfiguration(API_NAME_INTERCEPTOR)
Expand All @@ -559,7 +559,7 @@ public DeleteObjectResponse deleteObject(DeleteObjectRequest deleteObjectRequest

//= specification/s3-encryption/client.md#required-api-operations
//= type=implication
//# DeleteObjects MUST be implemented by the S3EC.
//# - DeleteObjects MUST be implemented by the S3EC.
/**
* See {@link S3Client#deleteObjects(DeleteObjectsRequest)}.
* <p>
Expand All @@ -578,11 +578,11 @@ public DeleteObjectsResponse deleteObjects(DeleteObjectsRequest deleteObjectsReq
try {
//= specification/s3-encryption/client.md#required-api-operations
//= type=implementation
//# DeleteObjects MUST delete each of the given objects.
//# - DeleteObjects MUST delete each of the given objects.
DeleteObjectsResponse deleteObjectsResponse = _wrappedAsyncClient.deleteObjects(actualRequest).join();
//= specification/s3-encryption/client.md#required-api-operations
//= type=implementation
//# DeleteObjects MUST delete each of the corresponding instruction files using the default instruction file suffix.
//# - DeleteObjects MUST delete each of the corresponding instruction files using the default instruction file suffix.
List<ObjectIdentifier> deleteObjects = instructionFileKeysToDelete(deleteObjectsRequest);
_wrappedAsyncClient.deleteObjects(DeleteObjectsRequest.builder()
.overrideConfiguration(API_NAME_INTERCEPTOR)
Expand All @@ -599,7 +599,7 @@ public DeleteObjectsResponse deleteObjects(DeleteObjectsRequest deleteObjectsReq

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# CreateMultipartUpload MAY be implemented by the S3EC.
//# - CreateMultipartUpload MAY be implemented by the S3EC.
/**
* See {@link S3Client#createMultipartUpload(CreateMultipartUploadRequest)}
* <p>
Expand All @@ -623,7 +623,7 @@ public CreateMultipartUploadResponse createMultipartUpload(CreateMultipartUpload

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# UploadPart MAY be implemented by the S3EC.
//# - UploadPart MAY be implemented by the S3EC.
/**
* See {@link S3Client#uploadPart(UploadPartRequest, RequestBody)}
*
Expand All @@ -649,7 +649,7 @@ public UploadPartResponse uploadPart(UploadPartRequest request, RequestBody requ

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# CompleteMultipartUpload MAY be implemented by the S3EC.
//# - CompleteMultipartUpload MAY be implemented by the S3EC.
/**
* See {@link S3Client#completeMultipartUpload(CompleteMultipartUploadRequest)}
* @param request the request instance
Expand All @@ -669,7 +669,7 @@ public CompleteMultipartUploadResponse completeMultipartUpload(CompleteMultipart

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# AbortMultipartUpload MAY be implemented by the S3EC.
//# - AbortMultipartUpload MAY be implemented by the S3EC.
/**
* See {@link S3Client#abortMultipartUpload(AbortMultipartUploadRequest)}
* @param request the request instance
Expand Down Expand Up @@ -763,7 +763,7 @@ private Builder() {
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "Pass mutability into wrapping client")
public Builder wrappedClient(S3Client _wrappedClient) {
//= specification/s3-encryption/client.md#wrapped-s3-client-s
//= type=exception
//= type=implementation
//# The S3EC MUST NOT support use of S3EC as the provided S3 client during its initialization; it MUST throw an exception in this case.
if (_wrappedClient instanceof S3EncryptionClient) {
throw new S3EncryptionClientException("Cannot use S3EncryptionClient as wrapped client");
Expand All @@ -785,7 +785,7 @@ public Builder wrappedClient(S3Client _wrappedClient) {
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "Pass mutability into wrapping client")
public Builder wrappedAsyncClient(S3AsyncClient _wrappedAsyncClient) {
//= specification/s3-encryption/client.md#wrapped-s3-client-s
//= type=exception
//= type=implementation
//# The S3EC MUST NOT support use of S3EC as the provided S3 client during its initialization; it MUST throw an exception in this case.
if (_wrappedAsyncClient instanceof S3AsyncEncryptionClient) {
throw new S3EncryptionClientException("Cannot use S3AsyncEncryptionClient as wrapped client");
Expand Down Expand Up @@ -885,7 +885,7 @@ private void checkKeyOptions() {
}

//= specification/s3-encryption/client.md#cryptographic-materials
//= type=exception
//= type=implementation
//# If both a CMM and a Keyring are provided, the S3EC MUST throw an exception.
throw new S3EncryptionClientException("Only one may be set of: crypto materials manager, keyring, AES key, RSA key pair, KMS key id");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private DecryptionMaterials prepareMaterialsFromRequest(final GetObjectRequest g
//# When enabled, the S3EC MUST be able to decrypt objects encrypted with all content encryption algorithms (both legacy and fully supported).
if (!_enableLegacyUnauthenticatedModes && algorithmSuite.isLegacy()) {
//= specification/s3-encryption/client.md#enable-legacy-unauthenticated-modes
//= type=exception
//= type=implementation
//# When disabled, the S3EC MUST NOT decrypt objects encrypted using legacy content encryption algorithms; it MUST throw an exception when attempting to decrypt an object encrypted with a legacy content encryption algorithm.
throw new S3EncryptionClientException("Enable legacy unauthenticated modes to use legacy content decryption: " + algorithmSuite.cipherName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public CreateMultipartUploadResponse createMultipartUpload(CreateMultipartUpload

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# If implemented, CreateMultipartUpload MUST initiate a multipart upload.
//# - If implemented, CreateMultipartUpload MUST initiate a multipart upload.
CreateMultipartUploadResponse response = _s3AsyncClient.createMultipartUpload(request).join();

MultipartUploadMaterials mpuMaterials = MultipartUploadMaterials.builder()
Expand Down Expand Up @@ -138,19 +138,19 @@ public UploadPartResponse uploadPart(UploadPartRequest request, RequestBody requ
final UploadPartResponse response;
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# Each part MUST be encrypted in sequence.
//# - Each part MUST be encrypted in sequence.
materials.beginPartUpload(actualRequest.partNumber(), partContentLength);
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# Each part MUST be encrypted using the same cipher instance for each part.
//# - Each part MUST be encrypted using the same cipher instance for each part.
Cipher cipher = materials.getCipher(materials.getIv());

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

try {
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# UploadPart MUST encrypt each part.
//# - UploadPart MUST encrypt each part.
final AsyncRequestBody cipherAsyncRequestBody = new CipherAsyncRequestBody(
AsyncRequestBody.fromInputStream(
requestBody.contentStreamProvider().newStream(),
Expand All @@ -170,8 +170,6 @@ public UploadPartResponse uploadPart(UploadPartRequest request, RequestBody requ
}
// Ensures parts are not retried to avoid corrupting ciphertext
AsyncRequestBody noRetryBody = new NoRetriesAsyncRequestBody(cipherAsyncRequestBody);
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
response = _s3AsyncClient.uploadPart(actualRequest, noRetryBody).join();
} finally {
materials.endPartUpload();
Expand Down Expand Up @@ -202,7 +200,7 @@ public CompleteMultipartUploadResponse completeMultipartUpload(CompleteMultipart

//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# CompleteMultipartUpload MUST complete the multipart upload.
//# - CompleteMultipartUpload MUST complete the multipart upload.
CompleteMultipartUploadResponse response = _s3AsyncClient.completeMultipartUpload(actualRequest).join();

_multipartUploadMaterials.remove(uploadId);
Expand All @@ -216,7 +214,7 @@ public AbortMultipartUploadResponse abortMultipartUpload(AbortMultipartUploadReq
.build();
//= specification/s3-encryption/client.md#optional-api-operations
//= type=implication
//# AbortMultipartUpload MUST abort the multipart upload.
//# - AbortMultipartUpload MUST abort the multipart upload.
return _s3AsyncClient.abortMultipartUpload(actualRequest).join();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,38 @@

import java.util.List;

//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The Keyring interface and its operations SHOULD adhere to the naming conventions of the implementation language.
/**
* Keyring defines the interface for wrapping data keys. A {@link CryptographicMaterialsManager} will use
* keyrings to encrypt and decrypt data keys.
*/
public interface Keyring {
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The Keyring interface and its operations SHOULD adhere to the naming conventions of the implementation language.
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The Keyring interface MUST include the OnEncrypt operation.
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The OnEncrypt operation MUST accept an instance of EncryptionMaterials as input.
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The OnEncrypt operation MUST return an instance of EncryptionMaterials as output.
EncryptionMaterials onEncrypt(final EncryptionMaterials materials);
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The Keyring interface and its operations SHOULD adhere to the naming conventions of the implementation language.
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The Keyring interface MUST include the OnDecrypt operation.
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The OnDecrypt operation MUST accept an instance of DecryptionMaterials and a collection of EncryptedDataKey instances as input.
//= specification/s3-encryption/materials/keyrings.md#interface
//= type=implication
//# The OnDecrypt operation MUST return an instance of DecryptionMaterials as output.
DecryptionMaterials onDecrypt(final DecryptionMaterials materials, final List<EncryptedDataKey> encryptedDataKeys);
}
Loading