Skip to content

Commit

Permalink
feat(node): support node v16 (aws#741)
Browse files Browse the repository at this point in the history
Regenerated the Package lock with Node 16, NPM 8.
Added CI testing for Node 16.
Encapsulated Crypto's Sign(er) and Verify to prevent breaking changes.
Implemented and used Catchable to catch unkown.
TS upgrade introduced TS bug when recognizing arguments to
SubtleCrypto's ImportKey. Introduced function and note to help it
resolve the issue.

Co-authored-by: seebees <ryanemer@amazon.com>
  • Loading branch information
texastony and seebees authored Nov 5, 2021
1 parent 6ba9add commit 66e63b5
Show file tree
Hide file tree
Showing 30 changed files with 19,466 additions and 7,207 deletions.
16 changes: 16 additions & 0 deletions buildspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,24 @@ batch:
image: aws/codebuild/standard:5.0
- identifier: testNodejs12
buildspec: codebuild/nodejs12.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testNodejs14
buildspec: codebuild/nodejs14.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testNodejs16
buildspec: codebuild/nodejs16.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testBrowser
buildspec: codebuild/browser.yml
env:
image: aws/codebuild/standard:5.0
- identifier: compliance
buildspec: codebuild/compliance.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testVectorsNodejsLatest
buildspec: codebuild/test_vectors/nodejs_latest.yml
env:
Expand All @@ -25,10 +35,16 @@ batch:
image: aws/codebuild/standard:5.0
- identifier: testVectorsNodejs12
buildspec: codebuild/test_vectors/nodejs12.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testVectorsNodejs14
buildspec: codebuild/test_vectors/nodejs14.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testVectorsNodejs16
buildspec: codebuild/test_vectors/nodejs16.yml
env:
image: aws/codebuild/standard:5.0
- identifier: testVectorsBrowser
buildspec: codebuild/test_vectors/browser.yml
env:
Expand Down
19 changes: 19 additions & 0 deletions codebuild/nodejs16.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 0.2

env:
variables:
NODE_OPTIONS: "--max-old-space-size=4096"

phases:
install:
commands:
- n 16
- node -v
- npm -v
- npm ci --unsafe-perm
- npm run build
build:
commands:
- npm -v
- node -v
- npm run coverage-node
22 changes: 22 additions & 0 deletions codebuild/test_vectors/nodejs16.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: 0.2

env:
variables:
NODE_OPTIONS: "--max-old-space-size=4096"
NPM_CONFIG_UNSAFE_PERM: true

phases:
install:
commands:
- n 16
- node -v
- npm -v
- npm ci --unsafe-perm
- npm run build
build:
commands:
- npm -v
- node -v
- npm run verdaccio-publish
- npm run verdaccio-node-decrypt
- npm run verdaccio-node-encrypt
6 changes: 3 additions & 3 deletions modules/decrypt-node/src/verify_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ export class VerifyStream extends PortableTransformWithType {
if (verify) {
const { rawHeader, headerAuth, messageHeader } = headerInfo
const { headerIv, headerAuthTag } = headerAuth
verify.update(rawHeader)
verify.update(<Buffer>rawHeader)
verify.update(
serializeMessageHeaderAuth({
<Buffer>serializeMessageHeaderAuth({
headerIv,
headerAuthTag,
messageHeader,
Expand Down Expand Up @@ -263,7 +263,7 @@ export class VerifyStream extends PortableTransformWithType {
return super.push(chunk, encoding)
}

_flush(callback: (err?: Error) => void) {
_flush(callback: (err?: Error | any | unknown) => void) {
const { finalAuthTagReceived } = this._verifyState
/* Precondition: All ciphertext MUST have been received.
* The verify stream has ended,
Expand Down
4 changes: 2 additions & 2 deletions modules/example-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-mocha": "2.0.1",
"karma-webpack": "^4.0.2",
"karma-webpack": "^5.0.0",
"ts-loader": "9.2.5",
"ts-node": "^10.2.1",
"tslib": "^2.2.0",
"typescript": "^4.0.2",
"webpack": "^4.42.1",
"webpack": "^5.42.0",
"webpack-cli": "4.6.0"
},
"main": "./build/main/src/index.js",
Expand Down
11 changes: 9 additions & 2 deletions modules/integration-browser/src/integration.encrypt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,15 @@ function aTest(testName: string, decryptOracle: string) {
const body = await response.arrayBuffer()
needs(response.ok, `Failed to decrypt: ${toUtf8(body)}`)
expect(plainText).toEqual(new Uint8Array(body))
} catch (e) {
if (!notSupportedMessages.includes(e.message)) throw e
} catch (err) {
needs(
err instanceof Error,
`Thrown object must be an error but was ${typeof err}`
)
needs(
notSupportedMessages.includes(err.message),
`Error message should be in notSupportedMessages but was ${err.message}`
)
}
})
}
16 changes: 14 additions & 2 deletions modules/integration-browser/src/testDecryptFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
MultiKeyringWebCrypto,
WebCryptoMaterialsManager,
DecryptResult,
needs,
} from '@aws-crypto/client-browser'
import {
DecryptionFixture,
Expand Down Expand Up @@ -69,14 +70,17 @@ export async function testPositiveDecryptFixture(
) {
return { result: true, name }
}
// noinspection ExceptionCaughtLocallyJS
/* If the actual plaintext does not match the expected plaintext,*/
throw new Error(
expectedNotActualPlaintextMessage +
`\n expected plaintext: ${expectedPlainText}` +
`\n actual plaintext: ${decryptResult.plaintext}`
)
} catch (err) {
/* it FAILED with err.message as expectedNotActualPlaintextMessage */
return { result: false, name, err }
//By catching the err and returning it above, we also satisfy:
/* If the decryption is NOT supported, FAILED with err.message in notSupportedDecryptMessages */
}
}

Expand All @@ -96,10 +100,18 @@ export async function testNegativeDecryptFixture(
const cmm = await _getCmm(keyInfos)
decryptResult = await _decrypt(cmm, cipher)
} catch (err) {
if (notSupportedDecryptMessages.includes(err.message))
needs(
err instanceof Error,
`Thrown object must be an error but was ${typeof err}`
)
if (notSupportedDecryptMessages.includes(err.message)) {
/* If the decryption is NOT supported, FAILED with err.message in notSupportedDecryptMessages */
return { result: false, name, err: err }
}
/* If it is a negative test, and it throws an error outside of notSupportedDecryptMessages, it PASSED.*/
return { result: true, name }
}
/* If it is a negative test, and it does not throw an error, it FAILED */
return {
result: false,
name,
Expand Down
4 changes: 2 additions & 2 deletions modules/integration-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
"@aws-crypto/integration-vectors": "file:../integration-vectors",
"@types/got": "^9.6.9",
"@types/stream-to-promise": "^2.2.0",
"@types/yargs": "^15.0.3",
"@types/yargs": "^17.0.1",
"got": "^11.8.0",
"stream-to-promise": "^3.0.0",
"tslib": "^2.3.0",
"yargs": "^17.1.0"
"yargs": "^17.0.1"
},
"sideEffects": false,
"main": "./build/main/src/index.js",
Expand Down
2 changes: 1 addition & 1 deletion modules/integration-node/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const cli = yargs
tolerateFailures,
testName,
concurrency,
} = argv
} = await argv
/* I set the result to 1 so that if I fall through the exit condition is a failure */
let result = 1
if (command === 'decrypt') {
Expand Down
33 changes: 12 additions & 21 deletions modules/integration-node/src/decrypt_materials_manager_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@
// SPDX-License-Identifier: Apache-2.0

import {
needs,
buildAwsKmsMrkAwareDiscoveryMultiKeyringNode,
buildAwsKmsMrkAwareStrictMultiKeyringNode,
KeyringNode,
MultiKeyringNode,
KmsKeyringNode,
MultiKeyringNode,
needs,
oaepHashSupported,
RawAesKeyringNode,
WrappingSuiteIdentifier,
RawAesWrappingSuiteIdentifier,
RawRsaKeyringNode,
oaepHashSupported,
buildAwsKmsMrkAwareStrictMultiKeyringNode,
buildAwsKmsMrkAwareDiscoveryMultiKeyringNode,
WrappingSuiteIdentifier,
} from '@aws-crypto/client-node'
import {
RsaKeyInfo,
AESKey,
AesKeyInfo,
buildGetKeyring,
KeyInfoTuple,
KMSKey,
KmsKeyInfo,
KmsMrkAwareKeyInfo,
KmsMrkAwareDiscoveryKeyInfo,
KmsMrkAwareKeyInfo,
RSAKey,
AESKey,
KMSKey,
KeyInfoTuple,
buildGetKeyring,
RsaKeyInfo,
} from '@aws-crypto/integration-vectors'
import { constants } from 'crypto'

Expand Down Expand Up @@ -117,12 +117,3 @@ export function rsaPadding(keyInfo: RsaKeyInfo) {
needs(oaepHashSupported || oaepHash === 'sha1', 'Not supported at this time.')
return { padding, oaepHash }
}

export class NotSupported extends Error {
code: string
constructor(message?: string) {
super(message)
Object.setPrototypeOf(this, NotSupported.prototype)
this.code = 'NOT_SUPPORTED'
}
}
2 changes: 1 addition & 1 deletion modules/integration-vectors/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export interface TestVectorResult {
name: string
result: boolean
description?: string
err?: Error
err?: Error | string | any
}

export interface StreamEntry extends Entry {
Expand Down
7 changes: 4 additions & 3 deletions modules/kms-keyring/src/kms_keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
readOnlyProperty,
unwrapDataKey,
Newable,
Catchable,
} from '@aws-crypto/material-management'
import {
KMS_PROVIDER_ID,
Expand Down Expand Up @@ -243,7 +244,7 @@ export function KmsKeyringClass<
*/
const decryptableEDKs = encryptedDataKeys.filter(filterEDKs(keyIds, this))

const cmkErrors: Error[] = []
const cmkErrors: Catchable[] = []

for (const edk of decryptableEDKs) {
let dataKey: RequiredDecryptResponse | false = false
Expand All @@ -259,7 +260,7 @@ export function KmsKeyringClass<
* If the caller does not have access they may have access
* through another Keyring.
*/
cmkErrors.push(e)
cmkErrors.push({ errPlus: e })
}

/* Check for early return (Postcondition): clientProvider may not return a client. */
Expand Down Expand Up @@ -300,7 +301,7 @@ export function KmsKeyringClass<
material.hasValidKey() ||
(!material.hasValidKey() && !cmkErrors.length),
cmkErrors.reduce(
(m, e, i) => `${m} Error #${i + 1} \n ${e.stack} \n`,
(m, e, i) => `${m} Error #${i + 1} \n ${e.errPlus.stack} \n`,
'Unable to decrypt data key and one or more KMS CMKs had an error. \n '
)
)
Expand Down
7 changes: 4 additions & 3 deletions modules/kms-keyring/src/kms_mrk_discovery_keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
readOnlyProperty,
SupportedAlgorithmSuites,
Newable,
Catchable,
} from '@aws-crypto/material-management'
import {
constructArnInOtherRegion,
Expand Down Expand Up @@ -170,7 +171,7 @@ export function AwsKmsMrkAwareSymmetricDiscoveryKeyringClass<
//# The set of encrypted data keys MUST first be filtered to match this
//# keyring's configuration.
const decryptableEDKs = encryptedDataKeys.filter(filterEDKs(this))
const cmkErrors: Error[] = []
const cmkErrors: Catchable[] = []

//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
//# For each encrypted data key in the filtered set, one at a time, the
Expand Down Expand Up @@ -253,7 +254,7 @@ export function AwsKmsMrkAwareSymmetricDiscoveryKeyringClass<
//# If the response does not satisfies these requirements then an error
//# is collected and the next encrypted data key in the filtered set MUST
//# be attempted.
cmkErrors.push(e)
cmkErrors.push({ errPlus: e })
}
}
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
Expand All @@ -266,7 +267,7 @@ export function AwsKmsMrkAwareSymmetricDiscoveryKeyringClass<
`Unable to decrypt data key${
!decryptableEDKs.length ? ': No EDKs supplied' : ''
}.`,
...cmkErrors.map((e, i) => `Error #${i + 1} \n${e.stack}`),
...cmkErrors.map((e, i) => `Error #${i + 1} \n${e.errPlus.stack}`),
].join('\n')
)
return material
Expand Down
7 changes: 4 additions & 3 deletions modules/kms-keyring/src/kms_mrk_keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
readOnlyProperty,
unwrapDataKey,
Newable,
Catchable,
} from '@aws-crypto/material-management'
import {
KMS_PROVIDER_ID,
Expand Down Expand Up @@ -274,7 +275,7 @@ export function AwsKmsMrkAwareSymmetricKeyringClass<
//# keyring's configuration.
const decryptableEDKs = encryptedDataKeys.filter(filterEDKs(keyId))

const cmkErrors: Error[] = []
const cmkErrors: Catchable[] = []

//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
//# For each encrypted data key in the filtered set, one at a time, the
Expand Down Expand Up @@ -344,7 +345,7 @@ export function AwsKmsMrkAwareSymmetricKeyringClass<
//# If the response does not satisfies these requirements then an error
//# MUST be collected and the next encrypted data key in the filtered set
//# MUST be attempted.
cmkErrors.push(e)
cmkErrors.push({ errPlus: e })
}
}

Expand All @@ -358,7 +359,7 @@ export function AwsKmsMrkAwareSymmetricKeyringClass<
`Unable to decrypt data key${
!decryptableEDKs.length ? ': No EDKs supplied' : ''
}.`,
...cmkErrors.map((e, i) => `Error #${i + 1} \n${e.stack}`),
...cmkErrors.map((e, i) => `Error #${i + 1} \n${e.errPlus.stack}`),
].join('\n')
)

Expand Down
1 change: 1 addition & 0 deletions modules/material-management-node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export {
KeyringTrace,
KeyringTraceFlag,
needs,
NotSupported,
KeyringNode,
MultiKeyringNode,
immutableBaseClass,
Expand Down
Loading

0 comments on commit 66e63b5

Please sign in to comment.