1+ // Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+ // SPDX-License-Identifier: Apache-2.0
3+
4+ include ".. / src/ Index. dfy"
5+
6+ // methods to validate a Get* Branch Key result from the Branch Key Store client
7+ module {:options "/ functionSyntax:4" } BranchKeyValidators {
8+ import opened Wrappers
9+ import opened StandardLibrary. UInt
10+ import UTF8
11+ import UUID
12+ import Types = AwsCryptographyKeyStoreTypes
13+ import Structure
14+
15+ method VerifyGetKeys (
16+ identifier : string ,
17+ keyStore : Types .IKeyStoreClient,
18+ storage : Types .IKeyStorageInterface,
19+ nameonly versionUtf8Bytes?: Option <seq <uint8>> := None,
20+ nameonly encryptionContext : Types .EncryptionContext := map[],
21+ nameonly hierarchyVersion : Types .HierarchyVersion := Types.HierarchyVersion.v1
22+ )
23+ requires
24+ keyStore. ValidState () && storage. ValidState ()
25+ modifies
26+ keyStore. Modifies, storage. Modifies
27+ ensures
28+ keyStore. ValidState () && storage. ValidState ()
29+
30+ {
31+ var _ := testBeaconKeyHappyCase (
32+ keyStore := keyStore,
33+ branchKeyId := identifier,
34+ encryptionContext := encryptionContext
35+ );
36+
37+ var activeResult := testActiveBranchKeyHappyCase (
38+ keyStore := keyStore,
39+ branchKeyId := identifier,
40+ encryptionContext := encryptionContext
41+ );
42+ var versionString :- expect UTF8. Decode (activeResult.branchKeyVersion);
43+
44+ var _ := testBranchKeyVersionHappyCase (
45+ keyStore := keyStore,
46+ branchKeyId := identifier,
47+ branchKeyIdActiveVersion := versionString,
48+ branchKeyIdActiveVersionUtf8Bytes := activeResult.branchKeyVersion,
49+ encryptionContext := encryptionContext
50+ );
51+ VerifyGetKeysFromStorage (identifier, storage, hierarchyVersion:=hierarchyVersion);
52+
53+ // = aws-encryption-sdk-specification/framework/branch-key-store.md#branch-key-and-beacon-key-creation
54+ // = type=test
55+ // # This guid MUST be [version 4 UUID](https://www.ietf.org/rfc/rfc4122.txt)
56+ var versionByteUUID :- expect UUID. ToByteArray (versionString);
57+ var versionRoundTrip :- expect UUID. FromByteArray (versionByteUUID);
58+ expect versionRoundTrip == versionString;
59+ }
60+
61+
62+ method VerifyGetKeysFromStorage (
63+ identifier : string ,
64+ storage : Types .IKeyStorageInterface,
65+ nameonly hierarchyVersion : Types .HierarchyVersion := Types.HierarchyVersion.v1
66+ )
67+ requires storage. ValidState ()
68+ modifies storage. Modifies
69+ ensures storage. ValidState ()
70+ {
71+ var active :- expect storage. GetEncryptedActiveBranchKey (
72+ Types.GetEncryptedActiveBranchKeyInput(
73+ Identifier := identifier
74+ )
75+ );
76+ expect active. Item. Type. ActiveHierarchicalSymmetricVersion?;
77+
78+ var beacon :- expect storage. GetEncryptedBeaconKey (
79+ Types.GetEncryptedBeaconKeyInput(
80+ Identifier := identifier
81+ )
82+ );
83+ expect beacon. Item. Type. ActiveHierarchicalSymmetricBeacon?;
84+
85+ var version :- expect storage. GetEncryptedBranchKeyVersion (
86+ Types.GetEncryptedBranchKeyVersionInput(
87+ Identifier := identifier,
88+ Version := active.Item.Type.ActiveHierarchicalSymmetricVersion.Version
89+ )
90+ );
91+ expect version. Item. Type. HierarchicalSymmetricVersion?;
92+
93+ var hvMatches? := match hierarchyVersion {
94+ case v1
95+ =>
96+ && branchKeyContextSaysHV1 (active.Item.EncryptionContext)
97+ && branchKeyContextSaysHV1 (beacon.Item.EncryptionContext)
98+ && branchKeyContextSaysHV1 (version.Item.EncryptionContext)
99+ case v2
100+ =>
101+ && branchKeyContextSaysHV2 (active.Item.EncryptionContext)
102+ && branchKeyContextSaysHV2 (beacon.Item.EncryptionContext)
103+ && branchKeyContextSaysHV2 (version.Item.EncryptionContext)
104+ };
105+ if (! hvMatches?) {
106+ print "HV did not match expectation, did bkc have hv?: ", Structure. HIERARCHY_VERSION in active. Item. EncryptionContext;
107+ if (Structure. HIERARCHY_VERSION in active. Item. EncryptionContext) {
108+ print " Actual HV: ", active. Item. EncryptionContext[Structure. HIERARCHY_VERSION];
109+ }
110+ }
111+ expect hvMatches?, "Hierarchy Version did not match expectation. ";
112+
113+ // = aws-encryption-sdk-specification/framework/branch-key-store.md#branch-key-and-beacon-key-creation
114+ // = type=test
115+ // # This timestamp MUST be in ISO 8601 format in UTC, to microsecond precision (e.g. “YYYY-MM-DDTHH:mm:ss.ssssssZ“)
116+ expect ISO8601?(active. Item. CreateTime);
117+ expect ISO8601?(beacon. Item. CreateTime);
118+ expect ISO8601?(version. Item. CreateTime);
119+ }
120+
121+ predicate branchKeyContextSaysHV1 (bkc: Types .EncryptionContextString)
122+ {
123+ Structure. HIERARCHY_VERSION in bkc && bkc[Structure. HIERARCHY_VERSION] == Structure. HIERARCHY_VERSION_VALUE_1
124+ }
125+
126+ predicate branchKeyContextSaysHV2 (bkc: Types .EncryptionContextString)
127+ {
128+ Structure. HIERARCHY_VERSION in bkc && bkc[Structure. HIERARCHY_VERSION] == Structure. HIERARCHY_VERSION_VALUE_2
129+ }
130+
131+ method testActiveBranchKeyHappyCase (
132+ keyStore: Types .IKeyStoreClient,
133+ branchKeyId: string ,
134+ nameonly versionUtf8Bytes?: Option <seq <uint8>> := None,
135+ nameonly encryptionContext : Types .EncryptionContext := map[]
136+ ) returns (output: Types. BranchKeyMaterials)
137+ requires keyStore. ValidState ()
138+ modifies keyStore. Modifies
139+ ensures keyStore. ValidState ()
140+ {
141+ var activeResult :- expect keyStore. GetActiveBranchKey (
142+ Types.GetActiveBranchKeyInput(
143+ branchKeyIdentifier := branchKeyId
144+ ));
145+ expect isValidActiveBranchKeyResult?(activeResult, branchKeyId, encryptionContext, versionUtf8Bytes?);
146+ return activeResult. branchKeyMaterials;
147+ }
148+
149+ method testBranchKeyVersionHappyCase (
150+ keyStore: Types .IKeyStoreClient,
151+ branchKeyId: string ,
152+ branchKeyIdActiveVersion: string ,
153+ branchKeyIdActiveVersionUtf8Bytes: seq <uint8 >,
154+ nameonly encryptionContext : Types .EncryptionContext := map[]
155+ ) returns (output: Types. BranchKeyMaterials)
156+ requires keyStore. ValidState ()
157+ modifies keyStore. Modifies
158+ ensures keyStore. ValidState ()
159+ {
160+ var versionResult :- expect keyStore. GetBranchKeyVersion (
161+ Types.GetBranchKeyVersionInput(
162+ branchKeyIdentifier := branchKeyId,
163+ branchKeyVersion := branchKeyIdActiveVersion
164+ ));
165+ expect isValidBranchKeyVersionResult?(versionResult, branchKeyId, encryptionContext, branchKeyIdActiveVersionUtf8Bytes);
166+ return versionResult. branchKeyMaterials;
167+ }
168+
169+ method testBeaconKeyHappyCase (
170+ keyStore: Types .IKeyStoreClient,
171+ branchKeyId: string ,
172+ nameonly encryptionContext : Types .EncryptionContext := map[]
173+ ) returns (output: Types. BeaconKeyMaterials)
174+ requires keyStore. ValidState ()
175+ modifies keyStore. Modifies
176+ ensures keyStore. ValidState ()
177+ {
178+ var beaconKeyResult :- expect keyStore. GetBeaconKey (
179+ Types.GetBeaconKeyInput(
180+ branchKeyIdentifier := branchKeyId
181+ ));
182+ expect beaconKeyResult. beaconKeyMaterials. beaconKeyIdentifier == branchKeyId, "Wrong Branch Key ID. ";
183+ expect beaconKeyResult. beaconKeyMaterials. beaconKey. Some?, "Beacon Key Materials MUST be present. ";
184+ expect |beaconKeyResult. beaconKeyMaterials. beaconKey. value| == 32, "Lenght of Beacon Key Materials MUST be 32 bytes. ";
185+ if (beaconKeyResult. beaconKeyMaterials. encryptionContext != encryptionContext) {
186+ print "Beacon Key's encryption context is incorrect. Expected: ", encryptionContext, " but got: ", beaconKeyResult. beaconKeyMaterials. encryptionContext;
187+ expect false , "Beacon Key's encryption context is incorrect. ";
188+ }
189+ expect isValidBeaconResult?(beaconKeyResult, branchKeyId, encryptionContext);
190+ return beaconKeyResult. beaconKeyMaterials;
191+ }
192+
193+ predicate isValidBeaconResult?(
194+ beaconKeyResult: Types. GetBeaconKeyOutput,
195+ branchKeyId: string ,
196+ encryptionContext : Types. EncryptionContext
197+ ) {
198+ && beaconKeyResult. beaconKeyMaterials. beaconKeyIdentifier == branchKeyId
199+ && beaconKeyResult. beaconKeyMaterials. beaconKey. Some?
200+ && |beaconKeyResult. beaconKeyMaterials. beaconKey. value| == 32
201+ && beaconKeyResult. beaconKeyMaterials. encryptionContext == encryptionContext
202+ }
203+
204+ predicate isValidActiveBranchKeyResult?(
205+ branchKeyResult: Types. GetActiveBranchKeyOutput,
206+ branchKeyId: string ,
207+ encryptionContext : Types. EncryptionContext,
208+ branchKeyIdActiveVersionUtf8Bytes: Option< seq < uint8>>
209+ )
210+ {
211+ && branchKeyResult. branchKeyMaterials. branchKeyIdentifier == branchKeyId
212+ && (branchKeyIdActiveVersionUtf8Bytes. None? ||
213+ branchKeyResult. branchKeyMaterials. branchKeyVersion == branchKeyIdActiveVersionUtf8Bytes. value)
214+ && |branchKeyResult. branchKeyMaterials. branchKey| == 32
215+ && branchKeyResult. branchKeyMaterials. encryptionContext == encryptionContext
216+ }
217+
218+ predicate isValidBranchKeyVersionResult?(
219+ versionResult: Types. GetBranchKeyVersionOutput,
220+ branchKeyId: string ,
221+ encryptionContext : Types. EncryptionContext,
222+ branchKeyIdActiveVersionUtf8Bytes: seq < uint8>
223+ )
224+ {
225+ && versionResult. branchKeyMaterials. branchKeyIdentifier == branchKeyId
226+ && versionResult. branchKeyMaterials. branchKeyVersion == branchKeyIdActiveVersionUtf8Bytes
227+ && |versionResult. branchKeyMaterials. branchKey| == 32
228+ && versionResult. branchKeyMaterials. encryptionContext == encryptionContext
229+ }
230+
231+ // = aws-encryption-sdk-specification/framework/branch-key-store.md#branch-key-and-beacon-key-creation
232+ // = type=test
233+ // # This timestamp MUST be in ISO 8601 format in UTC, to microsecond precision (e.g. “YYYY-MM-DDTHH:mm:ss.ssssssZ“)
234+ lemma ISO8601Test ()
235+ {
236+ assert ISO8601?("2024- 08- 06T17:23:25. 000874Z");
237+ }
238+
239+ // = aws-encryption-sdk-specification/framework/branch-key-store.md#branch-key-and-beacon-key-creation
240+ // = type=test
241+ // # This timestamp MUST be in ISO 8601 format in UTC, to microsecond precision (e.g. “YYYY-MM-DDTHH:mm:ss.ssssssZ“)
242+ predicate ISO8601?(
243+ CreateTime: string
244+ )
245+ {
246+ // “YYYY-MM-DDTHH:mm:ss.ssssssZ“
247+ && |CreateTime| == 27
248+ && CreateTime[4] == '- '
249+ && CreateTime[7] == '- '
250+ && CreateTime[10] == 'T'
251+ && CreateTime[13] == ':'
252+ && CreateTime[16] == ':'
253+ && CreateTime[19] == '. '
254+ && CreateTime[26] == 'Z'
255+ }
256+ }
0 commit comments