diff --git a/src/lib/crypto/keys/serialisation.spec.ts b/src/lib/crypto/keys/serialisation.spec.ts index 66594a246..e0149801d 100644 --- a/src/lib/crypto/keys/serialisation.spec.ts +++ b/src/lib/crypto/keys/serialisation.spec.ts @@ -31,10 +31,20 @@ describe('Key serializers', () => { expect(publicKeyDer).toEqual(Buffer.from(stubPublicKeyDer)); }); - test('Public key should be extracted first if input is PrivateKey', async () => { - const publicKeyDer = await derSerializePublicKey(stubKeyPair.privateKey); - - expect(publicKeyDer).toEqual(Buffer.from(stubPublicKeyDer)); + test('Provider should be used directly first if input is CryptoKeyWithProvider', async () => { + const mockPublicKey = Buffer.from('mock public key'); + const mockExportKey = jest.fn().mockResolvedValue(mockPublicKey); + const privateKeyWithProvider = { + ...stubKeyPair.privateKey, + provider: { + exportKey: mockExportKey, + }, + }; + + const publicKeyDer = await derSerializePublicKey(privateKeyWithProvider); + + expect(publicKeyDer).toEqual(mockPublicKey); + expect(mockExportKey).toBeCalledWith('spki', privateKeyWithProvider); }); }); diff --git a/src/lib/crypto/keys/serialisation.ts b/src/lib/crypto/keys/serialisation.ts index 449392708..1d4a4a6c7 100644 --- a/src/lib/crypto/keys/serialisation.ts +++ b/src/lib/crypto/keys/serialisation.ts @@ -1,6 +1,7 @@ import bufferToArray from 'buffer-to-arraybuffer'; -import { getEngineForKey, NODE_ENGINE } from '../pkijs'; +import { NODE_ENGINE } from '../pkijs'; +import { CryptoKeyWithProvider } from './CryptoKeyWithProvider'; const DEFAULT_RSA_KEY_PARAMS: RsaHashedImportParams = { hash: { name: 'SHA-256' }, @@ -12,9 +13,19 @@ const DEFAULT_RSA_KEY_PARAMS: RsaHashedImportParams = { * * @param publicKey */ -export async function derSerializePublicKey(publicKey: CryptoKey): Promise { - const engine = getEngineForKey(publicKey); - const publicKeyDer = await engine.exportKey('spki', publicKey); +export async function derSerializePublicKey( + publicKey: CryptoKey | CryptoKeyWithProvider, +): Promise { + let publicKeyDer: ArrayBuffer; + if ((publicKey as CryptoKeyWithProvider).provider) { + // This is likely a KMS-backed private key, so use the provider directly to prevent the + // engine from exporting the key to JWK first. + // https://github.com/relaycorp/cloud-gateway/issues/93 + const provider = (publicKey as CryptoKeyWithProvider).provider; + publicKeyDer = (await provider.exportKey('spki', publicKey as CryptoKey)) as ArrayBuffer; + } else { + publicKeyDer = await NODE_ENGINE.exportKey('spki', publicKey as CryptoKey); + } return Buffer.from(publicKeyDer); }