From 5834c7d5627bb9c2fcc18326a49ba8897995ea53 Mon Sep 17 00:00:00 2001 From: heatherlp Date: Wed, 9 Oct 2019 11:24:26 +0100 Subject: [PATCH] FABN-1391] Refactor cryptosuite tape UT - Created new User, Utils, CryptoSuite UTs - migrated constants to TestUtils - Also removed a duplicate test Signed-off-by: heatherlp Change-Id: Iad69240a46a38c2dd4e7e45ec0b94649f48ae6fb --- .gitignore | 2 + fabric-common/lib/Utils.js | 2 + .../lib/impl/CryptoSuite_ECDSA_AES.js | 2 +- fabric-common/test/TestUtils.js | 42 ++ fabric-common/test/User.js | 33 ++ fabric-common/test/Utils.js | 99 ++++ .../test/impl/CryptoSuite_ECDSA_AES.js | 296 ++++++++++++ fabric-common/test/impl/bccsp_pkcs11.js | 6 - test/unit/constants.js | 83 ---- test/unit/cryptosuite-ecdsa-aes.js | 453 ------------------ 10 files changed, 475 insertions(+), 543 deletions(-) create mode 100644 fabric-common/test/Utils.js create mode 100644 fabric-common/test/impl/CryptoSuite_ECDSA_AES.js delete mode 100644 test/unit/cryptosuite-ecdsa-aes.js diff --git a/.gitignore b/.gitignore index 4a7ceae154..60418dfb51 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ tmp .nyc_output/* *.csv *.heapsnapshot +.scannerwork/* +sonar-project.properties #test files test/temp/** diff --git a/fabric-common/lib/Utils.js b/fabric-common/lib/Utils.js index 45b0a256b8..3456b97c00 100644 --- a/fabric-common/lib/Utils.js +++ b/fabric-common/lib/Utils.js @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +'use strict'; + const Long = require('long'); const util = require('util'); const winston = require('winston'); diff --git a/fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js b/fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js index 3776b7f0da..144fae47f7 100755 --- a/fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js +++ b/fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js @@ -194,7 +194,7 @@ class CryptoSuite_ECDSA_AES extends CryptoSuite { /** * This is an implementation of {@link module:api.CryptoSuite#sign} - * Signs digest using key k. + * Signs digest using key. */ sign(key, digest) { if (typeof key === 'undefined' || key === null) { diff --git a/fabric-common/test/TestUtils.js b/fabric-common/test/TestUtils.js index 7f7520e725..3ff79bfb01 100644 --- a/fabric-common/test/TestUtils.js +++ b/fabric-common/test/TestUtils.js @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +'use strict'; const Long = require('long'); const fs = require('fs'); const path = require('path'); @@ -160,3 +161,44 @@ module.exports.createResponsePayload = (results = 'results') => { return payload.toBuffer(); }; + +module.exports.TEST_KEY_PRIVATE_CERT_PEM = '-----BEGIN CERTIFICATE-----' + +'MIICEDCCAbagAwIBAgIUXoY6X7jIpHAAgL267xHEpVr6NSgwCgYIKoZIzj0EAwIw' + +'fzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' + +'biBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK' + +'BgNVBAsTA1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwMTAzMDEyNDAw' + +'WhcNMTgwMTAzMDEyNDAwWjAQMQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEG' + +'CCqGSM49AwEHA0IABLoGEWBb+rQ/OuTBPlGVZO3jVWBcuC4+/pAq8axbtKorpORw' + +'J/GxahKPLr+vVLPNMyeLcnyJBGgneug+ajE8srijfzB9MA4GA1UdDwEB/wQEAwIF' + +'oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd' + +'BgNVHQ4EFgQU9BUt7QfgDXx9g6zpzCyJGxXsNM0wHwYDVR0jBBgwFoAUF2dCPaqe' + +'gj/ExR2fW8OZ0bWcSBAwCgYIKoZIzj0EAwIDSAAwRQIgcWQbMzluyZsmvQCvGzPg' + +'f5B7ECxK0kdmXPXIEBiizYACIQD2x39Q4oVwO5uL6m3AVNI98C2LZWa0g2iea8wk' + +'BAHpeA==' + +'-----END CERTIFICATE-----'; + +module.exports.TEST_PUBLIC_KEY_SKI = 'f7b61538c52260e83cf4f2693d1' + +'1019f73e7495056c5b54f1e05bae80e9402a7'; + +module.exports.TEST_PRIVATE_KEY_SKI = 'bced195e7aacb5705bbad45598' + +'535d2f41564953680c5cf696becbb2dfebf39c'; + +module.exports.TEST_MSG = 'this is a test message'; +module.exports.TEST_LONG_MSG = 'The Hyperledger project is an open source collaborative effort created to advance cross-industry blockchain technologies. ' + + 'It is a global collaboration including leaders in finance, banking, Internet of Things, supply chains, manufacturing and Technology. The Linux ' + + 'Foundation hosts Hyperledger as a Collaborative Project under the foundation. Why Create the Project? Not since the Web itself has a technology ' + + 'promised broader and more fundamental revolution than blockchain technology. A blockchain is a peer-to-peer distributed ledger forged by consensus, ' + + 'combined with a system for “smart contracts” and other assistive technologies. Together these can be used to build a new generation of transactional ' + + 'applications that establishes trust, accountability and transparency at their core, while streamlining business processes and legal constraints. ' + + 'Think of it as an operating system for marketplaces, data-sharing networks, micro-currencies, and decentralized digital communities. It has the potential ' + + 'to vastly reduce the cost and complexity of getting things done in the real world. Only an Open Source, collaborative software development approach can ' + + 'ensure the transparency, longevity, interoperability and support required to bring blockchain technologies forward to mainstream commercial adoption. That ' + + 'is what Hyperledger is about – communities of software developers building blockchain frameworks and platforms.'; + +module.exports.HASH_MSG_SHA2_256 = '4e4aa09b6d80efbd684e80f54a70c1d8605625c3380f4cb012b32644a002b5be'; +module.exports.HASH_LONG_MSG_SHA2_256 = '0d98987f5e4e3ea611f0e3d768c594ff9aac25404265d73554d12c86d7f6fbbc'; +module.exports.HASH_MSG_SHA2_384 = '6247065855a812ecd182476576c02d46a675845ef4b0056e973ca42dcf8191d3adabc8c6c4b909f20f96136032ab723a'; +module.exports.HASH_MSG_SHA3_256 = '7daeff454f7e91e3cd2d1c1bd5fcd1b6c9d4d5fffc6c327710d8fae7b06ee4a3'; +module.exports.HASH_LONG_MSG_SHA3_256 = '577174210438a85ae4311a62e5fccf2441b960013f5691993cdf38ed6ba0c84f'; +module.exports.HASH_MSG_SHA3_384 = '9e9c2e5edf6cbc0b512807a8efa2917daff71b83e04dee28fcc00b1a1dd935fb5afc5eafa06bf55bd64792a597e2a8f3'; +module.exports.HASH_LONG_MSG_SHA3_384 = '47a90d6721523682e09b81da0a60e6ee1faf839f0503252316638daf038cf682c0a842edaf310eb0f480a2e181a07af0'; diff --git a/fabric-common/test/User.js b/fabric-common/test/User.js index 2b50968af2..ad85f7891b 100644 --- a/fabric-common/test/User.js +++ b/fabric-common/test/User.js @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +'use strict'; + const rewire = require('rewire'); const chai = require('chai'); const chaiAsPromised = require('chai-as-promised'); @@ -12,6 +14,9 @@ chai.use(chaiAsPromised); const User = rewire('../lib/User'); const TestUtils = require('./TestUtils'); +const {Utils} = require('..'); +const path = require('path'); +const fs = require('fs-extra'); describe('User', () => { TestUtils.setCryptoConfigSettings(); @@ -107,6 +112,34 @@ describe('User', () => { // f_user.fromString(string, true); // await f_user._name.should.be.equal('user'); // }); + + it('should throw an error when the private key is missing from a user enrollment object', async () => { + const testUserEnrollment = { + 'name': 'admin2', + 'mspid': 'test', + 'roles': null, + 'affiliation': '', + 'enrollmentSecret': '', + 'enrollment': { + 'signingIdentity': '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a', + 'identity': { + 'certificate': TestUtils.TEST_KEY_PRIVATE_CERT_PEM + } + } + }; + // manufacture an error condition where the private key does not exist for the SKI, and only the public key does + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + await cryptoSuite.importKey(cert); + + fs.removeSync(path.join(Utils.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')); + + const user = new User('admin2'); + user.setCryptoSuite(cryptoSuite); + const enrollmentString = JSON.stringify(testUserEnrollment); + await user.fromString(enrollmentString).should.be.rejectedWith(/Private key missing from key store/); + + }); }); describe('#toString', () => { diff --git a/fabric-common/test/Utils.js b/fabric-common/test/Utils.js new file mode 100644 index 0000000000..55aa04c7b8 --- /dev/null +++ b/fabric-common/test/Utils.js @@ -0,0 +1,99 @@ +/** + * Copyright 2019 IBM All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ +'use strict'; + +const {Utils} = require('..'); +const path = require('path'); +const CryptoSuite_ECDSA_AES = require('../lib/impl/CryptoSuite_ECDSA_AES'); +const testUtils = require('./TestUtils'); + +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); +const sinonChai = require('sinon-chai'); + +const should = chai.should(); +chai.use(chaiAsPromised); +chai.use(sinonChai); + +describe('Utils', () => { + + describe('#newCryptoSuite', () => { + + beforeEach(() => { + testUtils.setCryptoConfigSettings(); + }); + + it('should return a default instance of CryptoSuite_ECDSA_AES with the correct properties', () => { + const defaultCryptoSuite = Utils.newCryptoSuite(); + defaultCryptoSuite.should.be.an.instanceOf(CryptoSuite_ECDSA_AES); + defaultCryptoSuite._keySize.should.equal(256); + should.exist(defaultCryptoSuite._ecdsaCurve); + should.exist(defaultCryptoSuite._ecdsa); + }); + + it('should return an instance of CryptoSuite_ECDSA_AES with the correct keysize', () => { + const cryptoSuite = Utils.newCryptoSuite({keysize: 384, algorithm: 'EC'}); + cryptoSuite.should.be.an.instanceOf(CryptoSuite_ECDSA_AES); + cryptoSuite._keySize.should.equal(384); + }); + + it('should return an instance of CryptoSuite_ECDSA_AES with the correct keysize', () => { + const cryptoSuite = Utils.newCryptoSuite({keysize: 384}); + cryptoSuite.should.be.an.instanceOf(CryptoSuite_ECDSA_AES); + cryptoSuite._keySize.should.equal(384); + }); + + it('should return an instance of CryptoSuite_ECDSA_AES with the default keysize', () => { + const cryptoSuite = Utils.newCryptoSuite({algorithm: 'EC'}); + cryptoSuite.should.be.an.instanceOf(CryptoSuite_ECDSA_AES); + cryptoSuite._keySize.should.equal(256); + }); + + it('should throw an error when an illegal key size is given', () => { + (() => { + Utils.newCryptoSuite({keysize: 123}); + }).should.throw(/Illegal key size/); + }); + + it('should throw an error when using HSM and a fake library path', () => { + Utils.setConfigSetting('crypto-hsm', true); + Utils.setConfigSetting('crypto-suite-hsm', {'EC': 'fabric-common/lib/impl/bccsp_pkcs11.js'}); + const fakePath = path.join('some', 'fake', 'path'); + (() => { + Utils.newCryptoSuite({lib: fakePath, slot: 0, pin: '1234'}); + }).should.throw(fakePath); + }); + it('should throw an error when using HSM and no library path is given', () => { + Utils.setConfigSetting('crypto-hsm', true); + Utils.setConfigSetting('crypto-suite-hsm', {'EC': 'fabric-common/lib/impl/bccsp_pkcs11.js'}); + (() => { + Utils.newCryptoSuite({keysize: 384, algorithm: 'EC'}); + }).should.throw(/PKCS11 library path must be specified/); + }); + + it('should throw an error when an illegal hashing algorithm has been set', () => { + Utils.setConfigSetting('crypto-hash-algo', 19745); + (() => { + Utils.newCryptoSuite({}); + }).should.throw(/Unsupported hash algorithm/); + }); + + it('should throw an error when an unsupported hashing algorithm has been set', () => { + Utils.setConfigSetting('crypto-hash-algo', '12345'); + (() => { + Utils.newCryptoSuite({}); + }).should.throw(/Unsupported hash algorithm and key size pair/); + }); + + it('should throw an error when an incorrect hashing algorithm is specified', () => { + (() => { + Utils.newCryptoSuite({algorithm: 'cake'}); + }).should.throw(/Desired CryptoSuite module not found supporting algorithm/); + }); + + }); + +}); diff --git a/fabric-common/test/impl/CryptoSuite_ECDSA_AES.js b/fabric-common/test/impl/CryptoSuite_ECDSA_AES.js new file mode 100644 index 0000000000..2a0687d5b6 --- /dev/null +++ b/fabric-common/test/impl/CryptoSuite_ECDSA_AES.js @@ -0,0 +1,296 @@ +/** + * Copyright 2019 IBM All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const {Utils} = require('../../'); +const path = require('path'); +const ECDSAKey = require('../../lib/impl/ecdsa/key'); +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); +const sinonChai = require('sinon-chai'); +const testUtils = require('../TestUtils'); +const fs = require('fs-extra'); +const elliptic = require('elliptic'); +const Signature = require('elliptic/lib/elliptic/ec/signature.js'); + +chai.should(); +chai.use(chaiAsPromised); +chai.use(sinonChai); + +describe('CryptoSuite_ECDSA_AES', () => { + + const curveName256String = 'secp256r1'; + const curveName384String = 'secp384r1'; + + beforeEach(() => { + testUtils.setCryptoConfigSettings(); + }); + + describe('#generateEphemeralKey', () => { + + it('should generate an ephemeral key', () => { + const cryptoSuite = Utils.newCryptoSuite(); + const ephemeralKey = cryptoSuite.generateEphemeralKey(); + ephemeralKey.should.be.an.instanceOf(ECDSAKey); + ephemeralKey._key.type.should.equal('EC'); + }); + + }); + + describe('#generateKey', () => { + + it('should generate a public key with the correct curveName', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + const key = await cryptoSuite.generateKey(); + key.should.be.an.instanceOf(ECDSAKey); + const curveName = key.getPublicKey()._key.curveName; + curveName.should.equal(curveName256String); + }); + + it('should generate a public key with the correct curveName for non-default 384 keysize', async () => { + const cryptoSuite = Utils.newCryptoSuite({keysize: 384}); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + const key = await cryptoSuite.generateKey(); + const curveName = key.getPublicKey()._key.curveName; + curveName.should.equal(curveName384String); + }); + + it('should generate an ephemeral key when specified', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + const key = await cryptoSuite.generateKey({ephemeral: true}); + key.should.be.an.instanceOf(ECDSAKey); + const curveName = key.getPublicKey()._key.curveName; + curveName.should.equal(curveName256String); + }); + + it('should throw an error when the cryptoKeyStore property has not been set', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + await cryptoSuite.generateKey().should.be.rejectedWith('generateKey requires CryptoKeyStore to be set.'); + }); + + }); + + describe('#createKeyFromRaw', () => { + + it('should generate a key from raw private key', () => { + const cryptoSuite = Utils.newCryptoSuite(); + const privateKey = cryptoSuite.createKeyFromRaw(testUtils.keyAsPEM); + privateKey.should.be.an.instanceOf(ECDSAKey); + privateKey._key.type.should.equal('EC'); + privateKey._key.isPrivate.should.be.true; + }); + + it('should throw an error if the key cannot be parsed', () => { + const cryptoSuite = Utils.newCryptoSuite(); + (() => { + cryptoSuite.createKeyFromRaw('wrongKey'); + }).should.throw(/Failed to parse key from PEM/); + }); + + }); + + describe('#importKey', () => { + + it('should return a public key', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + const key = await cryptoSuite.importKey(testUtils.certificateAsPEM); + key.isPrivate().should.equal(false); + key.getSKI().should.equal(testUtils.TEST_PUBLIC_KEY_SKI); + }); + + it('should store the imported public key in the correct directory', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + await cryptoSuite.importKey(testUtils.certificateAsPEM); + const keyDir = path.join(Utils.getDefaultKeyStorePath(), 'f7b61538c52260e83cf4f2693d11019f73e7495056c5b54f1e05bae80e9402a7-pub'); + fs.existsSync(keyDir).should.equal(true); + }); + + it('should return a private key', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + const key = await cryptoSuite.importKey(testUtils.keyAsPEM); + key.isPrivate().should.equal(true); + key.getSKI().should.equal(testUtils.TEST_PRIVATE_KEY_SKI); + }); + + it('should store the imported private key in the correct directory', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + await cryptoSuite.importKey(testUtils.keyAsPEM); + const keyDir = path.join(Utils.getDefaultKeyStorePath(), 'bced195e7aacb5705bbad45598535d2f41564953680c5cf696becbb2dfebf39c-priv'); + fs.existsSync(keyDir).should.equal(true); + }); + + it('should throw an error when the cryptoKeyStore property has not been set', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + await cryptoSuite.importKey(testUtils.certificateAsPEM).should.be.rejectedWith('importKey requires CryptoKeyStore to be set.'); + }); + + }); + + describe('#getKey', () => { + it('should throw an error when the cryptoKeyStore property has not been set', async () => { + const cryptoSuite = Utils.newCryptoSuite(); + await cryptoSuite.getKey(testUtils.certificateAsPEM).should.be.rejectedWith('getKey requires CryptoKeyStore to be set.'); + }); + + }); + + describe('#hash', () => { + + it('should return a SHA2 256-bit hash signature for a string using default key size', () => { + const cryptoSuite = Utils.newCryptoSuite(); + const hashString = cryptoSuite.hash(testUtils.TEST_MSG); + hashString.should.equal(testUtils.HASH_MSG_SHA2_256); + }); + + it('should return a SHA2 256-bit hash signature for a long string using default key size', () => { + const cryptoSuite = Utils.newCryptoSuite(); + const hashString = cryptoSuite.hash(testUtils.TEST_LONG_MSG); + hashString.should.equal(testUtils.HASH_LONG_MSG_SHA2_256); + }); + + it('should return a SHA2 384-bit hash signature for a string using a key size of 384', () => { + const cryptoSuite = Utils.newCryptoSuite({keysize: 384}); + const hashString = cryptoSuite.hash(testUtils.TEST_MSG); + hashString.should.equal(testUtils.HASH_MSG_SHA2_384); + }); + + it('should return a SHA3 256-bit hash signature for a string using default key size', () => { + Utils.setConfigSetting('crypto-hash-algo', 'SHA3'); + const cryptoSuite = Utils.newCryptoSuite(); + const hashString = cryptoSuite.hash(testUtils.TEST_MSG); + hashString.should.equal(testUtils.HASH_MSG_SHA3_256); + }); + + it('should return a SHA3 256-bit hash signature for a long string using default key size', () => { + Utils.setConfigSetting('crypto-hash-algo', 'sha3'); // lower case should be handled + const cryptoSuite = Utils.newCryptoSuite(); + const hashString = cryptoSuite.hash(testUtils.TEST_LONG_MSG); + hashString.should.equal(testUtils.HASH_LONG_MSG_SHA3_256); + }); + + it('should return a SHA3 384-bit hash signature for a string using a key size of 384', () => { + Utils.setConfigSetting('crypto-hash-algo', 'SHA3'); + const cryptoSuite = Utils.newCryptoSuite({keysize: 384}); + const hashString = cryptoSuite.hash(testUtils.TEST_MSG); + hashString.should.equal(testUtils.HASH_MSG_SHA3_384); + }); + + it('should return a SHA3 384-bit hash signature for a long string using a key size of 384', () => { + Utils.setConfigSetting('crypto-hash-algo', 'sha3'); // lower case should be handled + const cryptoSuite = Utils.newCryptoSuite({keysize: 384}); + const hashString = cryptoSuite.hash(testUtils.TEST_LONG_MSG); + hashString.should.equal(testUtils.HASH_LONG_MSG_SHA3_384); + }); + + }); + + describe('#sign', () => { + + let cryptoSuite; + let key; + let hash; + let signature; + let halfOrder; + const halfOrdersForCurve = { + 'secp256r1': elliptic.curves.p256.n.shrn(1), + 'secp384r1': elliptic.curves.p384.n.shrn(1) + }; + + beforeEach(async () => { + cryptoSuite = Utils.newCryptoSuite(); + cryptoSuite.setCryptoKeyStore(Utils.newCryptoKeyStore()); + key = await cryptoSuite.generateKey(); + }); + + it('should return a signature of a string with a good s-value', async () => { + hash = cryptoSuite.hash(testUtils.TEST_MSG); + signature = cryptoSuite.sign(key, hash); + halfOrder = halfOrdersForCurve[key._key.ecparams.name]; + const signatureObject = new Signature(signature); + const bigNumberComparison = signatureObject.s.cmp(halfOrder); + // Expect the generated signature object to have an S value below N/2 + bigNumberComparison.should.equal(-1); + }); + + it('should return a verifiable signature of a string using the given key', async () => { + hash = cryptoSuite.hash(testUtils.TEST_MSG); + signature = cryptoSuite.sign(key, hash); + halfOrder = halfOrdersForCurve[key._key.ecparams.name]; + const publicKey = cryptoSuite._ecdsa.keyFromPublic(key.getPublicKey()._key.pubKeyHex, 'hex'); + const signatureBuffer = Buffer.from(signature); + const verifyResults = publicKey.verify(hash, signatureBuffer); + verifyResults.should.equal(true); + }); + + it('should return a signature of a long string with a good s-value', async () => { + hash = cryptoSuite.hash(testUtils.TEST_LONG_MSG); + signature = cryptoSuite.sign(key, hash); + halfOrder = halfOrdersForCurve[key._key.ecparams.name]; + const signatureObject = new Signature(signature); + const bigNumberComparison = signatureObject.s.cmp(halfOrder); + // Expect the generated signature object to have an S value below N/2 + bigNumberComparison.should.equal(-1); + }); + + it('should return a verifiable signature of a long string using the given key', async () => { + hash = cryptoSuite.hash(testUtils.TEST_LONG_MSG); + signature = cryptoSuite.sign(key, hash); + halfOrder = halfOrdersForCurve[key._key.ecparams.name]; + const publicKey = cryptoSuite._ecdsa.keyFromPublic(key.getPublicKey()._key.pubKeyHex, 'hex'); + const signatureBuffer = Buffer.from(signature); + const verifyResults = publicKey.verify(hash, signatureBuffer); + verifyResults.should.equal(true); + }); + + describe('errors', () => { + it('should throw an error when a key is not defined', () => { + cryptoSuite = Utils.newCryptoSuite(); + (() => { + cryptoSuite.sign(); + }).should.throw(/A valid key is required to sign/); + }); + + it('should throw an error when a signing message is not defined', () => { + cryptoSuite = Utils.newCryptoSuite(); + (() => { + cryptoSuite.sign('dummy key'); + }).should.throw(/A valid message is required to sign/); + }); + }); + }); + + describe('#verify', () => { + + it('should throw an error when no key is specified', () => { + const cryptoSuite = Utils.newCryptoSuite(); + (() => { + cryptoSuite.verify(); + }).should.throw(/A valid key is required to verify/); + }); + + it('should throw an error when no signature is specified', () => { + const cryptoSuite = Utils.newCryptoSuite(); + (() => { + cryptoSuite.verify('dummy key'); + }).should.throw(/A valid signature is required to verify/); + }); + + it('should throw an error when no message is specified', () => { + const cryptoSuite = Utils.newCryptoSuite(); + (() => { + cryptoSuite.verify('dummy key', 'dummy signature'); + }).should.throw(/A valid message is required to verify/); + }); + + }); +}); diff --git a/fabric-common/test/impl/bccsp_pkcs11.js b/fabric-common/test/impl/bccsp_pkcs11.js index 926ad68ab0..4d5d7c4b7f 100644 --- a/fabric-common/test/impl/bccsp_pkcs11.js +++ b/fabric-common/test/impl/bccsp_pkcs11.js @@ -56,12 +56,6 @@ describe('CryptoSuite_PKCS11', () => { }).should.throw(/PKCS11 library path must be specified/); }); - it('should throw when no library path is given', () => { - (() => { - new PKCS11_Rewire(256); - }).should.throw(/PKCS11 library path must be specified/); - }); - it('should throw if pkcs11 slot not given', () => { (() => { new PKCS11_Rewire(256, 'sha2', {lib: '/temp'}); diff --git a/test/unit/constants.js b/test/unit/constants.js index cb612b9d31..f987362e6c 100644 --- a/test/unit/constants.js +++ b/test/unit/constants.js @@ -8,89 +8,6 @@ const path = require('path'); // test temp directory is /fabric-sdk-node/test/temp const tempdir = path.join(__dirname, '../temp'); -const TEST_CERT_PEM = '-----BEGIN CERTIFICATE-----' + -'MIIDVDCCAvqgAwIBAgIBATAKBggqhkjOPQQDAjBOMRMwEQYDVQQKDArOoyBBY21l' + -'IENvMRkwFwYDVQQDExB0ZXN0LmV4YW1wbGUuY29tMQ8wDQYDVQQqEwZHb3BoZXIx' + -'CzAJBgNVBAYTAk5MMB4XDTE2MTIxNjIzMTAxM1oXDTE2MTIxNzAxMTAxM1owTjET' + -'MBEGA1UECgwKzqMgQWNtZSBDbzEZMBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTEP' + -'MA0GA1UEKhMGR29waGVyMQswCQYDVQQGEwJOTDBZMBMGByqGSM49AgEGCCqGSM49' + -'AwEHA0IABFKnXh7hBdp6s9OJ/aadigT1z2WzBbSc7Hzb3rkaWFz4e+9alqqWg9lr' + -'ur/mDYzG9dudC8jFjVa7KIh+2BxgBayjggHHMIIBwzAOBgNVHQ8BAf8EBAMCAgQw' + -'JgYDVR0lBB8wHQYIKwYBBQUHAwIGCCsGAQUFBwMBBgIqAwYDgQsBMA8GA1UdEwEB' + -'/wQFMAMBAf8wDQYDVR0OBAYEBAECAwQwDwYDVR0jBAgwBoAEAQIDBDBiBggrBgEF' + -'BQcBAQRWMFQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY0JDQ1NQLmV4YW1wbGUuY29t' + -'MCoGCCsGAQUFBzAChh5odHRwOi8vY3J0LmV4YW1wbGUuY29tL2NhMS5jcnQwRgYD' + -'VR0RBD8wPYIQdGVzdC5leGFtcGxlLmNvbYERZ29waGVyQGdvbGFuZy5vcmeHBH8A' + -'AAGHECABSGAAACABAAAAAAAAAGgwDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAh' + -'oB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4YW1wbGUuY29tMFcGA1UdHwRQME4wJaAj' + -'oCGGH2h0dHA6Ly9jcmwxLmV4YW1wbGUuY29tL2NhMS5jcmwwJaAjoCGGH2h0dHA6' + -'Ly9jcmwyLmV4YW1wbGUuY29tL2NhMS5jcmwwFgYDKgMEBA9leHRyYSBleHRlbnNp' + -'b24wCgYIKoZIzj0EAwIDSAAwRQIgcguBb6FUxO+X8DbY17gpqSGuNC4NT4BddPg1' + -'UWUxIC0CIQDNyHQAwzhw+512meXRwG92GfpzSBssDKLdwlrqiHOu5A==' + -'-----END CERTIFICATE-----'; - -const TEST_KEY_PRIVATE_PEM = '-----BEGIN PRIVATE KEY-----' + -'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZYMvf3w5VkzzsTQY' + -'I8Z8IXuGFZmmfjIX2YSScqCvAkihRANCAAS6BhFgW/q0PzrkwT5RlWTt41VgXLgu' + -'Pv6QKvGsW7SqK6TkcCfxsWoSjy6/r1SzzTMni3J8iQRoJ3roPmoxPLK4' + -'-----END PRIVATE KEY-----'; - -const TEST_KEY_PRIVATE_CERT_PEM = '-----BEGIN CERTIFICATE-----' + -'MIICEDCCAbagAwIBAgIUXoY6X7jIpHAAgL267xHEpVr6NSgwCgYIKoZIzj0EAwIw' + -'fzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh' + -'biBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK' + -'BgNVBAsTA1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwMTAzMDEyNDAw' + -'WhcNMTgwMTAzMDEyNDAwWjAQMQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEG' + -'CCqGSM49AwEHA0IABLoGEWBb+rQ/OuTBPlGVZO3jVWBcuC4+/pAq8axbtKorpORw' + -'J/GxahKPLr+vVLPNMyeLcnyJBGgneug+ajE8srijfzB9MA4GA1UdDwEB/wQEAwIF' + -'oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd' + -'BgNVHQ4EFgQU9BUt7QfgDXx9g6zpzCyJGxXsNM0wHwYDVR0jBBgwFoAUF2dCPaqe' + -'gj/ExR2fW8OZ0bWcSBAwCgYIKoZIzj0EAwIDSAAwRQIgcWQbMzluyZsmvQCvGzPg' + -'f5B7ECxK0kdmXPXIEBiizYACIQD2x39Q4oVwO5uL6m3AVNI98C2LZWa0g2iea8wk' + -'BAHpeA==' + -'-----END CERTIFICATE-----'; - -const TEST_MSG = 'this is a test message'; -const TEST_LONG_MSG = 'The Hyperledger project is an open source collaborative effort created to advance cross-industry blockchain technologies. ' + - 'It is a global collaboration including leaders in finance, banking, Internet of Things, supply chains, manufacturing and Technology. The Linux ' + - 'Foundation hosts Hyperledger as a Collaborative Project under the foundation. Why Create the Project? Not since the Web itself has a technology ' + - 'promised broader and more fundamental revolution than blockchain technology. A blockchain is a peer-to-peer distributed ledger forged by consensus, ' + - 'combined with a system for “smart contracts” and other assistive technologies. Together these can be used to build a new generation of transactional ' + - 'applications that establishes trust, accountability and transparency at their core, while streamlining business processes and legal constraints. ' + - 'Think of it as an operating system for marketplaces, data-sharing networks, micro-currencies, and decentralized digital communities. It has the potential ' + - 'to vastly reduce the cost and complexity of getting things done in the real world. Only an Open Source, collaborative software development approach can ' + - 'ensure the transparency, longevity, interoperability and support required to bring blockchain technologies forward to mainstream commercial adoption. That ' + - 'is what Hyperledger is about – communities of software developers building blockchain frameworks and platforms.'; - -const HASH_MSG_SHA384 = '6247065855a812ecd182476576c02d46a675845ef4b0056e973ca42dcf8191d3adabc8c6c4b909f20f96136032ab723a'; -const HASH_MSG_SHA3_384 = '9e9c2e5edf6cbc0b512807a8efa2917daff71b83e04dee28fcc00b1a1dd935fb5afc5eafa06bf55bd64792a597e2a8f3'; -const HASH_LONG_MSG_SHA3_384 = '47a90d6721523682e09b81da0a60e6ee1faf839f0503252316638daf038cf682c0a842edaf310eb0f480a2e181a07af0'; -const HASH_MSG_SHA256 = '4e4aa09b6d80efbd684e80f54a70c1d8605625c3380f4cb012b32644a002b5be'; -const HASH_LONG_MSG_SHA256 = '0d98987f5e4e3ea611f0e3d768c594ff9aac25404265d73554d12c86d7f6fbbc'; -const HASH_MSG_SHA3_256 = '7daeff454f7e91e3cd2d1c1bd5fcd1b6c9d4d5fffc6c327710d8fae7b06ee4a3'; -const HASH_LONG_MSG_SHA3_256 = '577174210438a85ae4311a62e5fccf2441b960013f5691993cdf38ed6ba0c84f'; - -const TEST_KEY_PRIVATE = '93f15b31e3c3f3bddcd776d9219e93d8559e31453757b79e193a793cbd239573'; -const TEST_KEY_PUBLIC = '04f46815aa00fe2ba2814b906aa4ef1755caf152658de8997a6a858088296054baf45b06b2eba514bcbc37ae0c0cc7465115d36429d0e0bff23dc40e3760c10aa9'; -const TEST_MSG_SIGNATURE_SHA2_256 = '3046022100a6460b29373fa16ee96172bfe04666140405fdef78182280545d451f08547736022100d9022fe620ceadabbef1714b894b8d6be4b74c0f9c573bd774871764f4f789c9'; -const TEST_LONG_MSG_SIGNATURE_SHA2_256 = '3045022073266302d730b07499aabd0f88f12c8749a0f90144034dbc86a8cd742722ad29022100852346f93e50911008ab97afc452f83c5985a19fa3aa6d58f615c03bddaa90a1'; - module.exports = { tempdir: tempdir, - TEST_CERT_PEM: TEST_CERT_PEM, - TEST_KEY_PRIVATE_PEM: TEST_KEY_PRIVATE_PEM, - TEST_KEY_PRIVATE_CERT_PEM: TEST_KEY_PRIVATE_CERT_PEM, - TEST_MSG: TEST_MSG, - TEST_LONG_MSG: TEST_LONG_MSG, - HASH_MSG_SHA384: HASH_MSG_SHA384, - HASH_MSG_SHA3_384: HASH_MSG_SHA3_384, - HASH_LONG_MSG_SHA3_384: HASH_LONG_MSG_SHA3_384, - HASH_MSG_SHA256: HASH_MSG_SHA256, - HASH_LONG_MSG_SHA256: HASH_LONG_MSG_SHA256, - HASH_MSG_SHA3_256: HASH_MSG_SHA3_256, - HASH_LONG_MSG_SHA3_256: HASH_LONG_MSG_SHA3_256, - TEST_KEY_PRIVATE: TEST_KEY_PRIVATE, - TEST_KEY_PUBLIC: TEST_KEY_PUBLIC, - TEST_MSG_SIGNATURE_SHA2_256: TEST_MSG_SIGNATURE_SHA2_256, - TEST_LONG_MSG_SIGNATURE_SHA2_256: TEST_LONG_MSG_SIGNATURE_SHA2_256 }; diff --git a/test/unit/cryptosuite-ecdsa-aes.js b/test/unit/cryptosuite-ecdsa-aes.js deleted file mode 100644 index 150a0cdeb2..0000000000 --- a/test/unit/cryptosuite-ecdsa-aes.js +++ /dev/null @@ -1,453 +0,0 @@ -/** - * Copyright 2016-2017 IBM All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const tape = require('tape'); -const _test = require('tape-promise').default; -const test = _test(tape); - -const testutil = require('./util.js'); -const {Utils:utils, User} = require('fabric-common'); -const path = require('path'); -const fs = require('fs-extra'); -const util = require('util'); - -const jsrsa = require('jsrsasign'); -const ECDSA = jsrsa.ECDSA; - -const CryptoSuite_ECDSA_AES = require('fabric-common/lib/impl/CryptoSuite_ECDSA_AES.js'); -const ecdsaKey = require('fabric-common/lib/impl/ecdsa/key.js'); -const elliptic = require('elliptic'); -const Signature = require('elliptic/lib/elliptic/ec/signature.js'); - -const constants = require('./constants'); -const TEST_MSG = constants.TEST_MSG; -const TEST_LONG_MSG = constants.TEST_LONG_MSG; -const HASH_MSG_SHA384 = constants.HASH_MSG_SHA384; -const HASH_MSG_SHA3_384 = constants.HASH_MSG_SHA3_384; -const HASH_LONG_MSG_SHA3_384 = constants.HASH_LONG_MSG_SHA3_384; -const HASH_MSG_SHA256 = constants.HASH_MSG_SHA256; -const HASH_LONG_MSG_SHA256 = constants.HASH_LONG_MSG_SHA256; -const HASH_MSG_SHA3_256 = constants.HASH_MSG_SHA3_256; -const HASH_LONG_MSG_SHA3_256 = constants.HASH_LONG_MSG_SHA3_256; -const TEST_KEY_PRIVATE = constants.TEST_KEY_PRIVATE; -const TEST_KEY_PUBLIC = constants.TEST_KEY_PUBLIC; -const TEST_MSG_SIGNATURE_SHA2_256 = constants.TEST_MSG_SIGNATURE_SHA2_256; -const TEST_LONG_MSG_SIGNATURE_SHA2_256 = constants.TEST_LONG_MSG_SIGNATURE_SHA2_256; -const TEST_CERT_PEM = constants.TEST_CERT_PEM; -const TEST_KEY_PRIVATE_PEM = constants.TEST_KEY_PRIVATE_PEM; -const TEST_KEY_PRIVATE_CERT_PEM = constants.TEST_KEY_PRIVATE_CERT_PEM; - -const TEST_USER_ENROLLMENT = { - 'name': 'admin2', - 'mspid': 'test', - 'roles': null, - 'affiliation': '', - 'enrollmentSecret': '', - 'enrollment': { - 'signingIdentity': '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a', - 'identity': { - 'certificate': TEST_KEY_PRIVATE_CERT_PEM - } - } -}; - -const halfOrdersForCurve = { - 'secp256r1': elliptic.curves.p256.n.shrn(1), - 'secp384r1': elliptic.curves.p384.n.shrn(1) -}; - -test('\n\n** utils.newCryptoSuite tests **\n\n', (t) => { - testutil.resetDefaults(); - - let cs = utils.newCryptoSuite({keysize: 384, algorithm: 'EC'}); - t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Should return an instance of CryptoSuite_ECDSA_AES'); - t.equal(cs._keySize, 384, 'Returned instance should have keysize of 384'); - - cs = utils.newCryptoSuite({keysize: 384}); - t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Default test: should return an instance of CryptoSuite_ECDSA_AES'); - t.equal(cs._keySize, 384, 'Returned instance should have keysize of 384'); - - cs = utils.newCryptoSuite({algorithm: 'EC'}); - t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Should return an instance of CryptoSuite_ECDSA_AES'); - t.equal(cs._keySize, 256, 'Returned instance should have keysize of 256'); - - // each app instance is expected to use either HSM or software-based key management, as such this question - // is answered with a config setting rather than controlled on a case-by-case basis - utils.setConfigSetting('crypto-hsm', true); - /* eslint-disable-next-line */ - let expectedError = '/Error:.*\/usr\/local\/lib/'; - if (process.platform === 'win32') { - expectedError = 'Error: Win32 error 126/'; - } - t.throws( - () => { - cs = utils.newCryptoSuite({lib: '/usr/local/lib', slot: 0, pin: '1234'}); - }, - expectedError, - 'Should attempt to load the bccsp_pkcs11 module and fail because of the dummy library path' - ); - - // Control crypto-hsm settings via env variable - process.env.CRYPTO_HSM = false; - testutil.resetDefaults(); - cs = utils.newCryptoSuite({keysize: 384, algorithm: 'EC'}); - t.equal(cs instanceof CryptoSuite_ECDSA_AES, true, 'Should return an instance of CryptoSuite_ECDSA_AES'); - t.equal(cs._keySize, 384, 'Returned instance should have keysize of 384'); - - process.env.CRYPTO_HSM = true; - testutil.resetDefaults(); - t.throws( - () => { - cs = utils.newCryptoSuite({keysize: 384, algorithm: 'EC'}); - }, - /PKCS11 library path must be specified/, - 'Should attempt to load the bccsp_pkcs11 module and fail because of the lack of library path' - ); - - process.env.CRYPTO_HSM = true; - testutil.resetDefaults(); - t.throws( - () => { - cs = utils.newCryptoSuite({lib: '/usr/local/lib', slot: 0, pin: '1234'}); - }, - expectedError, - 'Should attempt to load the bccsp_pkcs11 module and fail because of the dummy library path' - ); - // Need to set it 'undefined' to prevent side effect to the other test suites - process.env.CRYPTO_HSM = undefined; - t.end(); -}); - -test('\n\n ** CryptoSuite_ECDSA_AES - error tests **\n\n', async (t) => { - testutil.resetDefaults(); - const cryptoUtils = utils.newCryptoSuite(); - - try { - await cryptoUtils.importKey(TEST_CERT_PEM); - t.fail('Import key did not fail when testing missing cryptoKeyStore'); - } catch (err) { - t.ok(err.toString() - .includes('importKey requires CryptoKeyStore to be set.'), - 'Test missing cryptoKeyStore: cryptoSuite.importKey'); - } - - try { - await cryptoUtils.generateKey(); - t.fail('generateKey did not fail when testing missing cryptoKeyStore'); - } catch (err) { - t.ok(err.toString() - .includes('generateKey requires CryptoKeyStore to be set.'), - 'Test missing cryptoKeyStore: cryptoSuite.generateKey'); - } - - t.end(); -}); - -test('\n\n ** CryptoSuite_ECDSA_AES - generateEphemeralKey tests **\n\n', (t) => { - testutil.resetDefaults(); - const cryptoUtils = utils.newCryptoSuite(); - const key = cryptoUtils.generateEphemeralKey(); - if (key && key._key && key._key.type === 'EC') { - t.pass('generateEphemeralKey returned key'); - t.end(); - } else { - t.fail('generateEphemeralKey did not return key'); - t.end(); - } - -}); - -test('\n\n ** CryptoSuite_ECDSA_AES - createKeyFromRaw **\n\n', async (t) => { - testutil.resetDefaults(); - const cryptoUtils = utils.newCryptoSuite(); - const key = cryptoUtils.createKeyFromRaw(TEST_KEY_PRIVATE_PEM); - if (key && key._key && key._key.type === 'EC') { - t.pass('importKey returned key using ephemeral true'); - } else { - t.fail('importKey did not return key using ephemeral true'); - } -}); - -test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', (t) => { - testutil.resetDefaults(); - - let cryptoUtils = utils.newCryptoSuite(); - - t.equal(true, (typeof cryptoUtils._ecdsaCurve !== 'undefined' && typeof cryptoUtils._ecdsa !== 'undefined'), - 'CryptoSuite_ECDSA_AES function tests: default instance has "_ecdsaCurve" and "_ecdsa" properties'); - - // test default curve 256 with SHA256 - t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA256, - 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with default key size which should be 256'); - - t.equal(cryptoUtils.hash(TEST_LONG_MSG), HASH_LONG_MSG_SHA256, - 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with default key size which should be 256'); - - // test SHA384 hash - utils.setConfigSetting('crypto-keysize', 384); - cryptoUtils = utils.newCryptoSuite(); - t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA384, - 'CryptoSuite_ECDSA_AES function tests: using "SHA2" hashing algorithm with default key size which should be 384'); - - // reset to default key size - utils.setConfigSetting('crypto-keysize', 256); - utils.setConfigSetting('key-value-store', 'fabric-common/lib/impl/FileKeyValueStore.js');// force for gulp test - cryptoUtils = utils.newCryptoSuite(); - cryptoUtils.setCryptoKeyStore(utils.newCryptoKeyStore()); - - cryptoUtils.generateKey() - .then((key) => { - t.equal('secp256r1', key.getPublicKey()._key.curveName, - 'CryptoSuite_ECDSA_AES function tests: cryptoUtils generated public key curveName == secp256r1'); - - // test curve 256 with SHA3_256 - utils.setConfigSetting('crypto-hash-algo', 'SHA3'); - utils.setConfigSetting('crypto-keysize', 256); - cryptoUtils = utils.newCryptoSuite(); - cryptoUtils.setCryptoKeyStore(utils.newCryptoKeyStore()); - return cryptoUtils.generateKey(); - }, (err) => { - t.fail('Failed to generateKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then((key) => { - t.equal('secp256r1', key.getPublicKey()._key.curveName, - 'CryptoSuite_ECDSA_AES function tests: ccryptoUtils generated public key curveName == secp256r1'); - - t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA3_256, - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 256'); - - t.equal(cryptoUtils.hash(TEST_LONG_MSG), HASH_LONG_MSG_SHA3_256, - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 256'); - - // test SHA3_384 - utils.setConfigSetting('crypto-hash-algo', 'SHA3'); - utils.setConfigSetting('crypto-keysize', 384); - cryptoUtils = utils.newCryptoSuite(); - cryptoUtils.setCryptoKeyStore(utils.newCryptoKeyStore()); - - t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA3_384, - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 384'); - - t.equal(cryptoUtils.hash(TEST_LONG_MSG), HASH_LONG_MSG_SHA3_384, - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 384'); - - return cryptoUtils.generateKey(); - }, (err) => { - t.fail('Failed to generateKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then((key) => { - t.equal('secp384r1', key.getPublicKey()._key.curveName, - 'CryptoSuite_ECDSA_AES function tests: ccryptoUtils generated public key curveName == secp384r1'); - - if (key._key) { - t.pass('CryptoSuite_ECDSA_AES function tests: verify generateKey return object'); - } else { - t.fail('CryptoSuite_ECDSA_AES function tests: verify generateKey return object'); - } - - utils.setConfigSetting('crypto-hash-algo', 'sha3'); // lower or upper case is allowed - cryptoUtils = utils.newCryptoSuite(); - cryptoUtils.setCryptoKeyStore(utils.newCryptoKeyStore()); - - t.equal(cryptoUtils.hash(TEST_MSG), HASH_MSG_SHA3_384, - 'CryptoSuite_ECDSA_AES function tests: using "SHA3" hashing algorithm with key size 384'); - - // test generation options - return cryptoUtils.generateKey({ephemeral: true}); - }, (err) => { - t.fail('Failed to generateKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then((key) => { - if (key._key) { - t.pass('CryptoSuite_ECDSA_AES function tests: verify generateKey ephemeral=true return object'); - } else { - t.fail('CryptoSuite_ECDSA_AES function tests: verify generateKey ephemeral=true return object'); - } - - t.throws( - () => { - utils.setConfigSetting('crypto-keysize', 123); - cryptoUtils = utils.newCryptoSuite(); - }, - /^Error: Illegal key size/, - 'CryptoSuite_ECDSA_AES function tests: setting key size 123 should throw Illegal level error' - ); - - t.throws( - () => { - utils.setConfigSetting('crypto-keysize', 256); - utils.setConfigSetting('crypto-hash-algo', '12345'); - cryptoUtils = utils.newCryptoSuite(); - }, - /^Error: Unsupported hash algorithm/, - 'CryptoSuite_ECDSA_AES function tests: setting hash algo to 12345 should throw Illegal Hash function family' - ); - - utils.setConfigSetting('crypto-keysize', 256); - utils.setConfigSetting('crypto-hash-algo', 'SHA3'); - cryptoUtils = utils.newCryptoSuite(); - cryptoUtils.setCryptoKeyStore(utils.newCryptoKeyStore()); - - return cryptoUtils.generateKey(); - }, (err) => { - t.fail('Failed to generateKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then((key) => { - t.throws( - () => { - cryptoUtils.sign(); - }, - /A valid key is required to sign/, - 'CryptoSuite_ECDSA_AES function tests: sign() should throw "A valid key is required to sign"' - ); - - t.throws( - () => { - cryptoUtils.sign('dummy key'); - }, - /A valid message is required to sign/, - 'CryptoSuite_ECDSA_AES function tests: sign() should throw "A valid message is required to sign"' - ); - - const testSignature = function (msg) { - const sig = cryptoUtils.sign(key, cryptoUtils.hash(msg)); - if (sig) { - // test that signatures have low-S - const halfOrder = halfOrdersForCurve[key._key.ecparams.name]; - const sigObject = new Signature(sig); - if (sigObject.s.cmp(halfOrder) === 1) { - t.fail('Invalid signature object: S value larger than N/2'); - } else { - t.pass('Valid signature object generated from sign()'); - } - - // using internal calls to verify the signature - const pubKey = cryptoUtils._ecdsa.keyFromPublic(key.getPublicKey()._key.pubKeyHex, 'hex'); - // note that the signature is generated on the hash of the message, not the message itself - t.equal(pubKey.verify(cryptoUtils.hash(msg), Buffer.from(sig)), true, - 'CryptoSuite_ECDSA_AES function tests: sign() method produced proper signature that was successfully verified'); - } else { - t.fail('Invalid signature generated by sign()'); - } - }; - - testSignature(TEST_MSG); - testSignature(TEST_LONG_MSG); - - t.throws( - () => { - cryptoUtils.verify(); - }, - /A valid key is required to verify/, - 'CryptoSuite_ECDSA_AES function tests: verify() should throw "A valid key is required to verify"' - ); - - t.throws( - () => { - cryptoUtils.verify('dummy key'); - }, - /A valid signature is required to verify/, - 'CryptoSuite_ECDSA_AES function tests: verify() should throw "A valid signature is required to verify"' - ); - - t.throws( - () => { - cryptoUtils.verify('dummy key', 'dummy signature'); - }, - /A valid message is required to verify/, - 'CryptoSuite_ECDSA_AES function tests: verify() should throw "A valid message is required to verify"' - ); - - utils.setConfigSetting('crypto-keysize', 256); - utils.setConfigSetting('crypto-hash-algo', 'SHA2'); - cryptoUtils = utils.newCryptoSuite(); - cryptoUtils.setCryptoKeyStore(utils.newCryptoKeyStore()); - - const testVerify = function (sig, msg, expected) { - // manually construct a key based on the saved privKeyHex and pubKeyHex - const f = new ECDSA({curve: 'secp256r1'}); - f.setPrivateKeyHex(TEST_KEY_PRIVATE); - f.setPublicKeyHex(TEST_KEY_PUBLIC); - f.isPrivate = true; - f.isPublic = false; - - t.equal(cryptoUtils.verify(new ecdsaKey(f), sig, msg), expected, - 'CryptoSuite_ECDSA_AES function tests: verify() method'); - }; - - // these signatures have S values larger than N/2 - testVerify(TEST_MSG_SIGNATURE_SHA2_256, TEST_MSG, false); - testVerify(TEST_LONG_MSG_SIGNATURE_SHA2_256, TEST_LONG_MSG, false); - - // test importKey() - return cryptoUtils.importKey(TEST_CERT_PEM); - }, (err) => { - t.fail('Failed to importKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then((pubKey) => { - t.equal(pubKey.isPrivate(), false, 'Test imported public key isPrivate()'); - t.equal(pubKey.getSKI(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef', 'Test imported public key SKI'); - - // verify that the pub key has been saved in the key store by the proper key - t.equal( - fs.existsSync(path.join(utils.getDefaultKeyStorePath(), 'b5cb4942005c4ecaa9f73a49e1936a58baf549773db213cf1e22a1db39d9dbef-pub')), - true, - 'Check that the imported public key has been saved in the key store'); - - return cryptoUtils.importKey(TEST_KEY_PRIVATE_PEM); - }, (err) => { - t.fail('Failed to importKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then((privKey) => { - t.equal(privKey.isPrivate(), true, 'Test imported private key isPrivate'); - t.equal(privKey.getSKI(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a', 'Test imported private key SKI'); - t.end(); - - // verify that the imported private key has been saved in the key store by the proper key - t.equal( - fs.existsSync(path.join(utils.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')), - true, - 'Check that the imported private key has been saved in the key store'); - - // verify that the imported key can properly sign messages - const testSig = cryptoUtils.sign(privKey, cryptoUtils.hash(TEST_MSG)); - t.equal( - cryptoUtils.verify(privKey.getPublicKey(), testSig, TEST_MSG), - true, - 'Check that the imported private key can properly sign messages'); - - // manufacture an error condition where the private key does not exist for the SKI, and only the public key does - return cryptoUtils.importKey(TEST_KEY_PRIVATE_CERT_PEM); - }, (err) => { - t.fail('Failed to importKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err); - t.end(); - }).then(() => { - fs.removeSync(path.join(utils.getDefaultKeyStorePath(), '0e67f7fa577fd76e487ea3b660e1a3ff15320dbc95e396d8b0ff616c87f8c81a-priv')); - - const poorUser = new User('admin2'); - poorUser.setCryptoSuite(cryptoUtils); - - return poorUser.fromString(JSON.stringify(TEST_USER_ENROLLMENT)); - }).then(() => { - t.fail('Failed to catch missing private key expected from a user enrollment object'); - t.end(); - }, (err) => { - const msg = 'Private key missing from key store'; - if (err.message && err.message.indexOf(msg) > -1) { - t.pass('Successfully caught missing private key expected from a user enrollment object'); - t.end(); - } else { - t.fail(util.format('Unexpected message. Expecting "%s" but got "%s"', msg, err)); - t.end(); - } - }).catch((err) => { - t.comment('final catch, caught err...'); - t.fail(err.stack ? err.stack : err); - t.end(); - }); -});