@@ -12,50 +12,15 @@ import {
12
12
} from '@aws-crypto/material-management'
13
13
import { v4 } from 'uuid'
14
14
import {
15
- constructAuthenticatedEncryptionContext ,
16
15
constructBranchKeyMaterials ,
17
16
decryptBranchKey ,
18
- getBranchKeyItem ,
19
- validateBranchKeyRecord ,
20
17
} from './branch_keystore_helpers'
21
- import {
22
- BRANCH_KEY_ACTIVE_TYPE ,
23
- BRANCH_KEY_TYPE_PREFIX ,
24
- KMS_CLIENT_USER_AGENT ,
25
- } from './constants'
26
-
27
- //= aws-encryption-sdk-specification/framework/branch-key-store.md#initialization
28
- //# The following inputs MAY be specified to create a KeyStore:
29
-
30
- //# - [ID](#keystore-id)
31
- //# - [AWS KMS Grant Tokens](#aws-kms-grant-tokens)
32
- //# - [DynamoDb Client](#dynamodb-client)
33
- //# - [KMS Client](#kms-client)
34
-
35
- //# The following inputs MUST be specified to create a KeyStore:
36
-
37
- //# - [Table Name](#table-name)
38
- //# - [AWS KMS Configuration](#aws-kms-configuration)
39
- //# - [Logical KeyStore Name](#logical-keystore-name)
40
- export interface BranchKeyStoreNodeInput {
41
- ddbTableName : string
42
- logicalKeyStoreName : string
43
- kmsConfiguration : KmsConfig
44
- kmsClient ?: KMSClient
45
- ddbClient ?: DynamoDBClient
46
- keyStoreId ?: string
47
- grantTokens ?: string [ ]
48
- }
18
+ import { KMS_CLIENT_USER_AGENT } from './constants'
49
19
50
- export interface IBranchKeyStoreNode {
51
- ddbTableName : string
52
- logicalKeyStoreName : string
53
- kmsConfiguration : Readonly < KmsConfig >
54
- kmsClient : KMSClient
55
- ddbClient : DynamoDBClient
56
- keyStoreId : string
57
- grantTokens ?: ReadonlyArray < string >
20
+ import { IBranchKeyStorage , BranchKeyStoreNodeInput } from './types'
21
+ import { DynamoDBKeyStorage } from './dynamodb_key_storage'
58
22
23
+ interface IBranchKeyStoreNode {
59
24
getActiveBranchKey ( branchKeyId : string ) : Promise < NodeBranchKeyMaterial >
60
25
getBranchKeyVersion (
61
26
branchKeyId : string ,
@@ -64,26 +29,23 @@ export interface IBranchKeyStoreNode {
64
29
}
65
30
66
31
export class BranchKeyStoreNode implements IBranchKeyStoreNode {
67
- public declare ddbTableName : string
32
+ // public declare ddbTableName: string
68
33
public declare logicalKeyStoreName : string
69
34
public declare kmsConfiguration : Readonly < KmsConfig >
70
35
public declare kmsClient : KMSClient
71
- public declare ddbClient : DynamoDBClient
36
+ // public declare ddbClient: DynamoDBClient
72
37
public declare keyStoreId : string
73
38
public declare grantTokens ?: ReadonlyArray < string >
74
39
40
+ public declare storage : IBranchKeyStorage
41
+
75
42
constructor ( {
76
- ddbTableName,
77
43
logicalKeyStoreName,
44
+ storage,
45
+ keyManagement,
78
46
kmsConfiguration,
79
- kmsClient,
80
- ddbClient,
81
47
keyStoreId,
82
- grantTokens,
83
48
} : BranchKeyStoreNodeInput ) {
84
- /* Precondition: DDB table name must be a string */
85
- needs ( typeof ddbTableName === 'string' , 'DDB table name must be a string' )
86
-
87
49
/* Precondition: Logical keystore name must be a string */
88
50
needs (
89
51
typeof logicalKeyStoreName === 'string' ,
@@ -94,23 +56,36 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
94
56
needs ( isKmsConfig ( kmsConfiguration ) , 'KMS Configuration must be SRK' )
95
57
96
58
/* Precondition: KMS client must be a KMSClient */
97
- if ( kmsClient ) {
98
- needs ( kmsClient instanceof KMSClient , 'KMS client must be a KMSClient' )
99
- } else {
100
- // ensure it's strictly undefined and not some other falsey value
101
- kmsClient = undefined
59
+ if ( keyManagement ?. kmsClient ) {
60
+ needs (
61
+ keyManagement . kmsClient instanceof KMSClient ,
62
+ 'KMS client must be a KMSClient'
63
+ )
102
64
}
103
65
104
- /* Precondition: DDB client must be a DynamoDBClient */
105
- if ( ddbClient ) {
66
+ if (
67
+ 'getEncryptedActiveBranchKey' in storage &&
68
+ 'getEncryptedBranchKeyVersion' in storage
69
+ ) {
70
+ this . storage
71
+ } else {
106
72
needs (
107
- ddbClient instanceof DynamoDBClient ,
73
+ ! storage . ddbClient ||
74
+ ( storage . ddbClient as any ) instanceof DynamoDBClient ,
108
75
'DDB client must be a DynamoDBClient'
109
76
)
110
- } else {
111
- // ensure it's strictly undefined and not some other falsey value
112
- ddbClient = undefined
77
+ this . storage = new DynamoDBKeyStorage ( {
78
+ ddbTableName : storage . ddbTableName ,
79
+ logicalKeyStoreName,
80
+ ddbClient :
81
+ storage . ddbClient instanceof DynamoDBClient
82
+ ? storage . ddbClient
83
+ : new DynamoDBClient ( {
84
+ region : ( kmsConfiguration as RegionalKmsConfig ) . getRegion ( ) ,
85
+ } ) ,
86
+ } )
113
87
}
88
+ readOnlyProperty ( this , 'storage' , this . storage )
114
89
115
90
/* Precondition: Keystore id must be a string */
116
91
if ( keyStoreId ) {
@@ -121,15 +96,14 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
121
96
}
122
97
123
98
/* Precondition: Grant tokens must be a string array */
124
- if ( grantTokens ) {
99
+ if ( keyManagement ?. grantTokens ) {
125
100
needs (
126
- Array . isArray ( grantTokens ) &&
127
- grantTokens . every ( ( grantToken ) => typeof grantToken === 'string' ) ,
101
+ Array . isArray ( keyManagement . grantTokens ) &&
102
+ keyManagement . grantTokens . every (
103
+ ( grantToken ) => typeof grantToken === 'string'
104
+ ) ,
128
105
'Grant tokens must be a string array'
129
106
)
130
- } else {
131
- // ensure it's strictly undefined and not some other falsey value
132
- grantTokens = undefined
133
107
}
134
108
135
109
//= aws-encryption-sdk-specification/framework/branch-key-store.md#keystore-id
@@ -140,42 +114,16 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
140
114
141
115
//= aws-encryption-sdk-specification/framework/branch-key-store.md#aws-kms-grant-tokens
142
116
//# A list of AWS KMS [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token).
143
- readOnlyProperty ( this , 'grantTokens' , grantTokens )
117
+ readOnlyProperty (
118
+ this ,
119
+ 'grantTokens' ,
120
+ keyManagement ?. grantTokens || undefined
121
+ )
144
122
/* Postcondition: If unprovided, the grant tokens are undefined */
145
123
146
124
needs ( kmsConfiguration , 'AWS KMS Configuration required' )
147
125
readOnlyProperty ( this , 'kmsConfiguration' , Object . freeze ( kmsConfiguration ) )
148
126
149
- //= aws-encryption-sdk-specification/framework/branch-key-store.md#dynamodb-client
150
- //# The DynamoDb Client used to put and get keys from the backing DDB table.
151
-
152
- //# If the AWS KMS Configuration is KMS Key ARN or KMS MRKey ARN,
153
- //# and no DynamoDb Client is provided,
154
- //# a new DynamoDb Client MUST be created
155
- //# with the region of the supplied KMS ARN.
156
-
157
- //# If the AWS KMS Configuration is Discovery,
158
- //# and no DynamoDb Client is provided,
159
- //# a new DynamoDb Client MUST be created
160
- //# with the default configuration.
161
-
162
- //# If the AWS KMS Configuration is MRDiscovery,
163
- //# and no DynamoDb Client is provided,
164
- //# a new DynamoDb Client MUST be created
165
- //# with the region configured in the MRDiscovery.
166
- // TODO: when other KMS configuration types/classes are supported for the keystore,
167
- // verify the configuration object type to determine how we instantiate the
168
- // DDB client. This will ensure safe type casting.
169
- readOnlyProperty (
170
- this ,
171
- 'ddbClient' ,
172
- ddbClient ||
173
- new DynamoDBClient ( {
174
- region : ( this . kmsConfiguration as RegionalKmsConfig ) . getRegion ( ) ,
175
- } )
176
- )
177
- /* Postcondition: If unprovided, the DDB client is configured */
178
-
179
127
//= aws-encryption-sdk-specification/framework/branch-key-store.md#kms-client
180
128
//# The KMS Client used when wrapping and unwrapping keys.
181
129
@@ -203,19 +151,14 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
203
151
readOnlyProperty (
204
152
this ,
205
153
'kmsClient' ,
206
- kmsClient ||
154
+ keyManagement ?. kmsClient ||
207
155
new KMSClient ( {
208
156
region : ( this . kmsConfiguration as RegionalKmsConfig ) . getRegion ( ) ,
209
157
customUserAgent : KMS_CLIENT_USER_AGENT ,
210
158
} )
211
159
)
212
160
/* Postcondition: If unprovided, the KMS client is configured */
213
161
214
- //= aws-encryption-sdk-specification/framework/branch-key-store.md#table-name
215
- //# The table name of the DynamoDb table that backs this Keystore.
216
- needs ( ddbTableName , 'DynamoDb table name required' )
217
- readOnlyProperty ( this , 'ddbTableName' , ddbTableName )
218
-
219
162
//= aws-encryption-sdk-specification/framework/branch-key-store.md#logical-keystore-name
220
163
//# This name is cryptographically bound to all data stored in this table,
221
164
//# and logically separates data between different tables.
@@ -234,38 +177,38 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
234
177
Object . freeze ( this )
235
178
}
236
179
237
- /**
238
- * This is a utility method that encapsulates the overlapping logic for getActiveBranchKey
239
- * and getBranchKeyVersion to retreive the branch key materials
240
- * @param branchKeyId
241
- * @param type - this could indicate an active or versioned request
242
- * @returns branch key materials
243
- */
244
- private async _getBranchKeyMaterials (
245
- branchKeyId : string ,
246
- type : string
247
- ) : Promise < NodeBranchKeyMaterial > {
248
- // get the ddb response item using the partition & sort keys
249
- const ddbBranchKeyItem = await getBranchKeyItem ( this , branchKeyId , type )
250
- // validate and form the branch key record
251
- const ddbBranchKeyRecord = validateBranchKeyRecord ( ddbBranchKeyItem )
252
- // construct an encryption context from the record
253
- const authenticatedEncryptionContext =
254
- constructAuthenticatedEncryptionContext ( this , ddbBranchKeyRecord )
255
- // decrypt the encrypted branch key
256
- const branchKey = await decryptBranchKey (
257
- this ,
258
- ddbBranchKeyRecord ,
259
- authenticatedEncryptionContext
260
- )
261
- // construct branch key materials from the authenticated encryption context
262
- const branchKeyMaterials = constructBranchKeyMaterials (
263
- branchKey ,
264
- branchKeyId ,
265
- authenticatedEncryptionContext
266
- )
267
- return branchKeyMaterials
268
- }
180
+ // / **
181
+ // * This is a utility method that encapsulates the overlapping logic for getActiveBranchKey
182
+ // * and getBranchKeyVersion to retreive the branch key materials
183
+ // * @param branchKeyId
184
+ // * @param type - this could indicate an active or versioned request
185
+ // * @returns branch key materials
186
+ // */
187
+ // private async _getBranchKeyMaterials(
188
+ // branchKeyId: string,
189
+ // type: string
190
+ // ): Promise<NodeBranchKeyMaterial> {
191
+ // // get the ddb response item using the partition & sort keys
192
+ // const ddbBranchKeyItem = await getBranchKeyItem(this, branchKeyId, type)
193
+ // // validate and form the branch key record
194
+ // const ddbBranchKeyRecord = validateBranchKeyRecord(ddbBranchKeyItem)
195
+ // // construct an encryption context from the record
196
+ // const authenticatedEncryptionContext =
197
+ // constructAuthenticatedEncryptionContext(this, ddbBranchKeyRecord)
198
+ // // decrypt the encrypted branch key
199
+ // const branchKey = await decryptBranchKey(
200
+ // this,
201
+ // ddbBranchKeyRecord,
202
+ // authenticatedEncryptionContext
203
+ // )
204
+ // // construct branch key materials from the authenticated encryption context
205
+ // const branchKeyMaterials = constructBranchKeyMaterials(
206
+ // branchKey,
207
+ // branchKeyId,
208
+ // authenticatedEncryptionContext
209
+ // )
210
+ // return branchKeyMaterials
211
+ // }
269
212
270
213
async getActiveBranchKey (
271
214
branchKeyId : string
@@ -279,10 +222,17 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
279
222
'MUST supply a string branch key id'
280
223
)
281
224
282
- return await this . _getBranchKeyMaterials (
283
- branchKeyId ,
284
- BRANCH_KEY_ACTIVE_TYPE
225
+ const activeEncryptedBranchKey =
226
+ await this . storage . getEncryptedActiveBranchKey ( branchKeyId )
227
+
228
+ // decrypt the encrypted branch key
229
+ const branchKey = await decryptBranchKey ( this , activeEncryptedBranchKey )
230
+ // construct branch key materials from the authenticated encryption context
231
+ const branchKeyMaterials = constructBranchKeyMaterials (
232
+ branchKey ,
233
+ activeEncryptedBranchKey
285
234
)
235
+ return branchKeyMaterials
286
236
}
287
237
288
238
async getBranchKeyVersion (
@@ -303,10 +253,19 @@ export class BranchKeyStoreNode implements IBranchKeyStoreNode {
303
253
'MUST supply a string branch key version'
304
254
)
305
255
306
- return await this . _getBranchKeyMaterials (
256
+ const encryptedBranchKey = await this . storage . getEncryptedBranchKeyVersion (
307
257
branchKeyId ,
308
- BRANCH_KEY_TYPE_PREFIX + branchKeyVersion
258
+ branchKeyVersion
259
+ )
260
+
261
+ // decrypt the encrypted branch key
262
+ const branchKey = await decryptBranchKey ( this , encryptedBranchKey )
263
+ // construct branch key materials from the authenticated encryption context
264
+ const branchKeyMaterials = constructBranchKeyMaterials (
265
+ branchKey ,
266
+ encryptedBranchKey
309
267
)
268
+ return branchKeyMaterials
310
269
}
311
270
}
312
271
@@ -318,3 +277,19 @@ export function isIBranchKeyStoreNode(
318
277
) : keyStore is BranchKeyStoreNode {
319
278
return keyStore instanceof BranchKeyStoreNode
320
279
}
280
+
281
+ // The JS implementation is not encumbered with the legacy construction
282
+ // by passing DDB clients et al.
283
+ // So it can be simplified.
284
+ //= aws-encryption-sdk-specification/framework/branch-key-store.md#initialization
285
+ //= type=exception
286
+ //# - [AWS KMS Grant Tokens](#aws-kms-grant-tokens)
287
+
288
+ //= aws-encryption-sdk-specification/framework/branch-key-store.md#initialization
289
+ //= type=exception
290
+ //# - [DynamoDb Client](#dynamodb-client)
291
+
292
+ //= aws-encryption-sdk-specification/framework/branch-key-store.md#initialization
293
+ //= type=exception
294
+ //# - [Table Name](#table-name)
295
+ //# - [KMS Client](#kms-client)
0 commit comments