Skip to content

Commit 55c521a

Browse files
committed
chore: include bad item keys in query errors
1 parent 1487d7e commit 55c521a

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/DdbMiddlewareConfig.dfy

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ module DdbMiddlewareConfig {
99
import EncTypes = AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes
1010
import DDBE = AwsCryptographyDbEncryptionSdkDynamoDbTypes
1111
import SearchableEncryptionInfo
12+
import DDB = ComAmazonawsDynamodbTypes
13+
import HexStrings
1214

1315
datatype TableConfig = TableConfig(
1416
physicalTableName: ComAmazonawsDynamodbTypes.TableName,
@@ -86,6 +88,35 @@ module DdbMiddlewareConfig {
8688
tableEncryptionConfigs: map<string, ValidTableConfig>
8789
)
8890

91+
function method AttrToString(attr : DDB.AttributeValue) : string
92+
{
93+
if attr.S? then
94+
attr.S
95+
else if attr.N? then
96+
attr.N
97+
else if attr.B? then
98+
HexStrings.ToHexString(attr.B)
99+
else
100+
"unexpected key type"
101+
}
102+
103+
// return human readable string containing primary keys
104+
function method KeyString(config : ValidTableConfig, item : DDB.AttributeMap) : string
105+
{
106+
var partition :=
107+
if config.partitionKeyName in item then
108+
config.partitionKeyName + " = " + AttrToString(item[config.partitionKeyName])
109+
else
110+
"";
111+
var sort :=
112+
if config.sortKeyName.Some? && config.sortKeyName.value in item then
113+
"\n" + config.sortKeyName.value + " = " + AttrToString(item[config.sortKeyName.value])
114+
else
115+
"";
116+
117+
partition + sort
118+
}
119+
89120
function method MapError<T>(r : Result<T, EncTypes.Error>) : Result<T, Error> {
90121
r.MapFailure(e => AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor(e))
91122
}

DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/QueryTransform.dfy

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,29 @@ module QueryTransform {
8181
if keyId.KeyId? {
8282
keyIdUtf8 :- UTF8.Encode(keyId.value).MapFailure(e => E(e));
8383
}
84-
ghost var originalHistory := tableConfig.itemEncryptor.History.DecryptItem;
85-
ghost var historySize := |originalHistory|;
84+
85+
var decryptErrors : seq<Error> := [];
86+
var lastRealError := -1;
87+
8688
for x := 0 to |encryptedItems|
89+
invariant lastRealError == -1 || lastRealError < |decryptErrors|
8790
{
8891
//= specification/dynamodb-encryption-client/ddb-sdk-integration.md#decrypt-after-query
8992
//# Each of these entries on the original response MUST be replaced
9093
//# with the resulting decrypted [DynamoDB Item](./decrypt-item.md#dynamodb-item-1).
9194
var decryptInput := EncTypes.DecryptItemInput(encryptedItem := encryptedItems[x]);
9295
var decryptRes := tableConfig.itemEncryptor.DecryptItem(decryptInput);
93-
var decrypted :- MapError(decryptRes);
96+
if decryptRes.Failure? {
97+
var error := AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor(decryptRes.error);
98+
var context := E(KeyString(tableConfig, encryptedItems[x]));
99+
if lastRealError == -1 || error != decryptErrors[lastRealError] {
100+
lastRealError := |decryptErrors|;
101+
decryptErrors := decryptErrors + [error];
102+
}
103+
decryptErrors := decryptErrors + [context];
104+
continue;
105+
}
106+
var decrypted := decryptRes.value;
94107

95108
// If the decrypted result was plaintext, i.e. has no parsedHeader
96109
// then this is expected IFF the table config allows plaintext read
@@ -111,7 +124,9 @@ module QueryTransform {
111124
decryptedItems := decryptedItems + [decrypted.plaintextItem];
112125
}
113126
}
114-
127+
if |decryptErrors| != 0 {
128+
return Failure(CollectionOfErrors(decryptErrors, message := "Error(s) found decrypting Query results."));
129+
}
115130
//= specification/dynamodb-encryption-client/ddb-sdk-integration.md#decrypt-after-query
116131
//# The resulting decrypted response MUST be [filtered](ddb-support.md#queryoutputforbeacons) from the result.
117132
var decryptedOutput := input.sdkOutput.(Items := Some(decryptedItems));

DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/ScanTransform.dfy

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ module ScanTransform {
7979
if keyId.KeyId? {
8080
keyIdUtf8 :- UTF8.Encode(keyId.value).MapFailure(e => E(e));
8181
}
82+
var decryptErrors : seq<Error> := [];
83+
var lastRealError := -1;
84+
8285
for x := 0 to |encryptedItems|
86+
invariant lastRealError == -1 || lastRealError < |decryptErrors|
8387
{
8488
//= specification/dynamodb-encryption-client/ddb-sdk-integration.md#decrypt-after-scan
8589
//# Each of these entries on the original response MUST be replaced
@@ -88,7 +92,17 @@ module ScanTransform {
8892

8993
var decryptInput := EncTypes.DecryptItemInput(encryptedItem := encryptedItems[x]);
9094
var decryptRes := tableConfig.itemEncryptor.DecryptItem(decryptInput);
91-
var decrypted :- MapError(decryptRes);
95+
if decryptRes.Failure? {
96+
var error := AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor(decryptRes.error);
97+
var context := E(KeyString(tableConfig, encryptedItems[x]));
98+
if lastRealError == -1 || error != decryptErrors[lastRealError] {
99+
lastRealError := |decryptErrors|;
100+
decryptErrors := decryptErrors + [error];
101+
}
102+
decryptErrors := decryptErrors + [context];
103+
continue;
104+
}
105+
var decrypted := decryptRes.value;
92106

93107
// If the decrypted result was plaintext, i.e. has no parsedHeader
94108
// then this is expected IFF the table config allows plaintext read
@@ -109,6 +123,9 @@ module ScanTransform {
109123
decryptedItems := decryptedItems + [decrypted.plaintextItem];
110124
}
111125
}
126+
if |decryptErrors| != 0 {
127+
return Failure(CollectionOfErrors(decryptErrors, message := "Error(s) found decrypting Scan results."));
128+
}
112129

113130
//= specification/dynamodb-encryption-client/ddb-sdk-integration.md#decrypt-after-scan
114131
//# The resulting decrypted response MUST be [filtered](ddb-support.md#scanoutputforbeacons) from the result.

0 commit comments

Comments
 (0)