Skip to content

Commit 43813f4

Browse files
authored
Release 2.2.0 (#613)
See GHSA-h45p-w933-jxh3
1 parent 06211c8 commit 43813f4

File tree

99 files changed

+18236
-24637
lines changed

Some content is hidden

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

99 files changed

+18236
-24637
lines changed

.gitmodules

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[submodule "aws-encryption-sdk-test-vectors"]
22
path = aws-encryption-sdk-test-vectors
3-
url = https://github.com/awslabs/aws-encryption-sdk-test-vectors.git
3+
url = https://github.com/awslabs/private-aws-encryption-sdk-test-vectors-staging.git
4+
branch = known-invalid-test-vectors

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ A multi keyring can be used to compose keyrings together.
6363
### Wrapping Keys
6464

6565
Wrapping keys are used to protect data keys.
66-
An example of a wrapping key is a `KMS customer master key (CMK)`_.
66+
An example of a wrapping key is a `KMS customer master key (CMK)`.
6767

6868
### Data Keys
6969

modules/client-browser/src/index.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ export * from '@aws-crypto/raw-aes-keyring-browser'
1010
export * from '@aws-crypto/raw-rsa-keyring-browser'
1111
export * from '@aws-crypto/web-crypto-backend'
1212

13-
import { CommitmentPolicy } from '@aws-crypto/material-management-browser'
13+
import {
14+
CommitmentPolicy,
15+
ClientOptions,
16+
} from '@aws-crypto/material-management-browser'
1417

1518
import { buildEncrypt } from '@aws-crypto/encrypt-browser'
1619
import { buildDecrypt } from '@aws-crypto/decrypt-browser'
1720

1821
export function buildClient(
19-
commitmentPolicy: CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
22+
options?: CommitmentPolicy | ClientOptions
2023
): ReturnType<typeof buildEncrypt> & ReturnType<typeof buildDecrypt> {
2124
return {
22-
...buildEncrypt(commitmentPolicy),
23-
...buildDecrypt(commitmentPolicy),
25+
...buildEncrypt(options),
26+
...buildDecrypt(options),
2427
}
2528
}

modules/client-node/src/index.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,19 @@ export * from '@aws-crypto/kms-keyring-node'
99
export * from '@aws-crypto/raw-aes-keyring-node'
1010
export * from '@aws-crypto/raw-rsa-keyring-node'
1111

12-
import { CommitmentPolicy } from '@aws-crypto/material-management-node'
12+
import {
13+
CommitmentPolicy,
14+
ClientOptions,
15+
} from '@aws-crypto/material-management-node'
1316

1417
import { buildEncrypt } from '@aws-crypto/encrypt-node'
1518
import { buildDecrypt } from '@aws-crypto/decrypt-node'
1619

1720
export function buildClient(
18-
commitmentPolicy: CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
21+
options?: CommitmentPolicy | ClientOptions
1922
): ReturnType<typeof buildEncrypt> & ReturnType<typeof buildDecrypt> {
2023
return {
21-
...buildEncrypt(commitmentPolicy),
22-
...buildDecrypt(commitmentPolicy),
24+
...buildEncrypt(options),
25+
...buildDecrypt(options),
2326
}
2427
}

modules/decrypt-browser/src/decrypt.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
WebCryptoMaterialsManager,
1212
CommitmentPolicy,
1313
CommitmentPolicySuites,
14+
ClientOptions,
1415
} from '@aws-crypto/material-management-browser'
1516
import {
1617
deserializeSignature,
@@ -34,20 +35,29 @@ export interface DecryptResult {
3435
}
3536

3637
export async function _decrypt(
37-
commitmentPolicy: CommitmentPolicy,
38+
{ commitmentPolicy, maxEncryptedDataKeys }: ClientOptions,
3839
cmm: KeyringWebCrypto | WebCryptoMaterialsManager,
3940
ciphertext: Uint8Array
4041
): Promise<DecryptResult> {
4142
/* Precondition: _decrypt needs a valid commitmentPolicy. */
4243
needs(CommitmentPolicy[commitmentPolicy], 'Invalid commitment policy.')
4344

45+
// buildDecrypt defaults this to false for backwards compatibility, so this is satisfied
46+
/* Precondition: _decrypt needs a valid maxEncryptedDataKeys. */
47+
needs(
48+
maxEncryptedDataKeys === false || maxEncryptedDataKeys >= 1,
49+
'Invalid maxEncryptedDataKeys value.'
50+
)
51+
4452
/* If the cmm is a Keyring, wrap it with WebCryptoDefaultCryptographicMaterialsManager. */
4553
cmm =
4654
cmm instanceof KeyringWebCrypto
4755
? new WebCryptoDefaultCryptographicMaterialsManager(cmm)
4856
: cmm
4957

50-
const headerInfo = deserialize.deserializeMessageHeader(ciphertext)
58+
const headerInfo = deserialize.deserializeMessageHeader(ciphertext, {
59+
maxEncryptedDataKeys,
60+
})
5161
if (headerInfo === false) throw new Error('Unable to parse Header')
5262
const { messageHeader, algorithmSuite } = headerInfo
5363
const { rawHeader, headerAuth } = headerInfo

modules/decrypt-browser/src/decrypt_client.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { _decrypt } from './decrypt'
55
import {
66
CommitmentPolicy,
7+
ClientOptions,
78
needs,
89
} from '@aws-crypto/material-management-browser'
910

@@ -15,13 +16,28 @@ type CurryFirst<fn extends (...a: any[]) => any> = fn extends (
1516
: []
1617

1718
export function buildDecrypt(
18-
commitmentPolicy: CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
19+
options: CommitmentPolicy | Partial<ClientOptions> = {}
1920
): {
2021
decrypt: (...args: CurryFirst<typeof _decrypt>) => ReturnType<typeof _decrypt>
2122
} {
23+
const {
24+
commitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
25+
maxEncryptedDataKeys = false,
26+
} = typeof options === 'string' ? { commitmentPolicy: options } : options
27+
2228
/* Precondition: browser buildDecrypt needs a valid commitmentPolicy. */
2329
needs(CommitmentPolicy[commitmentPolicy], 'Invalid commitment policy.')
30+
/* Precondition: browser buildDecrypt needs a valid maxEncryptedDataKeys. */
31+
needs(
32+
maxEncryptedDataKeys === false || maxEncryptedDataKeys >= 1,
33+
'Invalid maxEncryptedDataKeys value.'
34+
)
35+
36+
const clientOptions: ClientOptions = {
37+
commitmentPolicy,
38+
maxEncryptedDataKeys,
39+
}
2440
return {
25-
decrypt: _decrypt.bind({}, commitmentPolicy),
41+
decrypt: _decrypt.bind({}, clientOptions),
2642
}
2743
}

modules/decrypt-browser/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
export { buildDecrypt } from './decrypt_client'
5+
export { DecryptResult } from './decrypt'
56
export { MessageHeader } from '@aws-crypto/serialize'

modules/decrypt-browser/test/decrypt.test.ts

+61-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/* eslint-env mocha */
55

66
import * as chai from 'chai'
7+
// @ts-ignore
78
import chaiAsPromised from 'chai-as-promised'
89
import { buildDecrypt } from '../src/index'
910
import { _decrypt } from '../src/decrypt'
@@ -44,14 +45,34 @@ describe('decrypt', () => {
4445

4546
it('Precondition: _decrypt needs a valid commitmentPolicy.', async () => {
4647
await expect(
47-
_decrypt('fake_policy' as any, {} as any, {} as any)
48+
_decrypt(
49+
{ commitmentPolicy: 'fake_policy' as any, maxEncryptedDataKeys: false },
50+
{} as any,
51+
{} as any
52+
)
4853
).to.rejectedWith(Error, 'Invalid commitment policy.')
4954
})
5055

56+
it('Precondition: _decrypt needs a valid maxEncryptedDataKeys.', async () => {
57+
await expect(
58+
_decrypt(
59+
{
60+
commitmentPolicy: CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
61+
maxEncryptedDataKeys: 0,
62+
},
63+
{} as any,
64+
{} as any
65+
)
66+
).to.rejectedWith(Error, 'Invalid maxEncryptedDataKeys value.')
67+
})
68+
5169
it('Precondition: The parsed header algorithmSuite in _decrypt must be supported by the commitmentPolicy.', async () => {
5270
await expect(
5371
_decrypt(
54-
CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
72+
{
73+
commitmentPolicy: CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
74+
maxEncryptedDataKeys: false,
75+
},
5576
fixtures.decryptKeyring(),
5677
fixtures.base64CiphertextAlgAes256GcmIv12Tag16HkdfSha384EcdsaP384With4Frames()
5778
)
@@ -74,7 +95,10 @@ describe('decrypt', () => {
7495
} as any
7596
await expect(
7697
_decrypt(
77-
CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
98+
{
99+
commitmentPolicy: CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
100+
maxEncryptedDataKeys: false,
101+
},
78102
cmm,
79103
fromBase64(fixtures.compatibilityVectors().tests[0].ciphertext)
80104
)
@@ -142,6 +166,40 @@ describe('decrypt', () => {
142166
await expect(decrypt(keyring, data.slice(0, i))).to.rejectedWith(Error)
143167
}
144168
})
169+
170+
it('can decrypt data with less than maxEncryptedDataKeys', async () => {
171+
const { decrypt } = buildDecrypt({
172+
commitmentPolicy: CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT,
173+
maxEncryptedDataKeys: 3,
174+
})
175+
const { plaintext } = await decrypt(
176+
fixtures.decryptKeyring(),
177+
fixtures.twoEdksMessage()
178+
)
179+
expect(plaintext).to.deep.equal(Buffer.from('asdf'))
180+
})
181+
182+
it('can decrypt data with exactly maxEncryptedDataKeys', async () => {
183+
const { decrypt } = buildDecrypt({
184+
commitmentPolicy: CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT,
185+
maxEncryptedDataKeys: 3,
186+
})
187+
const { plaintext } = await decrypt(
188+
fixtures.decryptKeyring(),
189+
fixtures.threeEdksMessage()
190+
)
191+
expect(plaintext).to.deep.equal(Buffer.from('asdf'))
192+
})
193+
194+
it('will not decrypt data with more than maxEncryptedDataKeys', async () => {
195+
const { decrypt } = buildDecrypt({
196+
commitmentPolicy: CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT,
197+
maxEncryptedDataKeys: 3,
198+
})
199+
await expect(
200+
decrypt(fixtures.decryptKeyring(), fixtures.fourEdksMessage())
201+
).to.rejectedWith(Error, 'maxEncryptedDataKeys exceeded.')
202+
})
145203
})
146204

147205
// prettier-ignore

modules/decrypt-browser/test/decrypt_client.test.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/* eslint-env mocha */
55

66
import * as chai from 'chai'
7+
// @ts-ignore
78
import chaiAsPromised from 'chai-as-promised'
89
import { CommitmentPolicy } from '@aws-crypto/material-management-node'
910
import { buildDecrypt } from '../src/index'
@@ -13,11 +14,34 @@ const { expect } = chai
1314

1415
describe('buildDecrypt', () => {
1516
it('can build a client', () => {
17+
const test = buildDecrypt()
18+
expect(test).to.have.property('decrypt').and.to.be.a('function')
19+
})
20+
21+
it('can build a client with a commitment policy', () => {
1622
const test = buildDecrypt(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT)
1723
expect(test).to.have.property('decrypt').and.to.be.a('function')
1824
})
1925

26+
it('can build a client with max encrypted data keys', () => {
27+
for (const numKeys of [1, 10, Math.pow(2, 16) - 1, Math.pow(2, 16)]) {
28+
const test = buildDecrypt({ maxEncryptedDataKeys: numKeys })
29+
expect(test).to.have.property('decrypt').and.to.be.a('function')
30+
}
31+
})
32+
2033
it('Precondition: browser buildDecrypt needs a valid commitmentPolicy.', () => {
21-
expect(() => buildDecrypt({} as any)).to.throw('Invalid commitment policy.')
34+
expect(() => buildDecrypt('BAD_POLICY' as any)).to.throw(
35+
'Invalid commitment policy.'
36+
)
37+
})
38+
39+
it('Precondition: browser buildDecrypt needs a valid maxEncryptedDataKeys.', () => {
40+
expect(() => buildDecrypt({ maxEncryptedDataKeys: 0 })).to.throw(
41+
'Invalid maxEncryptedDataKeys value.'
42+
)
43+
expect(() => buildDecrypt({ maxEncryptedDataKeys: -1 })).to.throw(
44+
'Invalid maxEncryptedDataKeys value.'
45+
)
2246
})
2347
})

modules/decrypt-browser/test/fixtures.ts

+21
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,27 @@ export function frameSequenceOutOfOrder() {
250250
])
251251
}
252252

253+
export function twoEdksMessage() {
254+
// prettier-ignore
255+
return new Uint8Array([
256+
1,128,0,20,81,159,165,226,136,253,2,91,121,212,103,155,181,101,192,42,0,0,0,2,0,4,116,101,109,112,0,24,107,101,121,49,0,0,0,128,0,0,0,12,253,51,172,10,239,164,139,246,179,46,90,151,0,32,112,49,205,185,161,227,110,112,214,205,129,210,255,139,70,54,55,191,225,87,28,109,71,168,124,168,187,90,185,220,183,111,0,4,116,101,109,112,0,24,107,101,121,48,0,0,0,128,0,0,0,12,130,105,57,211,107,129,63,61,28,113,29,245,0,32,223,169,9,70,195,85,36,140,164,225,228,190,70,137,36,66,153,118,45,227,30,48,41,64,4,38,172,46,186,38,100,204,2,0,0,0,0,12,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,241,48,199,72,160,81,240,122,45,194,9,196,238,161,95,137,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,15,114,189,86,167,87,157,63,128,15,95,53,55,99,185,59,74,12,150,52
257+
])
258+
}
259+
260+
export function threeEdksMessage() {
261+
// prettier-ignore
262+
return new Uint8Array([
263+
1,128,0,20,6,147,84,28,195,247,246,16,92,66,254,35,91,134,21,113,0,0,0,3,0,4,116,101,109,112,0,24,107,101,121,50,0,0,0,128,0,0,0,12,243,10,221,12,30,48,159,193,178,76,143,111,0,32,164,227,105,185,29,231,91,130,47,214,222,135,16,165,55,47,97,135,251,159,33,232,143,25,70,73,55,217,248,216,69,44,0,4,116,101,109,112,0,24,107,101,121,48,0,0,0,128,0,0,0,12,146,167,240,23,105,252,154,26,125,18,74,76,0,32,243,219,32,78,83,237,209,122,150,92,241,94,91,201,171,7,110,218,233,15,20,56,246,15,48,131,41,225,114,157,197,252,0,4,116,101,109,112,0,24,107,101,121,49,0,0,0,128,0,0,0,12,215,162,33,39,252,66,105,179,78,16,42,232,0,32,30,167,255,38,200,18,212,153,115,229,175,89,11,101,31,244,6,146,25,12,80,32,22,53,53,63,239,107,104,139,65,167,2,0,0,0,0,12,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,25,251,17,157,236,34,27,100,13,10,155,194,218,166,195,57,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,15,114,189,86,231,188,115,162,175,197,222,3,249,202,81,98,227,231,67,146
264+
])
265+
}
266+
267+
export function fourEdksMessage() {
268+
// prettier-ignore
269+
return new Uint8Array([
270+
1,128,0,20,152,195,218,126,82,140,170,75,107,29,97,41,37,39,140,194,0,0,0,4,0,4,116,101,109,112,0,24,107,101,121,50,0,0,0,128,0,0,0,12,232,117,224,17,241,139,48,60,112,45,223,30,0,32,90,160,47,236,89,127,74,188,210,95,186,61,117,166,82,207,243,171,211,192,190,29,63,83,198,122,54,25,74,198,123,0,0,4,116,101,109,112,0,24,107,101,121,48,0,0,0,128,0,0,0,12,179,67,229,65,157,148,209,70,133,50,200,225,0,32,114,101,189,108,89,151,6,211,84,211,236,72,253,45,230,183,9,40,79,146,106,109,224,46,254,102,50,129,174,123,49,247,0,4,116,101,109,112,0,24,107,101,121,49,0,0,0,128,0,0,0,12,122,245,182,159,26,134,245,191,73,101,240,68,0,32,6,247,51,137,165,160,143,119,82,111,242,247,21,58,45,184,62,75,131,72,192,43,205,106,120,75,40,128,102,165,73,128,0,4,116,101,109,112,0,24,107,101,121,51,0,0,0,128,0,0,0,12,58,191,161,65,150,32,99,20,197,143,126,208,0,32,179,18,132,26,48,25,198,187,236,47,191,24,24,153,205,76,158,181,61,82,249,110,192,95,153,90,0,113,113,142,36,173,2,0,0,0,0,12,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,215,170,96,229,229,32,220,210,179,153,146,71,139,224,7,208,255,255,255,255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,15,114,189,86,12,123,234,170,45,72,187,11,199,119,21,216,211,21,95,51
271+
])
272+
}
273+
253274
class TestKeyring extends KeyringWebCrypto {
254275
async _onEncrypt(): Promise<WebCryptoEncryptionMaterial> {
255276
throw new Error('I should never see this error')

modules/decrypt-node/src/decipher_stream.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export function getDecipherStream() {
104104
decipherState.contentLength -= chunk.length
105105
/* Precondition: Only content should be transformed, so the lengths must always match.
106106
* The BodyHeader and AuthTag are striped in the VerifyStream and passed in
107-
* through events. This means that if I receive a chunk without havening reset
107+
* through events. This means that if I receive a chunk without having reset
108108
* the content accumulation events are out of order. Panic.
109109
*/
110110
needs(decipherState.contentLength >= 0, 'Lengths do not match')

modules/decrypt-node/src/decrypt.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import {
55
NodeMaterialsManager,
66
KeyringNode,
7-
CommitmentPolicy,
87
} from '@aws-crypto/material-management-node'
98
import { _decryptStream } from './decrypt_stream'
9+
import { DecryptParameters } from './types'
1010

1111
// @ts-ignore
1212
import { finished } from 'readable-stream'
@@ -24,12 +24,14 @@ export interface DecryptOptions {
2424
}
2525

2626
export async function _decrypt(
27-
commitmentPolicy: CommitmentPolicy,
27+
decryptParameters: DecryptParameters,
2828
cmm: NodeMaterialsManager | KeyringNode,
2929
ciphertext: Buffer | Uint8Array | Readable | string | NodeJS.ReadableStream,
3030
{ encoding, maxBodySize }: DecryptOptions = {}
3131
): Promise<DecryptOutput> {
32-
const stream = _decryptStream(commitmentPolicy, cmm, { maxBodySize })
32+
const stream = _decryptStream(decryptParameters, cmm, {
33+
maxBodySize,
34+
})
3335

3436
const plaintext: Buffer[] = []
3537
let messageHeader: MessageHeader | false = false

0 commit comments

Comments
 (0)