UNPKG

@relaycorp/webcrypto-kms

Version:

WebCrypto-compatible client for Key Management Services like GCP KMS

98 lines 4.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AwsKmsRsaPssProvider = void 0; const client_kms_1 = require("@aws-sdk/client-kms"); const KmsRsaPssProvider_1 = require("../KmsRsaPssProvider"); const AwsKmsRsaPssPrivateKey_1 = require("./AwsKmsRsaPssPrivateKey"); const KmsError_1 = require("../KmsError"); const buffer_1 = require("../utils/buffer"); const crypto_1 = require("../utils/crypto"); // See: https://docs.aws.amazon.com/kms/latest/developerguide/asymmetric-key-specs.html const SUPPORTED_MODULUS_LENGTHS = [2048, 3072, 4096]; const REQUEST_OPTIONS = { requestTimeout: 3_000 }; class AwsKmsRsaPssProvider extends KmsRsaPssProvider_1.KmsRsaPssProvider { constructor(client) { super(); this.client = client; // See: https://docs.aws.amazon.com/kms/latest/developerguide/asymmetric-key-specs.html this.hashAlgorithms = ['SHA-256', 'SHA-384', 'SHA-512']; } async onGenerateKey(algorithm) { if (!SUPPORTED_MODULUS_LENGTHS.includes(algorithm.modulusLength)) { throw new KmsError_1.KmsError(`Unsupported RSA modulus (${algorithm.modulusLength})`); } const keySpec = `RSA_${algorithm.modulusLength}`; const command = new client_kms_1.CreateKeyCommand({ KeySpec: keySpec, KeyUsage: client_kms_1.KeyUsageType.SIGN_VERIFY, }); const response = await this.client.send(command, REQUEST_OPTIONS); const keyArn = response.KeyMetadata?.Arn; if (!keyArn) { throw new KmsError_1.KmsError('Key creation response is missing KeyMetadata.Arn'); } const privateKey = new AwsKmsRsaPssPrivateKey_1.AwsKmsRsaPssPrivateKey(keyArn, algorithm.hash.name, this); const publicKeySerialised = await this.retrievePublicKey(privateKey); const publicKey = await (0, crypto_1.derDeserialisePublicKey)(publicKeySerialised, algorithm); return { privateKey, publicKey }; } async onExportKey(format, key) { requireAwsKmsKey(key); let keySerialised; if (format === 'raw') { const arnEncoded = Buffer.from(key.arn); keySerialised = (0, buffer_1.bufferToArrayBuffer)(arnEncoded); } else if (format === 'spki') { keySerialised = await this.retrievePublicKey(key); } else { throw new KmsError_1.KmsError(`Private key cannot be exported as ${format}`); } return keySerialised; } async onImportKey(format, keyData, algorithm) { if (format !== 'raw') { throw new KmsError_1.KmsError('Private key can only be exported to raw format'); } const keyArn = Buffer.from(keyData).toString(); return new AwsKmsRsaPssPrivateKey_1.AwsKmsRsaPssPrivateKey(keyArn, algorithm.hash.name, this); } async onSign(_algorithm, key, data) { requireAwsKmsKey(key); const hashingAlgorithm = key.algorithm.hash.name; const digest = await (0, crypto_1.hash)(data, hashingAlgorithm); const awsHashAlgo = `RSASSA_PSS_${hashingAlgorithm.replace('-', '_')}`; const command = new client_kms_1.SignCommand({ KeyId: key.arn, Message: Buffer.from(digest), MessageType: 'DIGEST', SigningAlgorithm: awsHashAlgo, }); const output = await this.client.send(command, REQUEST_OPTIONS); return (0, buffer_1.bufferToArrayBuffer)(output.Signature); } async onVerify() { throw new KmsError_1.KmsError('Signature verification is unsupported'); } async destroyKey(key) { requireAwsKmsKey(key); const command = new client_kms_1.ScheduleKeyDeletionCommand({ KeyId: key.arn }); await this.client.send(command, REQUEST_OPTIONS); } async close() { this.client.destroy(); } async retrievePublicKey(key) { const command = new client_kms_1.GetPublicKeyCommand({ KeyId: key.arn }); const response = await this.client.send(command, REQUEST_OPTIONS); return (0, buffer_1.bufferToArrayBuffer)(response.PublicKey); } } exports.AwsKmsRsaPssProvider = AwsKmsRsaPssProvider; function requireAwsKmsKey(key) { if (!(key instanceof AwsKmsRsaPssPrivateKey_1.AwsKmsRsaPssPrivateKey)) { throw new KmsError_1.KmsError(`Only AWS KMS keys are supported (got ${key.constructor.name})`); } } //# sourceMappingURL=AwsKmsRsaPssProvider.js.map