@dwn-protocol/id-sdk
Version:
SDK for accessing the features and capabilities
310 lines • 15.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocalKms = exports.defaultAlgorithms = void 0;
const cryptoUtils = __importStar(require("../crypto/utils.js"));
const index_js_1 = require("../crypto/index.js");
const utils_js_1 = require("./utils.js");
const store_managed_key_js_1 = require("./store-managed-key.js");
// Map key operations to algorithm specs to implementations.
exports.defaultAlgorithms = {
'AES-CTR': index_js_1.AesCtrAlgorithm,
ECDH: index_js_1.EcdhAlgorithm,
ECDSA: index_js_1.EcdsaAlgorithm,
EdDSA: index_js_1.EdDsaAlgorithm,
};
class LocalKms {
constructor(options) {
this._supportedAlgorithms = new Map();
const { agent, kmsName, keyStore, privateKeyStore } = options;
this._agent = agent;
this._name = kmsName;
this._keyStore = keyStore !== null && keyStore !== void 0 ? keyStore : new store_managed_key_js_1.KeyStoreMemory();
this._privateKeyStore = privateKeyStore !== null && privateKeyStore !== void 0 ? privateKeyStore : new store_managed_key_js_1.PrivateKeyStoreMemory();
// Merge the default and custom algorithms and register with the KMS.
const cryptoAlgorithms = Object.assign(Object.assign({}, exports.defaultAlgorithms), options.cryptoAlgorithms);
this.registerSupportedAlgorithms(cryptoAlgorithms);
}
/**
* Retrieves the `IDManagedAgent` execution context.
* If the `agent` instance proprety is undefined, it will throw an error.
*
* @returns The `IDManagedAgent` instance that represents the current execution
* context.
*
* @throws Will throw an error if the `agent` instance property is undefined.
*/
get agent() {
if (this._agent === undefined) {
throw new Error('KeyManager: Unable to determine agent execution context.');
}
return this._agent;
}
set agent(agent) {
this._agent = agent;
}
async decrypt(options) {
const { algorithm, data, keyRef } = options;
// Retrieve the ManagedKey from the KMS key metadata store.
const key = await this.getKey({ keyRef });
if ((0, utils_js_1.isManagedKey)(key)) {
const privateManagedKey = await this._privateKeyStore.getKey({
id: key.id,
agent: this.agent
});
if (privateManagedKey !== undefined) {
// Construct a CryptoKey object from the key metadata and private key material.
const privateCryptoKey = this.toCryptoKey(Object.assign(Object.assign({}, key), { material: privateManagedKey.material }));
// Decrypt the data.
const cryptoAlgorithm = this.getAlgorithm(algorithm);
const plaintext = cryptoAlgorithm.decrypt({ algorithm, key: privateCryptoKey, data });
return plaintext;
}
}
throw new Error(`Operation failed: 'decrypt'. Key not found: ${keyRef}`);
}
async deriveBits(options) {
let { algorithm, baseKeyRef, length } = options;
// Retrieve the ManagedKeyPair from the KMS key metadata store.
const ownKeyPair = await this.getKey({ keyRef: baseKeyRef });
if ((0, utils_js_1.isManagedKeyPair)(ownKeyPair)) {
const privateManagedKey = await this._privateKeyStore.getKey({
id: ownKeyPair.privateKey.id,
agent: this.agent
});
if (privateManagedKey !== undefined) {
// Construct a CryptoKey object from the key metadata and private key material.
const privateCryptoKey = this.toCryptoKey(Object.assign(Object.assign({}, ownKeyPair.privateKey), { material: privateManagedKey.material }));
// Derive the shared secret.
const cryptoAlgorithm = this.getAlgorithm(algorithm);
const sharedSecret = cryptoAlgorithm.deriveBits({ algorithm, baseKey: privateCryptoKey, length: length !== null && length !== void 0 ? length : null });
return sharedSecret;
}
}
throw new Error(`Operation failed: 'deriveBits'. Key not found: ${baseKeyRef}`);
}
async encrypt(options) {
const { algorithm, data, keyRef } = options;
// Retrieve the ManagedKey from the KMS key metadata store.
const key = await this.getKey({ keyRef });
if ((0, utils_js_1.isManagedKey)(key)) {
const privateManagedKey = await this._privateKeyStore.getKey({
id: key.id,
agent: this.agent
});
if (privateManagedKey !== undefined) {
// Construct a CryptoKey object from the key metadata and private key material.
const privateCryptoKey = this.toCryptoKey(Object.assign(Object.assign({}, key), { material: privateManagedKey.material }));
// Encrypt the data.
const cryptoAlgorithm = this.getAlgorithm(algorithm);
const ciphertext = cryptoAlgorithm.encrypt({ algorithm, key: privateCryptoKey, data });
return ciphertext;
}
}
throw new Error(`Operation failed: 'encrypt'. Key not found: ${keyRef}`);
}
async generateKey(options) {
let { algorithm, alias, extractable, keyUsages, metadata } = options;
// Get crypto algorithm implementation.
const cryptoAlgorithm = this.getAlgorithm(algorithm);
// Generate the key.
extractable !== null && extractable !== void 0 ? extractable : (extractable = true); // Default to extractable if not specified.
const cryptoKey = await cryptoAlgorithm.generateKey({ algorithm, extractable, keyUsages });
// Create a ManagedKey or ManagedKeyPair using the generated key and store the private key material.
let managedKeyOrKeyPair;
if (cryptoUtils.isCryptoKeyPair(cryptoKey)) {
const privateKeyType = cryptoKey.privateKey.type;
const id = await this._privateKeyStore.importKey({
key: { material: cryptoKey.privateKey.material, type: privateKeyType },
agent: this.agent
});
const managedKeyPair = {
privateKey: this.toManagedKey(Object.assign(Object.assign({}, cryptoKey.privateKey), { id, alias, metadata })),
publicKey: this.toManagedKey(Object.assign(Object.assign({}, cryptoKey.publicKey), { material: cryptoKey.publicKey.material, id, alias, metadata }))
};
managedKeyOrKeyPair = managedKeyPair;
}
else {
const keyType = cryptoKey.type;
const id = await this._privateKeyStore.importKey({
key: { material: cryptoKey.material, type: keyType },
agent: this.agent
});
managedKeyOrKeyPair = this.toManagedKey(Object.assign(Object.assign({}, cryptoKey), { id, alias, metadata }));
}
// Store the ManagedKey or ManagedKeyPair in the KMS key store.
await this._keyStore.importKey({ key: managedKeyOrKeyPair, agent: this.agent });
return managedKeyOrKeyPair;
}
async getKey(options) {
const keyOrKeyPair = this._keyStore.getKey({ id: options.keyRef, agent: this.agent });
return keyOrKeyPair;
}
async importKey(options) {
if ('privateKey' in options) {
// Asymmetric key pair import.
const { privateKey, publicKey } = options;
if (privateKey.type === 'public' && publicKey.type === 'private')
throw new Error(`Import failed due to private and public key mismatch`);
if (!(privateKey.type === 'private' && publicKey.type === 'public'))
throw new TypeError(`Out of range: '${privateKey.type}, ${publicKey.type}'. Must be 'private, public'`);
const id = await this._privateKeyStore.importKey({
key: { material: privateKey.material, type: privateKey.type },
agent: this.agent
});
const managedKeyPair = {
privateKey: this.toManagedKey(Object.assign(Object.assign({}, privateKey), { id, material: undefined })),
publicKey: this.toManagedKey(Object.assign(Object.assign({}, publicKey), { material: publicKey.material, id }))
};
await this._keyStore.importKey({ key: managedKeyPair, agent: this.agent });
return managedKeyPair;
}
const keyType = options.type;
switch (keyType) {
case 'private': {
// Asymmetric private key import.
const material = options.material;
const id = await this._privateKeyStore.importKey({
key: { material, type: keyType },
agent: this.agent
});
const privateManagedKey = this.toManagedKey(Object.assign(Object.assign({}, options), { material: undefined, id }));
await this._keyStore.importKey({ key: privateManagedKey, agent: this.agent });
return privateManagedKey;
}
case 'public': {
// Asymmetric public key import.
const material = options.material;
const publicManagedKey = this.toManagedKey(Object.assign(Object.assign({}, options), { material, id: '' }));
publicManagedKey.id = await this._keyStore.importKey({ key: publicManagedKey, agent: this.agent });
return publicManagedKey;
}
case 'secret': {
// Symmetric secret key import.
const material = options.material;
const id = await this._privateKeyStore.importKey({
key: { material, type: keyType },
agent: this.agent
});
const secretManagedKey = this.toManagedKey(Object.assign(Object.assign({}, options), { material: undefined, id }));
await this._keyStore.importKey({ key: secretManagedKey, agent: this.agent });
return secretManagedKey;
}
default:
throw new TypeError(`Out of range: '${keyType}'. Must be one of 'private, public, secret'`);
}
}
async sign(options) {
const { algorithm, data, keyRef } = options;
// Retrieve the ManagedKeyPair from the KMS key metadata store.
const keyPair = await this.getKey({ keyRef });
if ((0, utils_js_1.isManagedKeyPair)(keyPair)) {
const privateManagedKey = await this._privateKeyStore.getKey({
id: keyPair.privateKey.id,
agent: this.agent
});
if (privateManagedKey !== undefined) {
// Construct a CryptoKey object from the key metadata and private key material.
const privateCryptoKey = this.toCryptoKey(Object.assign(Object.assign({}, keyPair.privateKey), { material: privateManagedKey.material }));
// Sign the data.
const cryptoAlgorithm = this.getAlgorithm(algorithm);
const signature = cryptoAlgorithm.sign({ algorithm, key: privateCryptoKey, data });
return signature;
}
}
throw new Error(`Operation failed: 'sign'. Key not found: ${keyRef}`);
}
async updateKey(options) {
const { keyRef, alias, metadata } = options;
const keyOrKeyPair = await this.getKey({ keyRef });
if (!keyOrKeyPair) {
throw new Error(`Key not found: '${keyRef}'`);
}
const keyId = ((0, utils_js_1.isManagedKeyPair)(keyOrKeyPair))
? keyOrKeyPair.publicKey.id
: keyOrKeyPair.id;
// Update the KMS key metadata store.
return this._keyStore.updateKey({ id: keyId, alias, metadata, agent: this.agent });
}
async verify(options) {
const { algorithm, data, keyRef, signature } = options;
// Retrieve the ManagedKeyPair from the KMS key metadata store.
const keyPair = await this.getKey({ keyRef });
if ((0, utils_js_1.isManagedKeyPair)(keyPair)) {
if (keyPair.publicKey.material === undefined) {
throw new Error(`Required property missing: 'material'`);
}
// Construct a CryptoKey object from the key metadata and private key material.
const publicCryptoKey = this.toCryptoKey(Object.assign(Object.assign({}, keyPair.publicKey), { material: keyPair.publicKey.material }));
// Verify the signature and data.
const cryptoAlgorithm = this.getAlgorithm(algorithm);
const isValid = cryptoAlgorithm.verify({ algorithm, key: publicCryptoKey, signature, data });
return isValid;
}
throw new Error(`Operation failed: 'verify'. Key not found: ${keyRef}`);
}
getAlgorithm(algorithmIdentifier) {
cryptoUtils.checkRequiredProperty({ property: 'name', inObject: algorithmIdentifier });
const algorithm = this._supportedAlgorithms.get(algorithmIdentifier.name.toUpperCase());
if (algorithm === undefined) {
throw new Error(`The algorithm '${algorithmIdentifier.name}' is not supported`);
}
return algorithm.create();
}
registerSupportedAlgorithms(cryptoAlgorithms) {
for (const [name, implementation] of Object.entries(cryptoAlgorithms)) {
// Add the algorithm name and its implementation to the supported algorithms map,
// upper-cased to allow for case-insensitive.
this._supportedAlgorithms.set(name.toUpperCase(), implementation);
}
}
toCryptoKey(managedKey) {
const cryptoKey = {
algorithm: managedKey.algorithm,
extractable: managedKey.extractable,
material: managedKey.material,
type: managedKey.type,
usages: managedKey.usages
};
return cryptoKey;
}
toManagedKey(options) {
const managedKey = {
id: options.id,
algorithm: options.algorithm,
alias: options.alias,
extractable: options.extractable,
kms: this._name,
material: (options.type === 'public') ? options.material : undefined,
metadata: options.metadata,
state: 'Enabled',
type: options.type,
usages: options.usages
};
return managedKey;
}
}
exports.LocalKms = LocalKms;
//# sourceMappingURL=kms-local.js.map