Skip to content

Commit c111f05

Browse files
authored
Added overload to GetObject in encryption client to provide encryption context.
Added overload to GetObject in encryption client to provide encryption context. If the supplied encryption context does not exactly match the encryption context used for PutObject, the operation will fail.
1 parent 199c0a8 commit c111f05

File tree

4 files changed

+90
-2
lines changed

4 files changed

+90
-2
lines changed

src/aws-cpp-sdk-s3-encryption/include/aws/s3-encryption/S3EncryptionClient.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,23 @@ namespace Aws
9292
*/
9393
S3EncryptionGetObjectOutcome GetObject(const Aws::S3::Model::GetObjectRequest& request) const;
9494

95+
/*
96+
* Function to get an object decrypted from S3. Fails if stored Materials Description does not exactly match supplied contextMap
97+
*
98+
* Range gets using this method are deprecated. Please see
99+
* <https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html> for more information
100+
*/
101+
S3EncryptionGetObjectOutcome GetObject(const Aws::S3::Model::GetObjectRequest& request, const Aws::Map<Aws::String, Aws::String>& contextMap) const;
102+
95103
inline bool MultipartUploadSupported() const { return false; }
96104

97105
protected:
106+
/*
107+
* GetObject with optional contextMap.
108+
* Fail if contextMap is supplied and does not exactly match stored Materials Description
109+
*/
110+
S3EncryptionGetObjectOutcome GetObjectInner(const Aws::S3::Model::GetObjectRequest& request, const Aws::Map<Aws::String, Aws::String> * contextMap) const;
111+
98112
/*
99113
* Function to get the instruction file object of a encrypted object from S3. This instruction file object will be used to assist decryption.
100114
*/

src/aws-cpp-sdk-s3-encryption/source/s3-encryption/S3EncryptionClient.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,38 @@ namespace Aws
6363
return module->PutObjectSecurely(request, putObjectFunction, contextMap);
6464
}
6565

66-
S3EncryptionGetObjectOutcome S3EncryptionClientBase::GetObject(const Aws::S3::Model::GetObjectRequest & request) const
66+
bool MapsEqual(const Aws::Map<Aws::String, Aws::String>& passed, const Aws::Map<Aws::String, Aws::String>& stored)
67+
{
68+
// everything in passed must be in stored, withthe same value.
69+
auto stored_end = stored.end();
70+
auto passed_end = passed.end();
71+
for (const auto& pair : passed) {
72+
auto it = stored.find(pair.first);
73+
if (it == stored_end) return false;
74+
if (it->second != pair.second) return false;
75+
}
76+
77+
// everything in stored, if it does not begin with 'amz:' must be in passed.
78+
// if it is, then we already checked the value
79+
for (const auto& pair : stored) {
80+
if (strcmp(pair.first.c_str(), Materials::kmsEncryptionContextKey)
81+
&& strcmp(pair.first.c_str(),Materials::cmkID_Identifier)) {
82+
auto it = passed.find(pair.first);
83+
if (it == passed_end) return false;
84+
}
85+
}
86+
return true;
87+
}
88+
89+
S3EncryptionGetObjectOutcome S3EncryptionClientBase::GetObject(const Aws::S3::Model::GetObjectRequest & request) const
90+
{
91+
return GetObjectInner(request, nullptr);
92+
}
93+
S3EncryptionGetObjectOutcome S3EncryptionClientBase::GetObject(const Aws::S3::Model::GetObjectRequest & request, const Aws::Map<Aws::String, Aws::String>& contextMap) const
94+
{
95+
return GetObjectInner(request, &contextMap);
96+
}
97+
S3EncryptionGetObjectOutcome S3EncryptionClientBase::GetObjectInner(const Aws::S3::Model::GetObjectRequest & request, const Aws::Map<Aws::String, Aws::String> * contextMap) const
6798
{
6899
Aws::S3::Model::HeadObjectRequest headRequest;
69100
headRequest.WithBucket(request.GetBucket());
@@ -100,6 +131,12 @@ namespace Aws
100131
Handlers::MetadataHandler handler;
101132
contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
102133
}
134+
if (contextMap && !MapsEqual(*contextMap, contentCryptoMaterial.GetMaterialsDescription()))
135+
{
136+
return S3EncryptionGetObjectOutcome(BuildS3EncryptionError(AWSError<S3Errors>(
137+
S3Errors::INVALID_ACTION, "MaterialsDescriptionMismatch",
138+
"Provided encryption context does not match information retrieved from S3", false/*not retryable*/)));
139+
}
103140

104141
// security check
105142
if (request.RangeHasBeenSet() && m_cryptoConfig.GetUnAuthenticatedRangeGet() == RangeGetMode::DISABLED)

tests/aws-cpp-sdk-s3-encryption-integration-tests/LiveClientTests.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,43 @@ TEST_F(LiveClientTest, TestEOMode)
198198
AWS_EXPECT_SUCCESS(deleteResult);
199199
}
200200

201+
TEST_F(LiveClientTest, TestEncryptionContextEmpty)
202+
{
203+
ClientConfiguration s3ClientConfig;
204+
s3ClientConfig.region = AWS_TEST_REGION;
205+
206+
auto key = SymmetricCipher::GenerateKey();
207+
auto simpleEncryptionMaterials = Aws::MakeShared<Materials::SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, key);
208+
CryptoConfigurationV2 configuration(simpleEncryptionMaterials);
209+
210+
static const char* objectKey = "TestEncryptionContextEmptyKey";
211+
212+
S3EncryptionClientV2 client(configuration, s3ClientConfig);
213+
214+
Model::PutObjectRequest putObjectRequest;
215+
putObjectRequest.WithBucket(BucketName.c_str())
216+
.WithKey(objectKey);
217+
218+
auto ss = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
219+
*ss << TEST_STRING;
220+
ss->flush();
221+
222+
putObjectRequest.SetBody(ss);
223+
224+
auto putObjectResult = client.PutObject(putObjectRequest, {});
225+
AWS_ASSERT_SUCCESS(putObjectResult);
226+
227+
Model::GetObjectRequest getObjectRequest;
228+
getObjectRequest.WithBucket(BucketName.c_str()).WithKey(objectKey);
229+
230+
auto getObjectResult = client.GetObject(getObjectRequest);
231+
AWS_EXPECT_SUCCESS(getObjectResult);
232+
getObjectResult = client.GetObject(getObjectRequest, {});
233+
AWS_EXPECT_SUCCESS(getObjectResult);
234+
getObjectResult = client.GetObject(getObjectRequest, {{"foo", "bar"}});
235+
EXPECT_FALSE(getObjectResult.IsSuccess());
236+
}
237+
201238
TEST_F(LiveClientTest, TestAEMode)
202239
{
203240
CryptoConfiguration configuration;

tools/scripts/run_integration_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def main():
4949
"aws-cpp-sdk-lambda-integration-tests",
5050
"aws-cpp-sdk-cognitoidentity-integration-tests",
5151
#"aws-cpp-sdk-transfer-tests",
52-
#"aws-cpp-sdk-s3-encryption-integration-tests",
52+
"aws-cpp-sdk-s3-encryption-integration-tests",
5353
"aws-cpp-sdk-kinesis-integration-tests",
5454
"aws-cpp-sdk-logs-integration-tests",
5555
"aws-cpp-sdk-monitoring-integration-tests",

0 commit comments

Comments
 (0)