Skip to content

Commit 020bc24

Browse files
committed
chore(KSA-Model): more Mutation Operation changes (#955)
Explicitly: - Change InitializeMutationFlag from a union to an enum for ToString reasons - Model `DoNotVersion` flag for Initialize Mutation - Refactor Describe Mutation output to detail Input so resume can be done - Refactor System Key to be optional, detailing that TrustStorage is the default - More errors - Smithy changes from PR feedback on #854 - Correction of spelling mistakes - Mutation Token's UUID is required Why change the flag to an enum? Dafny/Smithy-Dafny's support for Union's results in structures that do not print well. The intention of the `InitializeMutationFlag` is to inform customers about the result of their request. Such information may, possibly even should, be logged. Initialize Mutation and Apply Mutation MUST ensure that the UUID of the Index and Commitment agree. Apply MUST ensure that the UUID of the Commitment and Token agree. The Mutation Token's UUID is REQUIRED. It is how we track a mutation, much like how CFN tracks a change set. Fixed bug where UUID is a reserved word in DDB. Refactored some of the error messages. Utilize Java Example to demonstrate resume and restart. Finally, addressed some of the feedback on PR #854.
1 parent d81be47 commit 020bc24

File tree

81 files changed

+3000
-1802
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+3000
-1802
lines changed

AwsCryptographicMaterialProviders/dafny/AwsCryptographyKeyStore/Model/Storage.smithy

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ list OverWriteEncryptedHierarchicalKeys {
101101
}
102102

103103
@documentation(
104-
"To avoid information loss, overwrites to any itme in the Key Store
104+
"To avoid information loss, overwrites to any item in the Key Store
105105
are done conditioned on the old value.")
106106
structure OverWriteMutationIndex {
107107
@required
@@ -130,22 +130,22 @@ structure MutationCommitment {
130130
UUID: String
131131

132132
@required
133-
@documentation("A commitment of the Original Mutable Properities of the Branch Key.")
133+
@documentation("A commitment of the Original Mutable Properties of the Branch Key.")
134134
Original: Blob
135135

136136
@required
137-
@documentation("A commitment of the Terminal Mutable Properities of the Branch Key.")
137+
@documentation("A commitment of the Terminal Mutable Properties of the Branch Key.")
138138
Terminal: Blob
139139

140140
@required
141-
@documentation("Description of the input to Initizlize Mutation.")
141+
@documentation("Description of the input to initialize a Mutation.")
142142
Input: Blob
143143

144144
@required
145145
CiphertextBlob: Blob
146146
}
147147

148-
@documentation("Information on an in-flight Mutation of a Branch Key.")
148+
@documentation("Information of an in-flight Mutation of a Branch Key.")
149149
structure MutationIndex {
150150
@required
151151
@documentation("The Branch Key under Mutation.")
@@ -256,9 +256,11 @@ operation GetKeyStorageInfo {
256256
}
257257

258258
@documentation(
259-
"Gets the ACTIVE branch key and the beacon key,
260-
and looks for a Mutation Commitment & Index,
261-
returning them if found.")
259+
"Retrieves the items necessary to initialize a Mutation,
260+
while checking for any in-flight Mutations.
261+
These items are the ACTIVE branch key and the beacon key.
262+
If a Mutation is already in-flight for this Branch Key,
263+
the in-flight Mutation's Commitment and Index are also returned.")
262264
operation GetItemsForInitializeMutation {
263265
input: GetItemsForInitializeMutationInput
264266
output: GetItemsForInitializeMutationOutput
@@ -286,7 +288,7 @@ operation WriteInitializeMutation {
286288
@documentation(
287289
"Creates a Mutation Index, conditioned on the Mutation Commitment.
288290
Used in the edge case where the Commitment exists and Index does not.
289-
The Index may have been deleted to restart the mutation from the very begining.
291+
The Index may have been deleted to restart the mutation from the very beginning.
290292
")
291293
operation WriteMutationIndex {
292294
input: WriteMutationIndexInput
@@ -329,9 +331,16 @@ operation QueryForVersions {
329331
in the terminal state of a Mutation,
330332
a page of version (decrypt only) items,
331333
conditioned on:
332-
- every version already exsisting
333-
- every version's enc has not changed
334+
- every version already existing
335+
- every version's cipher-text had not changed
334336
- the Mutation Commitment has not changed
337+
338+
If the Mutation is complete,
339+
the Mutation Index and Mutation Commitment are deleted.
340+
Otherwise,
341+
the Mutation Index is updated,
342+
conditioned on it not having been changed since
343+
it was last read.
335344
")
336345
operation WriteMutatedVersions {
337346
input: WriteMutatedVersionsInput
@@ -509,20 +518,20 @@ structure WriteInitializeMutationInput {
509518
@required
510519
@documentation("
511520
The active representation of this branch key,
512-
generated with the Mutation's terminal properities.
521+
generated with the Mutation's terminal properties.
513522
The plain-text cryptographic material of the Active must be the same as the Version.")
514523
Active: OverWriteEncryptedHierarchicalKey,
515524
@required
516525
@documentation("
517526
The decrypt representation of this branch key version,
518-
generated with the Mutation's terminal properities.
527+
generated with the Mutation's terminal properties.
519528
The plain-text cryptographic material of the `Version` must be the same as the `Active`.")
520529
Version: WriteInitializeMutationVersion,
521530
@required
522531
@documentation("
523532
The mutated HMAC key used to support searchable encryption.
524533
The cryptographic material is identical to the existing beacon,
525-
but is now authorized with the Mutation's terminal properities.")
534+
but is now authorized with the Mutation's terminal properties.")
526535
Beacon: OverWriteEncryptedHierarchicalKey,
527536
@required // Smithy will copy documentation traits from existing shapes
528537
MutationCommitment: MutationCommitment
@@ -543,20 +552,20 @@ structure WriteAtomicMutationInput {
543552
@required
544553
@documentation("
545554
The active representation of this branch key,
546-
generated with the Mutation's terminal properities.
555+
generated with the Mutation's terminal properties.
547556
The plain-text cryptographic material of the Active must be the same as the Version.")
548557
Active: OverWriteEncryptedHierarchicalKey,
549558
@required
550559
@documentation("
551560
The decrypt representation of this branch key version,
552-
generated with the Mutation's terminal properities.
561+
generated with the Mutation's terminal properties.
553562
The plain-text cryptographic material of the `Version` must be the same as the `Active`.")
554563
Version: WriteInitializeMutationVersion,
555564
@required
556565
@documentation("
557566
The mutated HMAC key used to support searchable encryption.
558567
The cryptographic material is identical to the existing beacon,
559-
but is now authorized with the Mutation's terminal properities.")
568+
but is now authorized with the Mutation's terminal properties.")
560569
Beacon: OverWriteEncryptedHierarchicalKey
561570
@documentation(
562571
"List of version (decrypt only) items of a Branch Key to overwrite conditionally.")
@@ -569,9 +578,9 @@ structure QueryForVersionsInput {
569578
@documentation(
570579
"Optional.
571580
If set, Query will start at this index and read forward.
572-
Otherwise, Query will start at the indexes begining.
581+
Otherwise, Query will start at the indexes beginning.
573582
The Default Storage is DDB;
574-
see Amazon DynamoDB's defination of exclusiveStartKey for details.
583+
see Amazon DynamoDB's definition of exclusiveStartKey for details.
575584
Note: While the Default Storage is DDB,
576585
the Key Store transforms the exclusiveStartKey into an opaque representation.")
577586
ExclusiveStartKey: Blob
@@ -588,7 +597,7 @@ structure QueryForVersionsOutput {
588597
"If none-empty, Query did not finish searching storage.
589598
Next Query should resume from here.
590599
The Default Storage is DDB;
591-
see Amazon DynamoDB's defination of exclusiveStartKey for details.
600+
see Amazon DynamoDB's definition of exclusiveStartKey for details.
592601
Note: While the Default Storage is DDB,
593602
the Key Store transforms the exclusiveStartKey into an opaque representation.")
594603
@required

AwsCryptographicMaterialProviders/dafny/AwsCryptographyKeyStore/src/CreateKeys.dfy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,8 @@ module {:options "/functionSyntax:4" } CreateKeys {
542542
);
543543
var overWrite := Types.OverWriteEncryptedHierarchicalKey(
544544
Item := active,
545-
Old := oldActiveItem);
545+
Old := oldActiveItem
546+
);
546547

547548
var _ :- storage.WriteNewEncryptedBranchKeyVersion(
548549
Types.WriteNewEncryptedBranchKeyVersionInput(

AwsCryptographicMaterialProviders/dafny/AwsCryptographyKeyStore/src/DefaultKeyStorageInterface.dfy

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ module DefaultKeyStorageInterface {
3939
map[
4040
"#pk" := Structure.BRANCH_KEY_IDENTIFIER_FIELD,
4141
"#sk" := Structure.TYPE_FIELD]
42+
// Ideally, MAX_PAGE would be Types.UInt.uint8, but the size of sequence is always an int
43+
const DDB_MAX_MUTATION_WRITE_PAGE_SIZE: int := 98
44+
const DDB_MAX_MUTATION_WRITE_PAGE_SIZE_str: string := "98"
4245

4346
datatype ConditionExpression =
4447
| BRANCH_KEY_NOT_EXIST
@@ -49,17 +52,11 @@ module DefaultKeyStorageInterface {
4952
// in the case statement to evaluate a literal.
5053
const MUTATION_COMMITMENT_TYPE := "branch:MUTATION_COMMITMENT" // Structure.MUTATION_COMMITMENT_TYPE
5154
const MUTATION_INDEX_TYPE := "branch:MUTATION_INDEX" // Structure.MUTATION_INDEX_TYPE
52-
// const BRANCH_KEY_ACTIVE_TYPE := "branch:ACTIVE" // Structure.BRANCH_KEY_ACTIVE_TYPE
53-
// const BEACON_KEY_TYPE_VALUE := "beacon:ACTIVE" // Structure.BEACON_KEY_TYPE_VALUE
54-
// const VERSION_TYPE_PREFIX := "branch:version:" // Structure.BRANCH_KEY_TYPE_PREFIX
5555

5656
lemma TypesAreCorrect()
5757
ensures
5858
&& MUTATION_COMMITMENT_TYPE == Structure.MUTATION_COMMITMENT_TYPE
5959
&& MUTATION_INDEX_TYPE == Structure.MUTATION_INDEX_TYPE
60-
// && BRANCH_KEY_ACTIVE_TYPE == Structure.BRANCH_KEY_ACTIVE_TYPE
61-
// && BEACON_KEY_TYPE_VALUE == Structure.BEACON_KEY_TYPE_VALUE
62-
// && VERSION_TYPE_PREFIX == Structure.BRANCH_KEY_TYPE_PREFIX
6360
{}
6461

6562
class {:termination false} DynamoDBKeyStorageInterface
@@ -560,12 +557,12 @@ module DefaultKeyStorageInterface {
560557
return Failure(
561558
Types.KeyStorageException(
562559
message :=
563-
"DDB request to Write Mutated Versions was failed by DDB with TransactionCanceledException. "
560+
"DDB request to Write Mutated Versions failed with DynamoDB's TransactionCanceledException. "
564561
+ "This MAY be caused by a race between hosts mutating the same Branch Key ID. "
565562
+ "The Mutation has NOT completed. "
566563
+ "Table Name: "+ ddbTableName
567564
+ "\tBranch Key ID: " + input.MutationCommitment.Identifier
568-
+ "\tDDB Exception Message: \n" + ddbResponse?.error.Message.UnwrapOr("")));
565+
+ "\tDynamoDB Exception Message: \n" + ddbResponse?.error.Message.UnwrapOr("")));
569566
}
570567
var ddbResponse :- ddbResponse?
571568
.MapFailure(
@@ -580,7 +577,7 @@ module DefaultKeyStorageInterface {
580577
}
581578

582579

583-
method GetMutation' ( input: Types.GetMutationInput )
580+
method {:vcs_split_on_every_assert} GetMutation' ( input: Types.GetMutationInput )
584581
returns (output: Result<Types.GetMutationOutput, Types.Error>)
585582
requires ValidState()
586583
modifies Modifies - {History}
@@ -1260,23 +1257,23 @@ module DefaultKeyStorageInterface {
12601257
));
12611258
}
12621259

1263-
/** Transaction OverWrite up to 99 Decryt Only Items, with a Global Condition on the M-Lock.*/
1260+
/** Transaction OverWrite up to 98 Decryt Only Items,
1261+
with a Global Condition on the M-Commitment.
1262+
The Mutation Index is also updated via an Optimistic Lock.
1263+
If the mutation is complete, the M-Commitment & M-Index are deleted.
1264+
*/
12641265
method WriteMutatedVersions' ( input: Types.WriteMutatedVersionsInput )
12651266
returns (output: Result<Types.WriteMutatedVersionsOutput, Types.Error>)
1266-
requires
1267-
&& ValidState()
1267+
requires && ValidState()
12681268
modifies Modifies - {History}
1269-
// Dafny will skip type parameters when generating a default decreases clause.
12701269
decreases Modifies - {History}
1271-
ensures
1272-
&& ValidState()
1270+
ensures unchanged(History) && ValidState()
12731271
ensures WriteMutatedVersionsEnsuresPublicly(input, output)
1274-
ensures unchanged(History)
12751272
{
12761273
/** Validate Input */
12771274
:- Need(
1278-
|input.Items| < 98,
1279-
Types.KeyStorageException(message:="DynamoDB Encrypted Key Storage can only write page sizes less than 99."
1275+
|input.Items| < DDB_MAX_MUTATION_WRITE_PAGE_SIZE,
1276+
Types.KeyStorageException(message:="DynamoDB Encrypted Key Storage can only write page sizes less than " + DDB_MAX_MUTATION_WRITE_PAGE_SIZE_str + "."
12801277
));
12811278
:- Need(
12821279
0 < |input.MutationCommitment.Original|,
@@ -1607,13 +1604,18 @@ module DefaultKeyStorageInterface {
16071604
"attribute_exists(#pk)"
16081605
+ " AND original = :original"
16091606
+ " AND terminal = :terminal"
1610-
+ " AND " + Structure.ENC_FIELD + " = :encOld",
1611-
ExpressionAttributeNames := map["#pk" := Structure.BRANCH_KEY_IDENTIFIER_FIELD], // "#pk":="branch-key-id"
1607+
+ " AND " + Structure.ENC_FIELD + " = :encOld"
1608+
+ " AND #uuid = :" + Structure.M_UUID,
1609+
ExpressionAttributeNames := map[
1610+
"#pk" := Structure.BRANCH_KEY_IDENTIFIER_FIELD, // "#pk":="branch-key-id"
1611+
"#uuid" := Structure.M_UUID // "#uuid" := "uuid"
1612+
],
16121613
ExpressionAttributeValues :=
16131614
map[
16141615
":original" := DDB.AttributeValue.B(mLock.Original),
16151616
":terminal" := DDB.AttributeValue.B(mLock.Terminal),
1616-
":encOld" := DDB.AttributeValue.B(mLock.CiphertextBlob)
1617+
":encOld" := DDB.AttributeValue.B(mLock.CiphertextBlob),
1618+
":" + Structure.M_UUID := DDB.AttributeValue.S(mLock.UUID)
16171619
]
16181620
)
16191621
}
@@ -1649,12 +1651,17 @@ module DefaultKeyStorageInterface {
16491651
ConditionExpression :=
16501652
"attribute_exists(#pk)"
16511653
+ " AND " + Structure.M_PAGE_INDEX + " = :" + Structure.M_PAGE_INDEX + "Old"
1652-
+ " AND " + Structure.ENC_FIELD + " = :" + Structure.ENC_FIELD + "Old",
1653-
ExpressionAttributeNames := map["#pk" := Structure.BRANCH_KEY_IDENTIFIER_FIELD], // "#pk":="branch-key-id"
1654+
+ " AND " + Structure.ENC_FIELD + " = :" + Structure.ENC_FIELD + "Old"
1655+
+ " AND #uuid = :" + Structure.M_UUID,
1656+
ExpressionAttributeNames := map[
1657+
"#pk" := Structure.BRANCH_KEY_IDENTIFIER_FIELD, // "#pk":="branch-key-id"
1658+
"#uuid" := Structure.M_UUID // "#uuid" := "uuid"
1659+
],
16541660
ExpressionAttributeValues :=
16551661
map[
16561662
":" + Structure.M_PAGE_INDEX + "Old" := DDB.AttributeValue.B(oldIndex.PageIndex),
1657-
":" + Structure.ENC_FIELD + "Old" := DDB.AttributeValue.B(oldIndex.CiphertextBlob)
1663+
":" + Structure.ENC_FIELD + "Old" := DDB.AttributeValue.B(oldIndex.CiphertextBlob),
1664+
":" + Structure.M_UUID := DDB.AttributeValue.S(oldIndex.UUID)
16581665
]
16591666
)
16601667
}

0 commit comments

Comments
 (0)