@@ -19,6 +19,7 @@ module DynamoDBSupport {
1919 import opened Wrappers
2020 import opened StandardLibrary
2121 import opened StandardLibrary. UInt
22+ import opened StandardLibrary. MemoryMath
2223 import opened DynamoDbEncryptionUtil
2324 import opened DdbVirtualFields
2425 import opened SearchableEncryptionInfo
@@ -33,23 +34,30 @@ module DynamoDBSupport {
3334 // At the moment, this means that no attribute names starts with "aws_dbe_",
3435 // as all other attribute names would need to be configured, and all the
3536 // other weird constraints were checked at configuration time.
36- function method IsWriteable (item : DDB .AttributeMap)
37- : (ret : Result< bool , string > )
37+ method IsWriteable (item : DDB .AttributeMap)
38+ returns (ret : Result< bool , string > )
3839 // = specification/dynamodb-encryption-client/ddb-support.md#writable
3940 // = type=implication
4041 // # Writeable MUST reject any item containing an attribute which begins with `aws_dbe_`.
4142 ensures ret. Success? ==> forall k < - item :: ! (ReservedPrefix <= k)
4243 {
43- if forall k < - item :: ! (ReservedPrefix <= k) then
44- Success (true)
45- else
46- var bad := set k < - item | ReservedPrefix <= k;
47- // We happen to order these values, but this ordering MUST NOT be relied upon.
48- var badSeq := SortedSets. ComputeSetToOrderedSequence2 (bad, CharLess);
49- if |badSeq| == 0 then
50- Failure ("")
51- else
52- Failure ("Writing reserved attributes not allowed : " + Join(badSeq, "\n"))
44+ var keys := SortedSets. ComputeSetToOrderedSequence2 (item.Keys, CharLess);
45+ SequenceIsSafeBecauseItIsInMemory (keys);
46+ var rp := ReservedPrefix; // because the constant ReservedPrefix is actual an expensive function call
47+ for i : uint64 := 0 to |keys| as uint64
48+ invariant forall j | 0 <= j < i :: ! (ReservedPrefix <= keys[j])
49+ {
50+ if rp <= keys[i] {
51+ var result := "Writing reserved attributes not allowed : ";
52+ for j : uint64 := i to |keys| as uint64 {
53+ if rp <= keys[i] {
54+ result := result + keys[i] + "\n";
55+ }
56+ }
57+ return Failure (result);
58+ }
59+ }
60+ return Success (true);
5361 }
5462
5563 function method GetEncryptedAttributes (
@@ -83,7 +91,8 @@ module DynamoDBSupport {
8391 {
8492 if expr. Some? then
8593 var attrs := GetEncryptedAttributes (actions, expr, attrNames);
86- if |attrs| == 0 then
94+ SequenceIsSafeBecauseItIsInMemory (attrs);
95+ if |attrs| as uint64 == 0 then
8796 Success (true)
8897 else
8998 Failure ("Condition Expressions forbidden on encrypted attributes : " + Join(attrs, ","))
@@ -121,7 +130,8 @@ module DynamoDBSupport {
121130 if expr. Some? then
122131 var attrs := Update. ExtractAttributes (expr.value, attrNames);
123132 var encryptedAttrs := Seq. Filter (s => IsSigned(actions, s), attrs);
124- if |encryptedAttrs| == 0 then
133+ SequenceIsSafeBecauseItIsInMemory (encryptedAttrs);
134+ if |encryptedAttrs| as uint64 == 0 then
125135 Success (true)
126136 else
127137 Failure ("Update Expressions forbidden on signed attributes : " + Join(encryptedAttrs, ","))
@@ -169,11 +179,13 @@ module DynamoDBSupport {
169179 // # if the constructed compound beacon does not match
170180 // # the existing attribute value AddSignedBeacons MUST fail.
171181 var badAttrs := set k < - newAttrs | k in item && item[k] != newAttrs[k] :: k;
172- :- Need (|badAttrs| == 0, E("Signed beacons have generated values different from supplied values."));
182+ SetIsSafeBecauseItIsInMemory (badAttrs);
183+ :- Need (|badAttrs| as uint64 == 0, E("Signed beacons have generated values different from supplied values."));
173184 var version : DDB. AttributeMap := map [VersionTag := DS (" ")];
174185 var both := newAttrs. Keys * item. Keys;
175186 var bad := set k < - both | newAttrs[k] != item[k];
176- if 0 < |bad| {
187+ SetIsSafeBecauseItIsInMemory (bad);
188+ if 0 < |bad| as uint64 {
177189 // We happen to order these values, but this ordering MUST NOT be relied upon.
178190 var badSeq := SortedSets. ComputeSetToOrderedSequence2 (bad, CharLess);
179191 return Failure (E("Supplied Beacons do not match calculated beacons : " + Join(badSeq, ", ")));
@@ -254,7 +266,8 @@ module DynamoDBSupport {
254266 req. FilterExpression,
255267 req. ExpressionAttributeNames,
256268 req. ExpressionAttributeValues);
257- :- Need (|newItems| < INT32_MAX_LIMIT, DynamoDbEncryptionUtil.E("This is impossible."));
269+ SequenceIsSafeBecauseItIsInMemory (newItems);
270+ :- Need (|newItems| as uint64 < INT32_MAX_LIMIT as uint64, DynamoDbEncryptionUtil.E("This is impossible."));
258271 var trimmedItems := Seq. Map (i => DoRemoveBeacons(i), newItems);
259272 var count :=
260273 if resp. Count. Some? then
@@ -323,7 +336,8 @@ module DynamoDBSupport {
323336 req. FilterExpression,
324337 req. ExpressionAttributeNames,
325338 req. ExpressionAttributeValues);
326- :- Need (|newItems| < INT32_MAX_LIMIT, DynamoDbEncryptionUtil.E("This is impossible."));
339+ SequenceIsSafeBecauseItIsInMemory (newItems);
340+ :- Need (|newItems| as uint64 < INT32_MAX_LIMIT as uint64, DynamoDbEncryptionUtil.E("This is impossible."));
327341 var trimmedItems := Seq. Map (i => DoRemoveBeacons(i), newItems);
328342 var count :=
329343 if resp. Count. Some? then
@@ -344,14 +358,15 @@ module DynamoDBSupport {
344358 requires forall x < - results :: x in bv. virtualFields
345359 ensures output. Success? ==> forall x < - output. value :: x in bv. virtualFields
346360 {
347- if |fields| == 0 then
361+ SequenceIsSafeBecauseItIsInMemory (fields);
362+ if |fields| as uint64 == 0 then
348363 Success (results)
349364 else
350- var optValue :- GetVirtField (bv.virtualFields[fields[0]], item);
365+ var optValue :- GetVirtField (bv.virtualFields[fields[0 as uint32 ]], item);
351366 if optValue. Some? then
352- GetVirtualFieldsLoop (fields[1..], bv, item, results[fields[0] := optValue.value])
367+ GetVirtualFieldsLoop (fields[1 as uint32 ..], bv, item, results[fields[0 as uint32 ] := optValue.value])
353368 else
354- GetVirtualFieldsLoop (fields[1..], bv, item, results)
369+ GetVirtualFieldsLoop (fields[1 as uint32 ..], bv, item, results)
355370 }
356371
357372 method GetVirtualFields (beaconVersion : SearchableEncryptionInfo .BeaconVersion, item : DDB .AttributeMap)
@@ -371,18 +386,19 @@ module DynamoDBSupport {
371386 requires forall x < - results :: x in bv. beacons
372387 ensures output. Success? ==> forall x < - output. value :: x in bv. beacons
373388 {
374- if |fields| == 0 then
389+ SequenceIsSafeBecauseItIsInMemory (fields);
390+ if |fields| as uint64 == 0 then
375391 Success (results)
376392 else
377- var beacon := bv. beacons[fields[0]];
393+ var beacon := bv. beacons[fields[0 as uint32 ]];
378394 if beacon. Compound? then
379395 var optValue :- beacon. cmp. getNaked (item, bv.virtualFields);
380396 if optValue. Some? then
381- GetCompoundBeaconsLoop (fields[1..], bv, item, results[fields[0] := optValue.value])
397+ GetCompoundBeaconsLoop (fields[1 as uint32 ..], bv, item, results[fields[0] := optValue.value])
382398 else
383- GetCompoundBeaconsLoop (fields[1..], bv, item, results)
399+ GetCompoundBeaconsLoop (fields[1 as uint32 ..], bv, item, results)
384400 else
385- GetCompoundBeaconsLoop (fields[1..], bv, item, results)
401+ GetCompoundBeaconsLoop (fields[1 as uint32 ..], bv, item, results)
386402 }
387403
388404 method GetCompoundBeacons (beaconVersion : SearchableEncryptionInfo .BeaconVersion, item : DDB .AttributeMap)
0 commit comments