@@ -28,7 +28,6 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
2828 import JSON. API
2929 import opened JSONHelpers
3030 import Norm = DynamoDbNormalizeNumber
31-
3231 import Types = AwsCryptographyDbEncryptionSdkDynamoDbTypes
3332 import DDB = ComAmazonawsDynamodbTypes
3433 import Filter = DynamoDBFilterExpr
@@ -37,10 +36,15 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
3736 import KeyMaterial
3837 import UTF8
3938 import KeyVectorsTypes = AwsCryptographyMaterialProvidersTestVectorKeysTypes
39+ import CMP = AwsCryptographyMaterialProvidersTypes
4040 import KeyVectors
4141 import CreateInterceptedDDBClient
4242 import SortedSets
4343 import Seq
44+ import SI = SearchableEncryptionInfo
45+ import MaterialProviders
46+ import MPT = AwsCryptographyMaterialProvidersTypes
47+ import Aws. Cryptography. Primitives
4448
4549 predicate IsValidInt32 (x: int ) { - 0x8000_0000 <= x < 0x8000_0000}
4650 type ConfigName = string
@@ -121,7 +125,8 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
121125 configsForModTest : PairList ,
122126 writeTests : seq <WriteTest >,
123127 roundTripTests : seq <RoundTripTest >,
124- decryptTests : seq <DecryptTest >
128+ decryptTests : seq <DecryptTest >,
129+ strings : seq <string >
125130 ) {
126131
127132 method RunAllTests ()
@@ -137,13 +142,15 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
137142 print |ioTests|, " ioTests. \n";
138143 print |configsForIoTest|, " configsForIoTest. \n";
139144 print |configsForModTest|, " configsForModTest. \n";
145+ print |strings|, " strings. \n";
140146 if |roundTripTests| != 0 {
141147 print |roundTripTests[0]. configs|, " configs and ", |roundTripTests[0]. records|, " records for round trip. \n";
142148 }
143149 if |roundTripTests| > 1 {
144150 print |roundTripTests[1]. configs|, " configs and ", |roundTripTests[1]. records|, " records for round trip. \n";
145151 }
146152 Validate ();
153+ StringOrdering ();
147154 BasicIoTest ();
148155 RunIoTests ();
149156 BasicQueryTest ();
@@ -156,6 +163,35 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
156163 DeleteTable (client);
157164 }
158165
166+ function NewOrderRecord (i : nat , str : string ) : Record
167+ {
168+ var n := String. Base10Int2String (i);
169+ var m : DDB. AttributeMap := map [HashName := DDB. AttributeValue. N (n), "StrValue" := DDB. AttributeValue. S (str)];
170+ Record (i, m)
171+ }
172+
173+ method StringOrdering () {
174+ print "StringOrdering\n";
175+ var client :- expect CreateInterceptedDDBClient. CreateVanillaDDBClient ();
176+ var records : seq < Record> := [];
177+ for i := 0 to |strings| {
178+ records := records + [NewOrderRecord (i, strings[i])];
179+ }
180+ WriteAllRecords (client, records);
181+ var subRecords := Seq. Map ((r : Record ) => r. item, records);
182+ var ops := ["< ", "<= ", "> ", ">= ", "=", "<> "];
183+ for i := 0 to |strings| {
184+ for j := 0 to |ops| {
185+ var expr := Some ("StrValue " + ops[j] + " :val ");
186+ var vals := Some (map[":val " := DDB.AttributeValue.S(strings[i])]);
187+ var query := SimpleQuery (None, None, expr, []);
188+ var items1 := FullScan (client, query, Some(map[]), vals);
189+ var bv :- expect GetFakeBeaconVersion ();
190+ var items2 :- expect Filter. FilterResults (bv, subRecords, None, expr, None, vals);
191+ CompareRecordsDisordered2 (items1, items2);
192+ }
193+ }
194+ }
159195
160196 method Validate () {
161197 var bad := false ;
@@ -531,7 +567,11 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
531567 }
532568 }
533569
534- method OneRoundTripTest (client : DDB .IDynamoDBClient, record : Record ) {
570+ method OneRoundTripTest (client : DDB .IDynamoDBClient, record : Record )
571+ requires client. ValidState ()
572+ ensures client. ValidState ()
573+ modifies client. Modifies
574+ {
535575 var putInput := DDB. PutItemInput (
536576 TableName := TableName,
537577 Item := record.item,
@@ -545,7 +585,7 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
545585 ExpressionAttributeValues := None
546586 );
547587 var _ :- expect client. PutItem (putInput);
548-
588+ expect HashName in record . item;
549589 var getInput := DDB. GetItemInput (
550590 TableName := TableName,
551591 Key := map[HashName := record.item[HashName]],
@@ -772,6 +812,19 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
772812 }
773813 expect ! bad;
774814 }
815+ method CompareRecordsDisordered2 (expected : DDB .ItemList, actual : DDB .ItemList)
816+ {
817+ expect |expected| == |actual|;
818+ var bad := false ;
819+ for i := 0 to |expected| {
820+ var found := FindMatchingRecord (expected[i], actual);
821+ if ! found {
822+ print "Did not find result for record ", expected[i], "\n";
823+ bad := true ;
824+ }
825+ }
826+ expect ! bad;
827+ }
775828
776829 method BasicIoTestScan (client : DDB .IDynamoDBClient, records : seq <Record >)
777830 requires client. ValidState ()
@@ -863,9 +916,11 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
863916 var asSet := Seq. ToSet (s);
864917 DDB. AttributeValue. BS (SortedSets.ComputeSetToOrderedSequence2(asSet, ByteLess))
865918 case L (list) =>
866- DDB. AttributeValue. L (Seq.Map(n => Normalize(n), list))
919+ // for some reason, Seq.Map() fails for verify, even when revealed
920+ var value := seq (|list|, i requires 0 <= i < |list| => Normalize(list[i]));
921+ DDB. AttributeValue. L (value)
867922 case M (m) =>
868- DDB. AttributeValue. M (map k <- m :: k := Normalize(m[k]))
923+ DDB. AttributeValue. M (map k <- m :: k := Normalize(m[k]))
869924 case _ => value
870925 }
871926 }
@@ -1047,7 +1102,7 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
10471102
10481103 function MakeEmptyTestVector () : TestVectorConfig
10491104 {
1050- TestVectorConfig (MakeCreateTableInput(), [], map [], [], map [], map [], [], [], [], [], [], [], [], [])
1105+ TestVectorConfig (MakeCreateTableInput(), [], map [], [], map [], map [], [], [], [], [], [], [], [], [], [] )
10511106 }
10521107
10531108 method ParseTestVector (data : JSON , prev : TestVectorConfig ) returns (output : Result< TestVectorConfig, string > )
@@ -1067,6 +1122,7 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
10671122 var writeTests : seq < WriteTest> := [];
10681123 var roundTripTests : seq < RoundTripTest> := [];
10691124 var decryptTests : seq < DecryptTest> := [];
1125+ var strings : seq < string > := [];
10701126
10711127 for i := 0 to |data. obj| {
10721128 match data. obj[i]. 0 {
@@ -1084,6 +1140,7 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
10841140 case "WriteTests" => writeTests :- GetWriteTests (data.obj[i].1);
10851141 case "RoundTripTest" => roundTripTests :- GetRoundTripTests (data.obj[i].1);
10861142 case "DecryptTests" => decryptTests :- GetDecryptTests (data.obj[i].1);
1143+ case "Strings" => strings :- GetStrings (data.obj[i].1);
10871144 case _ => return Failure ("Unexpected top level tag " + data.obj[i].0);
10881145 }
10891146 }
@@ -1104,7 +1161,8 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
11041161 configsForModTest := prev.configsForModTest + queryPairs,
11051162 writeTests := prev.writeTests + writeTests,
11061163 roundTripTests := prev.roundTripTests + roundTripTests,
1107- decryptTests := prev.decryptTests + decryptTests
1164+ decryptTests := prev.decryptTests + decryptTests,
1165+ strings := prev.strings + strings
11081166 )
11091167 );
11101168 }
@@ -1207,6 +1265,10 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
12071265 method GetOneTableConfig (name : string , data : JSON ) returns (output : Result< TableConfig, string > )
12081266 {
12091267 :- Need (data.Object?, "A Table Config must be an object.");
1268+ var logicalTableName := TableName;
1269+ var partitionKeyName : DDB. KeySchemaAttributeName := HashName;
1270+ var sortKeyName : Option< DDB. KeySchemaAttributeName> := None;
1271+ var algorithmSuiteId : Option< CMP. DBEAlgorithmSuiteId> := None;
12101272 var encrypt : seq < string > := [];
12111273 var attributeActionsOnEncrypt : Types. AttributeActions := map [];
12121274 var allowed : seq < DDB. AttributeName> := [];
@@ -1216,13 +1278,47 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
12161278 var virtualFields : seq < Types. VirtualField> := [];
12171279 var keySource : Option< Types. BeaconKeySource> := None;
12181280 var search : Option< Types. SearchConfig> := None;
1281+ var legacyOverride: Option< Types. LegacyOverride> := None;
1282+ var plaintextOverride: Option< Types. PlaintextOverride> := None;
12191283
12201284 for i := 0 to |data. obj| {
12211285 var obj := data. obj[i];
12221286 match obj. 0 {
1287+ case "logicalTableName" =>
1288+ :- Need (obj.1.String?, "logicalTableName must be of type String.");
1289+ logicalTableName := obj. 1. str;
1290+ case "partitionKeyName" =>
1291+ :- Need (obj.1.String?, "partitionKeyName must be of type String.");
1292+ :- Need (DDB.IsValid_KeySchemaAttributeName(obj.1.str), "partitionKeyName '" + obj. 1. str + "' is not a valid KeySchemaAttributeName. ");
1293+ partitionKeyName := obj. 1. str;
1294+ case "sortKeyName" =>
1295+ :- Need (obj.1.String?, "sortKeyName must be of type String.");
1296+ :- Need (DDB.IsValid_KeySchemaAttributeName(obj.1.str), "sortKeyName '" + obj. 1. str + "' is not a valid KeySchemaAttributeName. ");
1297+ sortKeyName := Some (obj.1.str);
1298+ case "algorithmSuiteId" =>
1299+ :- Need (obj.1.String?, "algorithmSuiteId must be of type String.");
1300+ if obj. 1. str == "ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384" {
1301+ algorithmSuiteId := Some (CMP.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384);
1302+ } else if obj. 1. str == "ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384" {
1303+ algorithmSuiteId := Some (CMP.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384);
1304+ } else {
1305+ return Failure ("algorithmSuiteId '" + obj.1.str + "' must be either ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384 or ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384");
1306+ }
1307+ case "plaintextOverride" =>
1308+ :- Need (obj.1.String?, "plaintextOverride must be of type String.");
1309+ if obj. 1. str == "FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ" {
1310+ plaintextOverride := Some (Types.FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ);
1311+ } else if obj. 1. str == "FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ" {
1312+ plaintextOverride := Some (Types.FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ);
1313+ } else if obj. 1. str == "FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ" {
1314+ plaintextOverride := Some (Types.FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ);
1315+ } else {
1316+ return Failure ("plaintextOverride '" + obj.1.str + "' must be one of FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ, FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ or FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ");
1317+ }
1318+
12231319 case "attributeActionsOnEncrypt" => attributeActionsOnEncrypt :- GetAttributeActions (obj.1);
12241320 case "allowedUnsignedAttributePrefix" =>
1225- :- Need (obj.1.String?, "Prefix must be of type String.");
1321+ :- Need (obj.1.String?, "allowedUnsignedAttributePrefix must be of type String.");
12261322 prefix := obj. 1. str;
12271323 case "allowedUnsignedAttributes" => allowed :- GetAttrNames (obj.1);
12281324 case "search" => var src :- GetOneSearchConfig (obj.1); search := Some (src);
@@ -1242,18 +1338,18 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
12421338
12431339 var config :=
12441340 Types. DynamoDbTableEncryptionConfig (
1245- logicalTableName := TableName ,
1246- partitionKeyName := HashName ,
1247- sortKeyName := None ,
1341+ logicalTableName := logicalTableName ,
1342+ partitionKeyName := partitionKeyName ,
1343+ sortKeyName := sortKeyName ,
12481344 search := search,
12491345 attributeActionsOnEncrypt := attributeActionsOnEncrypt,
12501346 allowedUnsignedAttributes := OptSeq(allowed),
12511347 allowedUnsignedAttributePrefix := OptSeq (prefix),
1252- algorithmSuiteId := None ,
1348+ algorithmSuiteId := algorithmSuiteId ,
12531349 keyring := Some (keyring),
12541350 cmm := None,
1255- legacyOverride := None ,
1256- plaintextOverride := None
1351+ legacyOverride := legacyOverride ,
1352+ plaintextOverride := plaintextOverride
12571353 );
12581354 return Success (TableConfig(name, config, |data.obj| == 0));
12591355 }
@@ -1327,6 +1423,32 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
13271423 );
13281424 }
13291425
1426+ method GetFakeBeaconVersion () returns (output : Result< SI. BeaconVersion, string > )
1427+ ensures output. Success? ==> output. value. ValidState () && fresh (output. value. Modifies ())
1428+ {
1429+ var keyMaterial : KeyMaterial. KeyMaterial :=
1430+ KeyMaterial. StaticKeyStoreInformation ("abc", UTF8.EncodeAscii("abc"), [1,2,3,4,5], [1,2,3,4,5]);
1431+ var store := SKS. CreateStaticKeyStore (keyMaterial);
1432+ var source : Types. BeaconKeySource := Types. single (Types.SingleKeyStore(keyId := "foo", cacheTTL := 42));
1433+
1434+ var sb := Types. StandardBeacon (name := "name", length := 5 as Types.BeaconBitLength, loc := None, style := None);
1435+
1436+ var mpl :- expect MaterialProviders. MaterialProviders ();
1437+
1438+ var cacheType : MPT. CacheType := MPT. Default (Default := MPT.DefaultCache(entryCapacity := 1));
1439+
1440+ var input := MPT. CreateCryptographicMaterialsCacheInput (
1441+ cache := cacheType
1442+ );
1443+ var cache :- expect mpl. CreateCryptographicMaterialsCache (input);
1444+
1445+ var client :- expect Primitives. AtomicPrimitives ();
1446+ var src := SI. KeySource (client, store, SI.SingleLoc("foo"), cache, 100 as uint32);
1447+
1448+ var bv :- expect SI. MakeBeaconVersion (1, src, map[], map[], map[]);
1449+ return Success (bv);
1450+ }
1451+
13301452 method GetAttributeActions (data : JSON ) returns (output : Result< Types. AttributeActions, string > )
13311453 {
13321454 :- Need (data.Object?, "attributeActionsOnEncrypt must be an object");
0 commit comments