@dwn-protocol/id-sdk
Version:
SDK for accessing the features and capabilities
310 lines • 16.4 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as cryptoUtils from '../crypto/utils.js';
import { EcdhAlgorithm, EcdsaAlgorithm, EdDsaAlgorithm, AesCtrAlgorithm, } from '../crypto/index.js';
import { isManagedKey, isManagedKeyPair } from './utils.js';
import { KeyStoreMemory, PrivateKeyStoreMemory } from './store-managed-key.js';
// Map key operations to algorithm specs to implementations.
export const defaultAlgorithms = {
'AES-CTR': AesCtrAlgorithm,
ECDH: EcdhAlgorithm,
ECDSA: EcdsaAlgorithm,
EdDSA: EdDsaAlgorithm,
};
export 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 KeyStoreMemory();
this._privateKeyStore = privateKeyStore !== null && privateKeyStore !== void 0 ? privateKeyStore : new PrivateKeyStoreMemory();
// Merge the default and custom algorithms and register with the KMS.
const cryptoAlgorithms = Object.assign(Object.assign({}, 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;
}
decrypt(options) {
return __awaiter(this, void 0, void 0, function* () {
const { algorithm, data, keyRef } = options;
// Retrieve the ManagedKey from the KMS key metadata store.
const key = yield this.getKey({ keyRef });
if (isManagedKey(key)) {
const privateManagedKey = yield 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}`);
});
}
deriveBits(options) {
return __awaiter(this, void 0, void 0, function* () {
let { algorithm, baseKeyRef, length } = options;
// Retrieve the ManagedKeyPair from the KMS key metadata store.
const ownKeyPair = yield this.getKey({ keyRef: baseKeyRef });
if (isManagedKeyPair(ownKeyPair)) {
const privateManagedKey = yield 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}`);
});
}
encrypt(options) {
return __awaiter(this, void 0, void 0, function* () {
const { algorithm, data, keyRef } = options;
// Retrieve the ManagedKey from the KMS key metadata store.
const key = yield this.getKey({ keyRef });
if (isManagedKey(key)) {
const privateManagedKey = yield 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}`);
});
}
generateKey(options) {
return __awaiter(this, void 0, void 0, function* () {
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 = yield 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 = yield 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 = yield 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.
yield this._keyStore.importKey({ key: managedKeyOrKeyPair, agent: this.agent });
return managedKeyOrKeyPair;
});
}
getKey(options) {
return __awaiter(this, void 0, void 0, function* () {
const keyOrKeyPair = this._keyStore.getKey({ id: options.keyRef, agent: this.agent });
return keyOrKeyPair;
});
}
importKey(options) {
return __awaiter(this, void 0, void 0, function* () {
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 = yield 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 }))
};
yield 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 = yield this._privateKeyStore.importKey({
key: { material, type: keyType },
agent: this.agent
});
const privateManagedKey = this.toManagedKey(Object.assign(Object.assign({}, options), { material: undefined, id }));
yield 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 = yield this._keyStore.importKey({ key: publicManagedKey, agent: this.agent });
return publicManagedKey;
}
case 'secret': {
// Symmetric secret key import.
const material = options.material;
const id = yield this._privateKeyStore.importKey({
key: { material, type: keyType },
agent: this.agent
});
const secretManagedKey = this.toManagedKey(Object.assign(Object.assign({}, options), { material: undefined, id }));
yield 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'`);
}
});
}
sign(options) {
return __awaiter(this, void 0, void 0, function* () {
const { algorithm, data, keyRef } = options;
// Retrieve the ManagedKeyPair from the KMS key metadata store.
const keyPair = yield this.getKey({ keyRef });
if (isManagedKeyPair(keyPair)) {
const privateManagedKey = yield 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}`);
});
}
updateKey(options) {
return __awaiter(this, void 0, void 0, function* () {
const { keyRef, alias, metadata } = options;
const keyOrKeyPair = yield this.getKey({ keyRef });
if (!keyOrKeyPair) {
throw new Error(`Key not found: '${keyRef}'`);
}
const keyId = (isManagedKeyPair(keyOrKeyPair))
? keyOrKeyPair.publicKey.id
: keyOrKeyPair.id;
// Update the KMS key metadata store.
return this._keyStore.updateKey({ id: keyId, alias, metadata, agent: this.agent });
});
}
verify(options) {
return __awaiter(this, void 0, void 0, function* () {
const { algorithm, data, keyRef, signature } = options;
// Retrieve the ManagedKeyPair from the KMS key metadata store.
const keyPair = yield this.getKey({ keyRef });
if (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;
}
}
//# sourceMappingURL=kms-local.js.map