Skip to content

Commit 4ff8d8c

Browse files
committed
m
1 parent bd5e532 commit 4ff8d8c

File tree

3 files changed

+72
-49
lines changed

3 files changed

+72
-49
lines changed

DynamoDbEncryption/dafny/DynamoDbEncryption/src/ConfigToInfo.dfy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ module SearchConfigToInfo {
141141
&& outer.attributeActionsOnEncrypt[config.multi.keyFieldName] == SE.ENCRYPT_AND_SIGN
142142
==> output.Failure?
143143
{
144-
// TODO-FutureCleanUp : https://github.com/aws/aws-database-encryption-sdk-dynamodb/issues/1510
144+
// FutureCleanUp : https://github.com/aws/aws-database-encryption-sdk-dynamodb/issues/1510
145145
// It is not-good that the MPL is initialized here;
146146
// The MPL has a config object that could hold customer intent that affects behavior.
147147
// Today, it does not. But tomorrow?

DynamoDbEncryption/dafny/DynamoDbEncryption/src/DDBSupport.dfy

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -223,48 +223,62 @@ module DynamoDBSupport {
223223
{
224224
Success(DoRemoveBeacons(item))
225225
}
226+
const BucketName : string := ":aws_dbe_bucket"
226227

227-
// If filter expression is 'bucket=NN ...' return (..., NN)
228-
// else return (None, 0)
229-
function method ExtractBucketNumber(filterExpr : Option<string>) : (Option<string>, uint32)
228+
function method GetNumber(val : DDB.AttributeValue) : Result<uint32, Error>
230229
{
231-
if filterExpr.None? then
232-
(None, 0)
233-
else if "bucket=" < filterExpr.value then
234-
var nFilter := filterExpr.value[7..];
235-
var nDigits := NN.CountDigits(nFilter);
236-
if nDigits == 0 then
237-
(None, 0)
230+
if val.N? then
231+
var val :- NN.StrToInt(val.N).MapFailure(e => E(e));
232+
:- Need(0 <= val < INT32_MAX_LIMIT, E("Value of " + BucketName + " out of range."));
233+
Success(val as uint32)
234+
else
235+
Failure(E("Value of " + BucketName + " is not numeric (i.e. 'N')"))
236+
}
237+
// If names[":aws_dbe_bucket"] holds S(N)' return (Some(names - {":aws_dbe_bucket"}), Some(N))
238+
// else return (None, None)
239+
function method ExtractBucketNumber(names : Option<DDB.ExpressionAttributeValueMap>) : Result<(Option<DDB.ExpressionAttributeValueMap>, Option<uint32>), Error>
240+
{
241+
if names.None? then
242+
Success((None, None))
243+
else if BucketName in names.value then
244+
var val :- GetNumber(names.value[BucketName]);
245+
if |names.value| == 1 then
246+
Success((None, Some(val)))
238247
else
239-
var num := NN.StrToInt(nFilter[..nDigits]);
240-
if num.Failure? then
241-
(None, 0)
242-
else if INT32_MAX_LIMIT < num.value then
243-
(None, 0)
244-
else
245-
(Some(nFilter[nDigits..]), num.value as uint32)
248+
Success((Some(names.value - {BucketName}), Some(val)))
246249
else
247-
(None, 0)
250+
Success((None, None))
248251
}
249252

250253
// Extract aws_dbe_bucket = NN from filterExpr and return bucket
251-
function method ExtractBucket(search : SearchableEncryptionInfo.BeaconVersion, filterExpr : Option<string>)
252-
: Result<(Option<string>, seq<uint8>), Error>
254+
method ExtractBucket(search : SearchableEncryptionInfo.BeaconVersion, keyExpr : Option<string>, filterExpr : Option<string>, names : Option<DDB.ExpressionAttributeNameMap>, values : Option<DDB.ExpressionAttributeValueMap>, actions : AttributeActions)
255+
returns (output : Result<(Option<DDB.ExpressionAttributeValueMap>, seq<uint8>), Error>)
253256
{
254-
if search.numBuckets <= 1 then
255-
Success((filterExpr, []))
256-
else
257-
var (nFilter, bucket) := ExtractBucketNumber(filterExpr);
258-
if nFilter.Some? then
259-
:- Need(bucket < search.numBuckets, E("Bucket number specified in FilterExpression was " + String.Base10Int2String(bucket as int) + "but it must be less than the number of buckets " + String.Base10Int2String(search.numBuckets as int)));
260-
:- Need(bucket < 256, E("Bucket must be less than 256")); // unreachable
261-
if bucket == 0 then
262-
Success((nFilter, []))
263-
else
264-
Success((nFilter, [bucket as uint8]))
265-
else
266-
// TODO - if no encrypted beacons then OK
267-
Failure(E("When numberOfBuckets is greater than one, FilterExpression must start with 'aws_dbe_bucket = NN && '"))
257+
if search.numBuckets <= 1 {
258+
return Success((values, []));
259+
}
260+
261+
var foo :- ExtractBucketNumber(values);
262+
var (nValues, bucket) := foo;
263+
if bucket.Some? {
264+
:- Need(bucket.value < search.numBuckets, E("Bucket number specified in FilterExpression was " + String.Base10Int2String(bucket.value as int) + "but it must be less than the number of buckets " + String.Base10Int2String(search.numBuckets as int)));
265+
:- Need(bucket.value < 256, E("Bucket must be less than 256")); // unreachable
266+
var nbucket := (bucket.value as nat) as uint8;
267+
if nbucket == 0 {
268+
return Success((nValues, []));
269+
} else {
270+
return Success((nValues, [nbucket]));
271+
}
272+
}
273+
// No bucket specified is OK if no encrypted fields are searched
274+
var encrypted := set k <- actions | actions[k] == SE.ENCRYPT_AND_SIGN :: k;
275+
var filterHasEncField := Filter.UsesEncryptedField(Filter.ParseExprOpt(filterExpr), encrypted, names);
276+
var keyHasEncField := Filter.UsesEncryptedField(Filter.ParseExprOpt(keyExpr), encrypted, names);
277+
if keyHasEncField.Some? || filterHasEncField.Some? {
278+
return Failure(E("When numberOfBuckets is greater than one, FilterExpression must start with 'aws_dbe_bucket = NN && '"));
279+
} else {
280+
return Success((values, []));
281+
}
268282
}
269283

270284
// Transform a QueryInput object for searchable encryption.
@@ -283,9 +297,9 @@ module DynamoDBSupport {
283297
} else {
284298
var keyId :- Filter.GetBeaconKeyId(search.value.curr(), req.KeyConditionExpression, req.FilterExpression, req.ExpressionAttributeValues, req.ExpressionAttributeNames);
285299

286-
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression);
287-
var (newFilter, bucket) := foo;
288-
var oldContext := Filter.ExprContext(req.KeyConditionExpression, newFilter, req.ExpressionAttributeValues, req.ExpressionAttributeNames);
300+
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression, req.KeyConditionExpression, req.ExpressionAttributeNames, req.ExpressionAttributeValues, actions);
301+
var (newValues, bucket) := foo;
302+
var oldContext := Filter.ExprContext(req.KeyConditionExpression, req.FilterExpression, newValues, req.ExpressionAttributeNames);
289303
var newContext :- Filter.Beaconize(search.value.curr(), oldContext, keyId, bucket);
290304
return Success(req.(
291305
KeyConditionExpression := newContext.keyExpr,
@@ -307,15 +321,15 @@ module DynamoDBSupport {
307321
var trimmedItems := Seq.Map(i => DoRemoveBeacons(i), resp.Items.value);
308322
return Success(resp.(Items := Some(trimmedItems)));
309323
} else {
310-
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression);
311-
var (newFilter, bucket) := foo;
324+
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression, req.KeyConditionExpression, req.ExpressionAttributeNames, req.ExpressionAttributeValues, map[]);
325+
var (newValues, bucket) := foo;
312326
var newItems :- Filter.FilterResults(
313327
search.value.curr(),
314328
resp.Items.value,
315329
req.KeyConditionExpression,
316-
newFilter,
330+
req.FilterExpression,
317331
req.ExpressionAttributeNames,
318-
req.ExpressionAttributeValues,
332+
newValues,
319333
bucket);
320334
SequenceIsSafeBecauseItIsInMemory(newItems);
321335
:- Need(|newItems| as uint64 < INT32_MAX_LIMIT as uint64, DynamoDbEncryptionUtil.E("This is impossible."));
@@ -359,9 +373,9 @@ module DynamoDBSupport {
359373
return Success(req);
360374
} else {
361375
var keyId :- Filter.GetBeaconKeyId(search.value.curr(), None, req.FilterExpression, req.ExpressionAttributeValues, req.ExpressionAttributeNames);
362-
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression);
363-
var (newFilter, bucket) := foo;
364-
var context := Filter.ExprContext(None, newFilter, req.ExpressionAttributeValues, req.ExpressionAttributeNames);
376+
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression, None, req.ExpressionAttributeNames, req.ExpressionAttributeValues, actions);
377+
var (newValues, bucket) := foo;
378+
var context := Filter.ExprContext(None, req.FilterExpression, newValues, req.ExpressionAttributeNames);
365379
var newContext :- Filter.Beaconize(search.value.curr(), context, keyId, bucket);
366380
return Success(req.(
367381
FilterExpression := newContext.filterExpr,
@@ -382,15 +396,15 @@ module DynamoDBSupport {
382396
var trimmedItems := Seq.Map(i => DoRemoveBeacons(i), resp.Items.value);
383397
return Success(resp.(Items := Some(trimmedItems)));
384398
} else {
385-
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression);
386-
var (newFilter, bucket) := foo;
399+
var foo :- ExtractBucket(search.value.curr(), req.FilterExpression, None, req.ExpressionAttributeNames, req.ExpressionAttributeValues, map[]);
400+
var (newValues, bucket) := foo;
387401
var newItems :- Filter.FilterResults(
388402
search.value.curr(),
389403
resp.Items.value,
390404
None,
391-
newFilter,
405+
req.FilterExpression,
392406
req.ExpressionAttributeNames,
393-
req.ExpressionAttributeValues,
407+
newValues,
394408
bucket);
395409
SequenceIsSafeBecauseItIsInMemory(newItems);
396410
:- Need(|newItems| as uint64 < INT32_MAX_LIMIT as uint64, DynamoDbEncryptionUtil.E("This is impossible."));

DynamoDbEncryption/dafny/DynamoDbEncryption/src/FilterExpr.dfy

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,15 @@ module DynamoDBFilterExpr {
677677
if 0 < tup.0 then [tup.1] + ParseExpr(s, Add(pos, tup.0)) else []
678678
}
679679

680+
function method {:tailrecursion} ParseExprOpt(s: Option<string>) : (res: seq<Token>)
681+
ensures s.None? || s.value == [] ==> res == []
682+
{
683+
if s.None? then
684+
[]
685+
else
686+
ParseExpr(s.value)
687+
}
688+
680689
// convert ch to lower case
681690
function method ByteLower(ch: uint8): uint8
682691
{

0 commit comments

Comments
 (0)