Skip to content

Commit 4ab97bc

Browse files
authored
feat: allow indirect attribute names with MultiKeyStore (#1208)
* feat: allow indirect attribute names with MultiKeyStore
1 parent 31c6b98 commit 4ab97bc

File tree

3 files changed

+94
-4
lines changed

3 files changed

+94
-4
lines changed

DynamoDbEncryption/dafny/DynamoDbEncryption/src/FilterExpr.dfy

+1-1
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ module DynamoDBFilterExpr {
15331533
else
15341534
var name := if names.Some? && attr.value.s in names.value then names.value[attr.value.s] else attr.value.s;
15351535
var keyIdField := bv.keySource.keyLoc.keyName;
1536-
if keyIdField == attr.value.s then
1536+
if keyIdField == name then
15371537
Some(value)
15381538
else
15391539
KeyIdFromPart(bv, keyIdField, attr.value.s, value)

DynamoDbEncryption/dafny/DynamoDbEncryption/test/BeaconTestFixtures.dfy

+37-3
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ module BeaconTestFixtures {
130130
var keyStoreConfig := KTypes.KeyStoreConfig(
131131
id := None,
132132
kmsConfiguration := kmsConfig,
133-
logicalKeyStoreName := "foo",
133+
logicalKeyStoreName := "KeyStoreDdbTable",
134134
grantTokens := None,
135-
ddbTableName := "foo",
135+
ddbTableName := "KeyStoreDdbTable",
136136
ddbClient := Some(ddbClient),
137137
kmsClient := Some(kmsClient)
138138
);
@@ -177,6 +177,24 @@ module BeaconTestFixtures {
177177
);
178178
}
179179

180+
method GetLotsaBeaconsMulti() returns (output : BeaconVersion)
181+
ensures output.keyStore.ValidState()
182+
ensures fresh(output.keyStore.Modifies)
183+
ensures output.version == 1
184+
{
185+
var store := GetKeyStore();
186+
return BeaconVersion (
187+
version := 1,
188+
keyStore := store,
189+
keySource := multi(MultiKeyStore(keyFieldName := "TheKeyField", cacheTTL := 42)),
190+
standardBeacons := [std2, std4, std6, NameTitleBeacon, NameB, TitleB],
191+
compoundBeacons := Some([NameTitle, YearName, Mixed, JustSigned]),
192+
virtualFields := Some([NameTitleField]),
193+
encryptedParts := None,
194+
signedParts := None
195+
);
196+
}
197+
180198
const EmptyTableConfig := DynamoDbTableEncryptionConfig (
181199
logicalTableName := "Foo",
182200
partitionKeyName := "foo",
@@ -200,7 +218,8 @@ module BeaconTestFixtures {
200218
"Title" := SE.ENCRYPT_AND_SIGN,
201219
"TooBad" := SE.ENCRYPT_AND_SIGN,
202220
"Year" := SE.SIGN_ONLY,
203-
"Date" := SE.SIGN_ONLY
221+
"Date" := SE.SIGN_ONLY,
222+
"TheKeyField" := SE.SIGN_ONLY
204223
]
205224
)
206225

@@ -223,6 +242,21 @@ module BeaconTestFixtures {
223242
return SI.KeySource(client, version.keyStore, SI.LiteralLoc(keys), cache, 0);
224243
}
225244

245+
method GetMultiSource(keyName : string, version : BeaconVersion) returns (output : SI.KeySource)
246+
requires version.keyStore.ValidState()
247+
ensures output.ValidState()
248+
ensures version.keyStore == output.store
249+
ensures fresh(output.client.Modifies)
250+
{
251+
var client :- expect Primitives.AtomicPrimitives();
252+
var mpl :- expect MaterialProviders.MaterialProviders();
253+
var input := MPT.CreateCryptographicMaterialsCacheInput(
254+
cache := MPT.Default(Default := MPT.DefaultCache(entryCapacity := 3))
255+
);
256+
var cache :- expect mpl.CreateCryptographicMaterialsCache(input);
257+
return SI.KeySource(client, version.keyStore, SI.MultiLoc(keyName, false), cache, 0);
258+
}
259+
226260
const SimpleItem : DDB.AttributeMap := map[
227261
"std2" := Std2String,
228262
"std4" := Std4String,

DynamoDbEncryption/dafny/DynamoDbEncryption/test/DDBSupport.dfy

+56
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,60 @@ module TestDDBSupport {
3232
expect newItem == SimpleItem + expectedNew;
3333
}
3434

35+
// DynamoDB String :: cast string to DDB.AttributeValue.S
36+
function method DS(x : string) : DDB.AttributeValue
37+
{
38+
DDB.AttributeValue.S(x)
39+
}
40+
41+
method {:test} TestMulti() {
42+
var version := GetLotsaBeaconsMulti();
43+
var src := GetMultiSource("TheKeyField", version);
44+
var bv :- expect ConvertVersionWithSource(FullTableConfig, version, src);
45+
var search := SI.SearchInfo([bv], 0);
46+
var expressionAttributeValues : map<string, AttributeValue> := map[
47+
":value" := DS("0ad21413-51aa-42e1-9c3d-6a4b1edf7e10")
48+
];
49+
var queryInput := DDB.QueryInput (
50+
TableName := "SomeTable",
51+
ExpressionAttributeValues := Some(expressionAttributeValues),
52+
KeyConditionExpression := Some("TheKeyField = :value")
53+
);
54+
var result :- expect QueryInputForBeacons(Some(search), FullTableConfig.attributeActionsOnEncrypt, queryInput);
55+
56+
// Verify Success with branch key id plus beacon
57+
expressionAttributeValues := map[
58+
":value" := DS("0ad21413-51aa-42e1-9c3d-6a4b1edf7e10"),
59+
":other" := DS("junk")
60+
];
61+
queryInput := DDB.QueryInput (
62+
TableName := "foo",
63+
ExpressionAttributeValues := Some(expressionAttributeValues),
64+
KeyConditionExpression := Some("TheKeyField = :value AND std2 = :other")
65+
);
66+
result :- expect QueryInputForBeacons(Some(search), FullTableConfig.attributeActionsOnEncrypt, queryInput);
67+
68+
// Verify Failure with beacon but no branch key id
69+
queryInput := DDB.QueryInput (
70+
TableName := "foo",
71+
ExpressionAttributeValues := Some(expressionAttributeValues),
72+
KeyConditionExpression := Some("std2 = :other")
73+
);
74+
var result2 := QueryInputForBeacons(Some(search), FullTableConfig.attributeActionsOnEncrypt, queryInput);
75+
expect result2 == Failure(AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error.DynamoDbEncryptionException(
76+
message := "Need KeyId because of beacon std2 but no KeyId found in query"));
77+
78+
// Verify Success, even when field names are indirect via ExpressionAttributeNames
79+
var expressionAttributeNames := map[
80+
"#beacon" := "std2",
81+
"#keyfield" := "TheKeyField"
82+
];
83+
queryInput := DDB.QueryInput (
84+
TableName := "foo",
85+
ExpressionAttributeNames := Some(expressionAttributeNames),
86+
ExpressionAttributeValues := Some(expressionAttributeValues),
87+
KeyConditionExpression := Some("#keyfield = :value AND #beacon = :other")
88+
);
89+
result :- expect QueryInputForBeacons(Some(search), FullTableConfig.attributeActionsOnEncrypt, queryInput);
90+
}
3591
}

0 commit comments

Comments
 (0)