Skip to content

feat: Support AWS SDK v3 #1043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions modules/kms-keyring-browser/src/kms_keyring_browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
limitRegions,
excludeRegions,
cacheClients,
AwsEsdkKMSInterface,
} from '@aws-crypto/kms-keyring'
import {
WebCryptoAlgorithmSuite,
Expand All @@ -29,16 +30,18 @@ const getKmsClient = getClient(KMS, {
})
const cacheKmsClients = cacheClients(getKmsClient)

export type KmsKeyringWebCryptoInput = Partial<KmsKeyringInput<KMS>>
export type KmsKeyringWebCryptoInput = Partial<
KmsKeyringInput<AwsEsdkKMSInterface>
>
export type KMSWebCryptoConstructible = KMSConstructible<
KMS,
KMS.ClientConfiguration
>
export type KmsWebCryptoClientSupplier = KmsClientSupplier<KMS>
export type KmsWebCryptoClientSupplier = KmsClientSupplier<AwsEsdkKMSInterface>

export class KmsKeyringBrowser extends KmsKeyringClass<
WebCryptoAlgorithmSuite,
KMS
AwsEsdkKMSInterface
>(KeyringWebCrypto as Newable<KeyringWebCrypto>) {
constructor({
clientProvider = cacheKmsClients,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {
AwsKmsMrkAwareSymmetricDiscoveryKeyringClass,
AwsKmsMrkAwareSymmetricDiscoveryKeyringInput,
AwsEsdkKMSInterface,
} from '@aws-crypto/kms-keyring'
import {
WebCryptoAlgorithmSuite,
Expand All @@ -16,16 +17,15 @@ import {
KeyringWebCrypto,
Newable,
} from '@aws-crypto/material-management-browser'
import { KMS } from 'aws-sdk'

export type AwsKmsMrkAwareSymmetricDiscoveryKeyringWebCryptoInput =
AwsKmsMrkAwareSymmetricDiscoveryKeyringInput<KMS>
AwsKmsMrkAwareSymmetricDiscoveryKeyringInput<AwsEsdkKMSInterface>

export class AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser extends AwsKmsMrkAwareSymmetricDiscoveryKeyringClass<
WebCryptoAlgorithmSuite,
KMS
AwsEsdkKMSInterface
>(KeyringWebCrypto as Newable<KeyringWebCrypto>) {
declare client: KMS
declare client: AwsEsdkKMSInterface

constructor({
client,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { getAwsKmsMrkAwareDiscoveryMultiKeyringBuilder } from '@aws-crypto/kms-keyring'
import {
getAwsKmsMrkAwareDiscoveryMultiKeyringBuilder,
AwsEsdkKMSInterface,
} from '@aws-crypto/kms-keyring'
import {
MultiKeyringWebCrypto,
WebCryptoAlgorithmSuite,
} from '@aws-crypto/material-management-browser'
import { getKmsClient } from '.'
import { AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser } from './kms_mrk_discovery_keyring_browser'
import { KMS } from 'aws-sdk'

export const buildAwsKmsMrkAwareDiscoveryMultiKeyringBrowser =
getAwsKmsMrkAwareDiscoveryMultiKeyringBuilder<WebCryptoAlgorithmSuite, KMS>(
getAwsKmsMrkAwareDiscoveryMultiKeyringBuilder<
WebCryptoAlgorithmSuite,
AwsEsdkKMSInterface
>(
AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser,
MultiKeyringWebCrypto,
getKmsClient
Expand Down
8 changes: 4 additions & 4 deletions modules/kms-keyring-browser/src/kms_mrk_keyring_browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {
AwsKmsMrkAwareSymmetricKeyringClass,
AwsKmsMrkAwareSymmetricKeyringInput,
AwsEsdkKMSInterface,
} from '@aws-crypto/kms-keyring'
import {
WebCryptoAlgorithmSuite,
Expand All @@ -16,16 +17,15 @@ import {
KeyringWebCrypto,
Newable,
} from '@aws-crypto/material-management-browser'
import { KMS } from 'aws-sdk'

export type AwsKmsMrkAwareSymmetricKeyringWebCryptoInput =
AwsKmsMrkAwareSymmetricKeyringInput<KMS>
AwsKmsMrkAwareSymmetricKeyringInput<AwsEsdkKMSInterface>

export class AwsKmsMrkAwareSymmetricKeyringBrowser extends AwsKmsMrkAwareSymmetricKeyringClass<
WebCryptoAlgorithmSuite,
KMS
AwsEsdkKMSInterface
>(KeyringWebCrypto as Newable<KeyringWebCrypto>) {
declare client: KMS
declare client: AwsEsdkKMSInterface
declare keyId: string
declare grantTokens?: string[]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { getAwsKmsMrkAwareStrictMultiKeyringBuilder } from '@aws-crypto/kms-keyring'
import {
getAwsKmsMrkAwareStrictMultiKeyringBuilder,
AwsEsdkKMSInterface,
} from '@aws-crypto/kms-keyring'
import {
MultiKeyringWebCrypto,
WebCryptoAlgorithmSuite,
} from '@aws-crypto/material-management-browser'
import { getKmsClient } from '.'
import { AwsKmsMrkAwareSymmetricKeyringBrowser } from './kms_mrk_keyring_browser'
import { KMS } from 'aws-sdk'

export const buildAwsKmsMrkAwareStrictMultiKeyringBrowser =
getAwsKmsMrkAwareStrictMultiKeyringBuilder<WebCryptoAlgorithmSuite, KMS>(
AwsKmsMrkAwareSymmetricKeyringBrowser,
MultiKeyringWebCrypto,
getKmsClient
)
getAwsKmsMrkAwareStrictMultiKeyringBuilder<
WebCryptoAlgorithmSuite,
AwsEsdkKMSInterface
>(AwsKmsMrkAwareSymmetricKeyringBrowser, MultiKeyringWebCrypto, getKmsClient)
50 changes: 46 additions & 4 deletions modules/kms-keyring-browser/test/kms_keyring_browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import * as chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { KmsKeyringBrowser, getClient, KMS } from '../src/index'
import { KmsKeyringBrowser, getClient } from '../src/index'
import { KMS as V2KMS } from 'aws-sdk'
import { KMS as V3KMS } from '@aws-sdk/client-kms'
import {
KeyringWebCrypto,
WebCryptoEncryptionMaterial,
Expand All @@ -28,7 +30,7 @@ describe('KmsKeyringBrowser::constructor', () => {
const keyArn =
'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f'
const keyIds = [keyArn]
const clientProvider = getClient(KMS, { credentials })
const clientProvider = getClient(V2KMS, { credentials })

const test = new KmsKeyringBrowser({
clientProvider,
Expand All @@ -49,13 +51,53 @@ describe('KmsKeyringBrowser::constructor', () => {
})
})

describe('KmsKeyringBrowser encrypt/decrypt', () => {
describe('KmsKeyringBrowser can encrypt/decrypt with AWS SDK v2 client', () => {
const generatorKeyId =
'arn:aws:kms:us-west-2:658956600833:alias/EncryptDecrypt'
const keyArn =
'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f'
const keyIds = [keyArn]
const clientProvider = getClient(KMS, { credentials })
const clientProvider = getClient(V2KMS, { credentials })
const keyring = new KmsKeyringBrowser({
clientProvider,
generatorKeyId,
keyIds,
})
let encryptedDataKey: EncryptedDataKey

it('can encrypt and create unencrypted data key', async () => {
const suite = new WebCryptoAlgorithmSuite(
AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA256
)
const material = new WebCryptoEncryptionMaterial(suite, {})
const test = await keyring.onEncrypt(material)
expect(test.hasValidKey()).to.equal(true)
const udk = test.getUnencryptedDataKey()
expect(udk).to.have.lengthOf(suite.keyLengthBytes)
expect(test.encryptedDataKeys).to.have.lengthOf(2)
const [edk] = test.encryptedDataKeys
encryptedDataKey = edk
})

it('can decrypt an EncryptedDataKey', async () => {
const suite = new WebCryptoAlgorithmSuite(
AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA256
)
const material = new WebCryptoDecryptionMaterial(suite, {})
const test = await keyring.onDecrypt(material, [encryptedDataKey])
expect(test.hasValidKey()).to.equal(true)
// The UnencryptedDataKey should be zeroed, because the cryptoKey has been set
expect(() => test.getUnencryptedDataKey()).to.throw()
})
})

describe('KmsKeyringBrowser can encrypt/decrypt with AWS SDK v3 client', () => {
const generatorKeyId =
'arn:aws:kms:us-west-2:658956600833:alias/EncryptDecrypt'
const keyArn =
'arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f'
const keyIds = [keyArn]
const clientProvider = getClient(V3KMS, { credentials })
const keyring = new KmsKeyringBrowser({
clientProvider,
generatorKeyId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
AlgorithmSuiteIdentifier,
WebCryptoDecryptionMaterial,
} from '@aws-crypto/material-management-browser'
import { KMS } from 'aws-sdk'
import { KMS as V2KMS } from 'aws-sdk'
import { KMS as V3KMS } from '@aws-sdk/client-kms'

chai.use(chaiAsPromised)
const { expect } = chai
Expand Down Expand Up @@ -56,7 +57,7 @@ describe('AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser::constructor', () => {
/* Injected from @aws-sdk/karma-credential-loader. */
declare const credentials: any

describe('AwsKmsMrkAwareSymmetricKeyringBrowser encrypt/decrypt', () => {
describe('AwsKmsMrkAwareSymmetricKeyringBrowser can encrypt/decrypt with AWS SDK v2 client', () => {
const discoveryFilter = { accountIDs: ['658956600833'], partition: 'aws' }

const eastKeyId =
Expand All @@ -69,7 +70,7 @@ describe('AwsKmsMrkAwareSymmetricKeyringBrowser encrypt/decrypt', () => {

const keyring = new AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser({
// Note the difference in the region from the keyId
client: new KMS({ region: 'us-west-2', credentials }),
client: new V2KMS({ region: 'us-west-2', credentials }),
discoveryFilter,
grantTokens,
})
Expand All @@ -84,7 +85,55 @@ describe('AwsKmsMrkAwareSymmetricKeyringBrowser encrypt/decrypt', () => {

it('can decrypt an EncryptedDataKey', async () => {
const encryptKeyring = new AwsKmsMrkAwareSymmetricKeyringBrowser({
client: new KMS({ region: 'us-east-1', credentials }),
client: new V2KMS({ region: 'us-east-1', credentials }),
keyId: eastKeyId,
grantTokens,
})
const encryptMaterial = await encryptKeyring.onEncrypt(
new WebCryptoEncryptionMaterial(suite, encryptionContext)
)
const [edk] = encryptMaterial.encryptedDataKeys

const material = await keyring.onDecrypt(
new WebCryptoDecryptionMaterial(suite, encryptionContext),
[edk]
)
const test = await keyring.onDecrypt(material, [edk])
expect(test.hasValidKey()).to.equal(true)
// The UnencryptedDataKey should be zeroed, because the cryptoKey has been set
expect(() => test.getUnencryptedDataKey()).to.throw()
})
})

describe('AwsKmsMrkAwareSymmetricKeyringBrowser can encrypt/decrypt with AWS SDK v3 client', () => {
const discoveryFilter = { accountIDs: ['658956600833'], partition: 'aws' }

const eastKeyId =
'arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7'
const grantTokens = ['grant']
const encryptionContext = { some: 'context' }
const suite = new WebCryptoAlgorithmSuite(
AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA256
)

const keyring = new AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser({
// Note the difference in the region from the keyId
client: new V3KMS({ region: 'us-west-2', credentials }),
discoveryFilter,
grantTokens,
})

it('throws an error on encrypt', async () => {
const material = new WebCryptoEncryptionMaterial(suite, encryptionContext)
return expect(keyring.onEncrypt(material)).to.rejectedWith(
Error,
'AwsKmsMrkAwareSymmetricDiscoveryKeyring cannot be used to encrypt'
)
})

it('can decrypt an EncryptedDataKey', async () => {
const encryptKeyring = new AwsKmsMrkAwareSymmetricKeyringBrowser({
client: new V3KMS({ region: 'us-east-1', credentials }),
keyId: eastKeyId,
grantTokens,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
WebCryptoDecryptionMaterial,
KeyringTraceFlag,
} from '@aws-crypto/material-management-browser'
import { KMS } from 'aws-sdk'
import { KMS as V2KMS } from 'aws-sdk'
import { KMS as V3KMS } from '@aws-sdk/client-kms'

chai.use(chaiAsPromised)
const { expect } = chai
Expand Down Expand Up @@ -50,7 +51,7 @@ describe('AwsKmsMrkAwareSymmetricKeyringBrowser::constructor', () => {
/* Injected from @aws-sdk/karma-credential-loader. */
declare const credentials: any

describe('AwsKmsMrkAwareSymmetricKeyringBrowser encrypt/decrypt', () => {
describe('AwsKmsMrkAwareSymmetricKeyringBrowser can encrypt/decrypt with AWS SDK v2 client', () => {
const westKeyId =
'arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7'
const eastKeyId =
Expand All @@ -62,12 +63,75 @@ describe('AwsKmsMrkAwareSymmetricKeyringBrowser encrypt/decrypt', () => {
)

const encryptKeyring = new AwsKmsMrkAwareSymmetricKeyringBrowser({
client: new KMS({ region: 'us-west-2', credentials }),
client: new V2KMS({ region: 'us-west-2', credentials }),
keyId: westKeyId,
grantTokens,
})
const decryptKeyring = new AwsKmsMrkAwareSymmetricKeyringBrowser({
client: new KMS({ region: 'us-east-1', credentials }),
client: new V2KMS({ region: 'us-east-1', credentials }),
keyId: eastKeyId,
grantTokens,
})
let encryptedDataKey: EncryptedDataKey

it('can encrypt and create unencrypted data key', async () => {
const material = new WebCryptoEncryptionMaterial(suite, encryptionContext)
const test = await encryptKeyring.onEncrypt(material)
expect(test.hasValidKey()).to.equal(true)
const udk = test.getUnencryptedDataKey()
expect(udk).to.have.lengthOf(suite.keyLengthBytes)
expect(test.encryptedDataKeys).to.have.lengthOf(1)
const [edk] = test.encryptedDataKeys
encryptedDataKey = edk
})

it('can encrypt a pre-existing plaintext data key', async () => {
const seedMaterial = new WebCryptoEncryptionMaterial(
suite,
encryptionContext
).setUnencryptedDataKey(new Uint8Array(suite.keyLengthBytes), {
keyName: 'keyName',
keyNamespace: 'keyNamespace',
flags: KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY,
})
const encryptTest = await encryptKeyring.onEncrypt(seedMaterial)
expect(encryptTest.hasValidKey()).to.equal(true)
expect(encryptTest.encryptedDataKeys).to.have.lengthOf(1)
const [kmsEDK] = encryptTest.encryptedDataKeys
expect(kmsEDK.providerId).to.equal('aws-kms')
expect(kmsEDK.providerInfo).to.equal(westKeyId)
})

it('can decrypt an EncryptedDataKey', async () => {
const suite = new WebCryptoAlgorithmSuite(
AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA256
)
const material = new WebCryptoDecryptionMaterial(suite, encryptionContext)
const test = await decryptKeyring.onDecrypt(material, [encryptedDataKey])
expect(test.hasValidKey()).to.equal(true)
// The UnencryptedDataKey should be zeroed, because the cryptoKey has been set
expect(() => test.getUnencryptedDataKey()).to.throw()
})
})

describe('AwsKmsMrkAwareSymmetricKeyringBrowser can encrypt/decrypt with AWS SDK v3 client', () => {
const westKeyId =
'arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7'
const eastKeyId =
'arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7'
const grantTokens = ['grant']
const encryptionContext = { some: 'context' }
const suite = new WebCryptoAlgorithmSuite(
AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA256
)

const encryptKeyring = new AwsKmsMrkAwareSymmetricKeyringBrowser({
client: new V3KMS({ region: 'us-west-2', credentials }),
keyId: westKeyId,
grantTokens,
})
const decryptKeyring = new AwsKmsMrkAwareSymmetricKeyringBrowser({
client: new V3KMS({ region: 'us-east-1', credentials }),
keyId: eastKeyId,
grantTokens,
})
Expand Down
Loading