diff --git a/src/cleartext.js b/src/cleartext.js index e5909392..b90e25b7 100644 --- a/src/cleartext.js +++ b/src/cleartext.js @@ -20,16 +20,17 @@ * @requires encoding/armor * @requires enums * @requires packet + * @requires signature * @module cleartext */ 'use strict'; import config from './config'; -import packet from './packet'; -import enums from './enums.js'; import armor from './encoding/armor.js'; -import * as sigModule from './signature.js'; +import enums from './enums.js'; +import packet from './packet'; +import { Signature } from './signature.js'; /** * @class @@ -45,10 +46,10 @@ export function CleartextMessage(text, signature) { } // normalize EOL to canonical form this.text = text.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n"); - if (signature && !(signature instanceof sigModule.Signature)) { + if (signature && !(signature instanceof Signature)) { throw new Error('Invalid signature input'); } - this.signature = signature || new sigModule.Signature(new packet.List()); + this.signature = signature || new Signature(new packet.List()); } /** @@ -105,7 +106,7 @@ CleartextMessage.prototype.signDetached = async function(privateKeys) { signatureList.forEach(signaturePacket => packetlist.push(signaturePacket)); }); - return new sigModule.Signature(packetlist); + return new Signature(packetlist); }; /** @@ -131,24 +132,21 @@ CleartextMessage.prototype.verifyDetached = function(signature, keys) { var keyPacket = null; await Promise.all(keys.map(async function(key) { await key.verifyPrimaryUser(); + // Look for the unique key packet that matches issuerKeyId of signature var result = key.getSigningKeyPacket(signature.issuerKeyId, config.verify_expired_keys); if (result) { keyPacket = result; } })); - var verifiedSig = {}; - if (keyPacket) { - verifiedSig.keyid = signature.issuerKeyId; - verifiedSig.valid = await signature.verify(keyPacket, literalDataPacket); - } else { - verifiedSig.keyid = signature.issuerKeyId; - verifiedSig.valid = null; - } + var verifiedSig = { + keyid: signature.issuerKeyId, + valid: keyPacket ? await signature.verify(keyPacket, literalDataPacket) : null + }; var packetlist = new packet.List(); packetlist.push(signature); - verifiedSig.signature = new sigModule.Signature(packetlist); + verifiedSig.signature = new Signature(packetlist); return verifiedSig; })); @@ -191,7 +189,7 @@ export function readArmored(armoredText) { var packetlist = new packet.List(); packetlist.read(input.data); verifyHeaders(input.headers, packetlist); - var signature = new sigModule.Signature(packetlist); + var signature = new Signature(packetlist); var newMessage = new CleartextMessage(input.text, signature); return newMessage; } diff --git a/src/crypto/gcm.js b/src/crypto/gcm.js index e07f2ebf..39786cc8 100644 --- a/src/crypto/gcm.js +++ b/src/crypto/gcm.js @@ -30,7 +30,7 @@ const webCrypto = util.getWebCrypto(); // no GCM support in IE11, Safari 9 const nodeCrypto = util.getNodeCrypto(); const Buffer = util.getNodeBuffer(); -export const ivLength = 12; // size of the IV in bytes +const ivLength = 12; // size of the IV in bytes const TAG_LEN = 16; // size of the tag in bytes const ALGO = 'AES-GCM'; @@ -42,7 +42,7 @@ const ALGO = 'AES-GCM'; * @param {Uint8Array} iv The initialization vector (12 bytes) * @return {Promise} The ciphertext output */ -export function encrypt(cipher, plaintext, key, iv) { +function encrypt(cipher, plaintext, key, iv) { if (cipher.substr(0,3) !== 'aes') { return Promise.reject(new Error('GCM mode supports only AES cipher')); } @@ -64,7 +64,7 @@ export function encrypt(cipher, plaintext, key, iv) { * @param {Uint8Array} iv The initialization vector (12 bytes) * @return {Promise} The plaintext output */ -export function decrypt(cipher, ciphertext, key, iv) { +function decrypt(cipher, ciphertext, key, iv) { if (cipher.substr(0,3) !== 'aes') { return Promise.reject(new Error('GCM mode supports only AES cipher')); } @@ -78,6 +78,12 @@ export function decrypt(cipher, ciphertext, key, iv) { } } +export default { + ivLength, + encrypt, + decrypt +}; + ////////////////////////// // // diff --git a/src/crypto/index.js b/src/crypto/index.js index 51ce77d6..c1530db2 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -8,7 +8,7 @@ import cipher from './cipher'; import hash from './hash'; import cfb from './cfb'; -import * as gcm from './gcm'; +import gcm from './gcm'; import publicKey from './public_key'; import signature from './signature'; import random from './random'; diff --git a/src/crypto/public_key/elliptic/curves.js b/src/crypto/public_key/elliptic/curves.js index 3fa52cf5..fa9fe764 100644 --- a/src/crypto/public_key/elliptic/curves.js +++ b/src/crypto/public_key/elliptic/curves.js @@ -193,7 +193,7 @@ async function generate(curve) { }; } -function getPreferredHashAlgorithm(oid) { +function getPreferredHashAlgo(oid) { return curves[enums.write(enums.curve, oid.toHex())].hash; } @@ -202,7 +202,7 @@ module.exports = { curves: curves, webCurves: webCurves, nodeCurves: nodeCurves, - getPreferredHashAlgorithm: getPreferredHashAlgorithm, + getPreferredHashAlgo: getPreferredHashAlgo, generate: generate, get: get }; diff --git a/src/crypto/public_key/elliptic/index.js b/src/crypto/public_key/elliptic/index.js index a171c3cb..39108f0a 100644 --- a/src/crypto/public_key/elliptic/index.js +++ b/src/crypto/public_key/elliptic/index.js @@ -27,7 +27,7 @@ 'use strict'; -import {get, generate, getPreferredHashAlgorithm} from './curves'; +import {get, generate, getPreferredHashAlgo} from './curves'; import ecdsa from './ecdsa'; import eddsa from './eddsa'; import ecdh from './ecdh'; @@ -38,5 +38,5 @@ module.exports = { ecdh: ecdh, get: get, generate: generate, - getPreferredHashAlgorithm: getPreferredHashAlgorithm + getPreferredHashAlgo: getPreferredHashAlgo }; diff --git a/src/key.js b/src/key.js index 787f4a83..c79daa7d 100644 --- a/src/key.js +++ b/src/key.js @@ -17,20 +17,22 @@ /** * @requires config + * @requires crypto * @requires encoding/armor * @requires enums + * @requires util * @requires packet * @module key */ 'use strict'; -import packet from './packet'; -import enums from './enums.js'; -import armor from './encoding/armor.js'; import config from './config'; -import util from './util'; import crypto from './crypto'; +import armor from './encoding/armor.js'; +import enums from './enums.js'; +import util from './util'; +import packet from './packet'; /** * @class @@ -824,7 +826,7 @@ User.prototype.sign = async function(primaryKey, privateKeys) { signaturePacket.signatureType = enums.write(enums.signature, enums.signature.cert_generic); signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - signaturePacket.hashAlgorithm = getPreferredHashAlgorithm(privateKey); + signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); signaturePacket.signingKeyId = signingKeyPacket.getKeyId(); signaturePacket.sign(signingKeyPacket, dataToSign); return signaturePacket; @@ -1296,7 +1298,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) { var signaturePacket = new packet.Signature(); signaturePacket.signatureType = enums.signature.cert_generic; signaturePacket.publicKeyAlgorithm = options.keyType; - signaturePacket.hashAlgorithm = getPreferredHashAlgorithm(secretKeyPacket); + signaturePacket.hashAlgorithm = getPreferredHashAlgo(secretKeyPacket); signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; signaturePacket.preferredSymmetricAlgorithms = []; // prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support) @@ -1340,7 +1342,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) { var subkeySignaturePacket = new packet.Signature(); subkeySignaturePacket.signatureType = enums.signature.subkey_binding; subkeySignaturePacket.publicKeyAlgorithm = options.keyType; - subkeySignaturePacket.hashAlgorithm = getPreferredHashAlgorithm(secretSubkeyPacket); + subkeySignaturePacket.hashAlgorithm = getPreferredHashAlgo(secretSubkeyPacket); subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage]; if (options.keyExpirationTime > 0) { subkeySignaturePacket.keyExpirationTime = options.keyExpirationTime; @@ -1364,7 +1366,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) { * @param {object} key * @return {String} */ -export function getPreferredHashAlgorithm(key) { +export function getPreferredHashAlgo(key) { var hash_algo = config.prefer_hash_algorithm, pref_algo = hash_algo; if (Key.prototype.isPrototypeOf(key)) { @@ -1385,7 +1387,7 @@ export function getPreferredHashAlgorithm(key) { case 'ecdh': case 'ecdsa': case 'eddsa': - pref_algo = crypto.publicKey.elliptic.getPreferredHashAlgorithm(key.params[0]); + pref_algo = crypto.publicKey.elliptic.getPreferredHashAlgo(key.params[0]); } } return crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ? diff --git a/src/keyring/keyring.js b/src/keyring/keyring.js index 11fd8d5e..c7b860ca 100644 --- a/src/keyring/keyring.js +++ b/src/keyring/keyring.js @@ -17,22 +17,22 @@ /** * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. - * @requires enums * @requires key - * @requires util + * @requires keyring/localstore * @module keyring/keyring + * @param {keyring/localstore} [storeHandler] class implementing loadPublic(), loadPrivate(), storePublic(), and storePrivate() methods */ 'use strict'; -import * as keyModule from '../key.js'; +import { readArmored } from '../key.js'; import LocalStore from './localstore.js'; /** * Initialization routine for the keyring. This method reads the * keyring from HTML5 local storage and initializes this instance. * @constructor - * @param {class} [storeHandler] class implementing loadPublic(), loadPrivate(), storePublic(), and storePrivate() methods + * @param {keyring/localstore} [storeHandler] class implementing loadPublic(), loadPrivate(), storePublic(), and storePrivate() methods */ export default function Keyring(storeHandler) { this.storeHandler = storeHandler || new LocalStore(); @@ -181,7 +181,7 @@ KeyArray.prototype.getForId = function (keyId, deep) { * @return {Array|null} array of error objects or null */ KeyArray.prototype.importKey = function (armored) { - var imported = keyModule.readArmored(armored); + var imported = readArmored(armored); var that = this; imported.keys.forEach(async function(key) { // check if key already in key array diff --git a/src/keyring/localstore.js b/src/keyring/localstore.js index b190359a..aaa84c7e 100644 --- a/src/keyring/localstore.js +++ b/src/keyring/localstore.js @@ -18,6 +18,8 @@ /** * The class that deals with storage of the keyring. Currently the only option is to use HTML5 local storage. * @requires config + * @requires key + * @requires util * @module keyring/localstore * @param {String} prefix prefix for itemnames in localstore */ @@ -25,7 +27,7 @@ 'use strict'; import config from '../config'; -import * as keyModule from '../key.js'; +import { readArmored } from '../key.js'; import util from '../util.js'; export default function LocalStore(prefix) { @@ -67,7 +69,7 @@ function loadKeys(storage, itemname) { if (armoredKeys !== null && armoredKeys.length !== 0) { var key; for (var i = 0; i < armoredKeys.length; i++) { - key = keyModule.readArmored(armoredKeys[i]); + key = readArmored(armoredKeys[i]); if (!key.err) { keys.push(key.keys[0]); } else { diff --git a/src/message.js b/src/message.js index 311dbcd9..4546981c 100644 --- a/src/message.js +++ b/src/message.js @@ -20,20 +20,24 @@ * @requires crypto * @requires encoding/armor * @requires enums + * @requires util * @requires packet + * @requires signature + * @requires key * @module message */ 'use strict'; -import util from './util.js'; -import packet from './packet'; -import enums from './enums.js'; -import armor from './encoding/armor.js'; import config from './config'; import crypto from './crypto'; -import * as sigModule from './signature.js'; -import * as keyModule from './key.js'; +import armor from './encoding/armor.js'; +import enums from './enums.js'; +import util from './util.js'; +import packet from './packet'; +import { Signature } from './signature.js'; +import { getPreferredHashAlgo, getPreferredSymAlgo } from './key.js'; + /** * @class @@ -228,7 +232,7 @@ Message.prototype.encrypt = function(keys, passwords, sessionKey) { symAlgo = sessionKey.algorithm; sessionKey = sessionKey.data; } else if (keys && keys.length) { - symAlgo = enums.read(enums.symmetric, keyModule.getPreferredSymAlgo(keys)); + symAlgo = enums.read(enums.symmetric, getPreferredSymAlgo(keys)); } else if (passwords && passwords.length) { symAlgo = enums.read(enums.symmetric, config.encryption_cipher); } else { @@ -361,7 +365,7 @@ Message.prototype.sign = async function(privateKeys=[], signature=null) { onePassSig = new packet.OnePassSignature(); onePassSig.type = signatureType; //TODO get preferred hash algo from key signature - onePassSig.hashAlgorithm = keyModule.getPreferredHashAlgorithm(privateKey); + onePassSig.hashAlgorithm = getPreferredHashAlgo(privateKey); onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm; onePassSig.signingKeyId = signingKeyPacket.getKeyId(); if (i === privateKeys.length - 1) { @@ -381,7 +385,7 @@ Message.prototype.sign = async function(privateKeys=[], signature=null) { throw new Error('Private key is not decrypted.'); } signaturePacket.signatureType = signatureType; - signaturePacket.hashAlgorithm = keyModule.getPreferredHashAlgorithm(privateKey); + signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; await signaturePacket.sign(signingKeyPacket, literalDataPacket); return signaturePacket; @@ -424,7 +428,7 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null) } signaturePacket.signatureType = signatureType; signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - signaturePacket.hashAlgorithm = keyModule.getPreferredHashAlgorithm(privateKey); + signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); await signaturePacket.sign(signingKeyPacket, literalDataPacket); return signaturePacket; })).then(signatureList => { @@ -436,7 +440,7 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null) packetlist.concat(existingSigPacketlist); } - return new sigModule.Signature(packetlist); + return new Signature(packetlist); }; @@ -483,25 +487,22 @@ async function createVerificationObjects(signatureList, literalDataList, keys) { var keyPacket = null; await Promise.all(keys.map(async function(key) { await key.verifyPrimaryUser(); + // Look for the unique key packet that matches issuerKeyId of signature var result = key.getSigningKeyPacket(signature.issuerKeyId, config.verify_expired_keys); if (result) { keyPacket = result; } })); - var verifiedSig = {}; - if (keyPacket) { - //found a key packet that matches keyId of signature - verifiedSig.keyid = signature.issuerKeyId; - verifiedSig.valid = await signature.verify(keyPacket, literalDataList[0]); - } else { - verifiedSig.keyid = signature.issuerKeyId; - verifiedSig.valid = null; - } + // Look for the unique key packet that matches issuerKeyId of signature + var verifiedSig = { + keyid: signature.issuerKeyId, + valid: keyPacket ? await signature.verify(keyPacket, literalDataList[0]) : null + }; var packetlist = new packet.List(); packetlist.push(signature); - verifiedSig.signature = new sigModule.Signature(packetlist); + verifiedSig.signature = new Signature(packetlist); return verifiedSig; })); diff --git a/src/openpgp.js b/src/openpgp.js index 7540ee0e..6a6daa31 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -16,11 +16,13 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** + * @requires ed6-promise * @requires message * @requires cleartext * @requires key * @requires config * @requires util + * @requires worker/async_proxy * @module openpgp */ @@ -35,8 +37,8 @@ import es6Promise from 'es6-promise'; import * as messageLib from './message.js'; -import * as cleartext from './cleartext.js'; -import * as key from './key.js'; +import { CleartextMessage } from './cleartext.js'; +import { generate, reformat } from './key.js'; import config from './config/config.js'; import util from './util'; import AsyncProxy from './worker/async_proxy.js'; @@ -109,11 +111,11 @@ export function generateKey({ userIds=[], passphrase, numBits=2048, unlocked=fal return asyncProxy.delegate('generateKey', options); } - return key.generate(options).then(newKey => ({ + return generate(options).then(key => ({ - key: newKey, - privateKeyArmored: newKey.armor(), - publicKeyArmored: newKey.toPublic().armor() + key: key, + privateKeyArmored: key.armor(), + publicKeyArmored: key.toPublic().armor() })).catch(onError.bind(null, 'Error generating keypair')); } @@ -137,11 +139,11 @@ export function reformatKey({ privateKey, userIds=[], passphrase="", unlocked=fa return asyncProxy.delegate('reformatKey', options); } - return key.reformat(options).then(newKey => ({ + return reformat(options).then(key => ({ - key: newKey, - privateKeyArmored: newKey.armor(), - publicKeyArmored: newKey.toPublic().armor() + key: key, + privateKeyArmored: key.armor(), + publicKeyArmored: key.toPublic().armor() })).catch(onError.bind(null, 'Error reformatting keypair')); } @@ -157,16 +159,15 @@ export function decryptKey({ privateKey, passphrase }) { return asyncProxy.delegate('decryptKey', { privateKey, passphrase }); } - return execute(() => { + return Promise.resolve().then(async function() { + + await privateKey.decrypt(passphrase); - if (!privateKey.decrypt(passphrase)) { - throw new Error('Invalid passphrase'); - } return { key: privateKey }; - }, 'Error decrypting private key'); + }).catch(onError.bind(null, 'Error decrypting private key')); } @@ -308,7 +309,7 @@ export function sign({ data, privateKeys, armor=true, detached=false}) { var message; if (util.isString(data)) { - message = new cleartext.CleartextMessage(data); + message = new CleartextMessage(data); } else { message = messageLib.fromBinary(data); } @@ -353,7 +354,7 @@ export function verify({ message, publicKeys, signature=null }) { return Promise.resolve().then(async function() { var result = {}; - if (cleartext.CleartextMessage.prototype.isPrototypeOf(message)) { + if (CleartextMessage.prototype.isPrototypeOf(message)) { result.data = message.getText(); } else { result.data = message.getLiteralData(); @@ -395,9 +396,11 @@ export function encryptSessionKey({ data, algorithm, publicKeys, passwords }) { return asyncProxy.delegate('encryptSessionKey', { data, algorithm, publicKeys, passwords }); } - return execute(async () => ({ - message: await messageLib.encryptSessionKey(data, algorithm, publicKeys, passwords) - }), 'Error encrypting session key'); + return Promise.resolve().then(async function() { + + return { message: await messageLib.encryptSessionKey(data, algorithm, publicKeys, passwords) }; + + }).catch(onError.bind(null, 'Error encrypting session key')); } /** @@ -418,7 +421,11 @@ export function decryptSessionKey({ message, privateKey, password }) { return asyncProxy.delegate('decryptSessionKey', { message, privateKey, password }); } - return execute(() => message.decryptSessionKey(privateKey, password), 'Error decrypting session key'); + return Promise.resolve().then(async function() { + + return message.decryptSessionKey(privateKey, password); + + }).catch(onError.bind(null, 'Error decrypting session key')); } @@ -453,7 +460,7 @@ function checkMessage(message) { } } function checkCleartextOrMessage(message) { - if (!cleartext.CleartextMessage.prototype.isPrototypeOf(message) && !messageLib.Message.prototype.isPrototypeOf(message)) { + if (!CleartextMessage.prototype.isPrototypeOf(message) && !messageLib.Message.prototype.isPrototypeOf(message)) { throw new Error('Parameter [message] needs to be of type Message or CleartextMessage'); } } @@ -540,20 +547,6 @@ function parseMessage(message, format) { } } -/** - * Command pattern that wraps synchronous code into a promise. - * @param {function} cmd The synchronous function with a return value - * to be wrapped in a promise - * @param {String} message A human readable error Message - * @return {Promise} The promise wrapped around cmd - */ -function execute(cmd, message) { - // wrap the sync cmd in a promise - const promise = new Promise(resolve => resolve(cmd())); - // handler error globally - return promise.catch(onError.bind(null, message)); -} - /** * Global error handler that logs the stack trace and rethrows a high lvl error message. * @param {String} message A human readable high level error Message diff --git a/src/packet/clone.js b/src/packet/clone.js index c61b0f0a..07e0a632 100644 --- a/src/packet/clone.js +++ b/src/packet/clone.js @@ -23,10 +23,10 @@ 'use strict'; -import * as key from '../key.js'; -import * as message from '../message.js'; -import * as cleartext from '../cleartext.js'; -import * as signature from '../signature.js' +import { Key } from '../key.js'; +import { Message } from '../message.js'; +import { CleartextMessage } from '../cleartext.js'; +import { Signature } from '../signature.js' import Packetlist from './packetlist.js'; import type_keyid from '../type/keyid.js'; @@ -58,13 +58,13 @@ export function clonePackets(options) { } if (options.message) { //could be either a Message or CleartextMessage object - if (options.message instanceof message.Message) { + if (options.message instanceof Message) { options.message = options.message.packets; - } else if (options.message instanceof cleartext.CleartextMessage) { + } else if (options.message instanceof CleartextMessage) { options.message.signature = options.message.signature.packets; } } - if (options.signature && (options.signature instanceof signature.Signature)) { + if (options.signature && (options.signature instanceof Signature)) { options.signature = options.signature.packets; } if (options.signatures) { @@ -120,23 +120,23 @@ export function parseClonedPackets(options, method) { function packetlistCloneToKey(clone) { const packetlist = Packetlist.fromStructuredClone(clone); - return new key.Key(packetlist); + return new Key(packetlist); } function packetlistCloneToMessage(clone) { const packetlist = Packetlist.fromStructuredClone(clone); - return new message.Message(packetlist); + return new Message(packetlist); } function packetlistCloneToCleartextMessage(clone) { var packetlist = Packetlist.fromStructuredClone(clone.signature); - return new cleartext.CleartextMessage(clone.text, new signature.Signature(packetlist)); + return new CleartextMessage(clone.text, new Signature(packetlist)); } //verification objects function packetlistCloneToSignatures(clone) { clone.keyid = type_keyid.fromClone(clone.keyid); - clone.signature = new signature.Signature(clone.signature); + clone.signature = new Signature(clone.signature); return clone; } @@ -146,5 +146,5 @@ function packetlistCloneToSignature(clone) { return clone; } var packetlist = Packetlist.fromStructuredClone(clone); - return new signature.Signature(packetlist); + return new Signature(packetlist); } diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js index 48a84fc5..803afd1d 100644 --- a/test/crypto/elliptic.js +++ b/test/crypto/elliptic.js @@ -286,16 +286,16 @@ describe('Elliptic Curve Cryptography', function () { expect(verify_signature('p384', 8, p384_r, p384_s, p384_message, key_data.p384.pub)) .to.eventually.be.true.notify(done); }); - it('Sign and verify message', function (done) { + it('Sign and verify message', function () { var curve = elliptic_curves.get('p521'); - curve.genKeyPair().then(keyPair => { + return curve.genKeyPair().then(keyPair => { var keyPublic = bin2bi(keyPair.getPublic()); var keyPrivate = bin2bi(keyPair.getPrivate()); var oid = curve.oid; var message = p384_message; - elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate).then(signature => { + return elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate).then(signature => { expect(elliptic_curves.ecdsa.verify(oid, 10, signature, message, keyPublic)) - .to.eventually.be.true.notify(done); + .to.eventually.be.true; }); }); });