Skip to content

Commit

Permalink
FABN-835: Refactor CryptoKeyStore (#145)
Browse files Browse the repository at this point in the history
internal code style change for the implementation first

Signed-off-by: david <[email protected]>
  • Loading branch information
davidkhala authored Feb 26, 2020
1 parent 373a6a8 commit c31fa5e
Showing 1 changed file with 69 additions and 51 deletions.
120 changes: 69 additions & 51 deletions fabric-common/lib/impl/CryptoKeyStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,75 +6,100 @@
*/

'use strict';
const {Utils: utils} = require('../../');
const {Utils} = require('../../');
const jsrsasign = require('jsrsasign');
const KEYUTIL = jsrsasign.KEYUTIL;

const ECDSAKey = require('./ecdsa/key.js');
const KeyValueStore = require('../KeyValueStore');

/*
* The mixin enforces the special indexing mechanism with private and public
const _getKeyIndex = (ski, isPrivateKey) => {
if (isPrivateKey) {
return ski + '-priv';
} else {
return ski + '-pub';
}
};

/**
* A CryptoKeyStore uses an underlying instance of {@link module:api.KeyValueStore} implementation
* to persist crypto keys.
*
* This class enforces the special indexing mechanism with private and public
* keys on top of a standard implementation of the KeyValueStore interface
* with the getKey() and putKey() methods
*
* @class
*/
const CryptoKeyStoreMixin = (KeyValueStore) => class extends KeyValueStore {
getKey(ski) {
const self = this;
class CryptoKeyStore extends KeyValueStore {
/**
* @param {KeyValueStore} keyValueStore
*/
constructor(keyValueStore) {
super();
this.keyValueStore = keyValueStore;
}

async initialize() {
await this.keyValueStore.initialize();
}

async getValue(name) {
return await this.keyValueStore.getValue(name);
}

async setValue(name, value) {
await this.keyValueStore.setValue(name, value);
}

async getKey(ski) {
// first try the private key entry, since it encapsulates both
// the private key and public key
return this.getValue(_getKeyIndex(ski, true))
.then((raw) => {
if (raw !== null) {
const privKey = KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(raw);
// TODO: for now assuming ECDSA keys only, need to add support for RSA keys
return new ECDSAKey(privKey);
}

// didn't find the private key entry matching the SKI
// next try the public key entry
return self.getValue(_getKeyIndex(ski, false));
}).then((key) => {
if (key instanceof ECDSAKey) {
return key;
}

if (key !== null) {
const pubKey = KEYUTIL.getKey(key);
return new ECDSAKey(pubKey);
}
});
const raw = await this.getValue(_getKeyIndex(ski, true));

if (raw !== null) {
const privKey = KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(raw);
// TODO: for now assuming ECDSA keys only, need to add support for RSA keys
return new ECDSAKey(privKey);
}

// didn't find the private key entry matching the SKI
// next try the public key entry
const key = await this.getValue(_getKeyIndex(ski, false));
if (key instanceof ECDSAKey) {
return key;
}
if (key !== null) {
const pubKey = KEYUTIL.getKey(key);
return new ECDSAKey(pubKey);
}

}

putKey(key) {
async putKey(key) {
const idx = _getKeyIndex(key.getSKI(), key.isPrivate());
const pem = key.toBytes();
return this.setValue(idx, pem)
.then(() => {
return key;
});
await this.setValue(idx, pem);
return key;
}
};
}

/**
* A CryptoKeyStore uses an underlying instance of {@link module:api.KeyValueStore} implementation
* to persist crypto keys.
*
* @param {function} KVSImplClass Optional. The built-in key store saves private keys.
* The key store may be backed by different {@link KeyValueStore} implementations.
* If specified, the value of the argument must point to a module implementing the
* KeyValueStore interface.
* @param {Object} opts Implementation-specific option object used in the constructor
*
* @class
* @return {CryptoKeyStore}
*/
const CryptoKeyStore = function (KVSImplClass, opts) {
const newInstance = (KVSImplClass, opts) => {
let superClass;

if (typeof KVSImplClass !== 'function') {
let impl_class = utils.getConfigSetting('crypto-value-store');
let impl_class = Utils.getConfigSetting('crypto-value-store');
if (!impl_class) {
impl_class = utils.getConfigSetting('key-value-store');
impl_class = Utils.getConfigSetting('key-value-store');
}
superClass = require(impl_class);
} else {
Expand All @@ -86,17 +111,10 @@ const CryptoKeyStore = function (KVSImplClass, opts) {
opts = KVSImplClass;
}

const MyClass = class extends CryptoKeyStoreMixin(superClass) {
};
return new MyClass(opts);
const keyValueStore = new superClass(opts);

return new CryptoKeyStore(keyValueStore);
};

function _getKeyIndex(ski, isPrivateKey) {
if (isPrivateKey) {
return ski + '-priv';
} else {
return ski + '-pub';
}
}

module.exports = CryptoKeyStore;
module.exports = newInstance;

0 comments on commit c31fa5e

Please sign in to comment.