Skip to content

Commit

Permalink
fix(derSerializePublicKey): Support KMS-backed private keys
Browse files Browse the repository at this point in the history
  • Loading branch information
gnarea committed Jan 18, 2024
1 parent 0745a9d commit 68d9f02
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 8 deletions.
18 changes: 14 additions & 4 deletions src/lib/crypto/keys/serialisation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});

Expand Down
19 changes: 15 additions & 4 deletions src/lib/crypto/keys/serialisation.ts
Original file line number Diff line number Diff line change
@@ -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' },
Expand All @@ -12,9 +13,19 @@ const DEFAULT_RSA_KEY_PARAMS: RsaHashedImportParams = {
*
* @param publicKey
*/
export async function derSerializePublicKey(publicKey: CryptoKey): Promise<Buffer> {
const engine = getEngineForKey(publicKey);
const publicKeyDer = await engine.exportKey('spki', publicKey);
export async function derSerializePublicKey(
publicKey: CryptoKey | CryptoKeyWithProvider,
): Promise<Buffer> {
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);
}

Expand Down

0 comments on commit 68d9f02

Please sign in to comment.