From e411839ae3bdec9c98b1bc094f946065bd67fa15 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 2 Mar 2018 23:50:44 +0100 Subject: [PATCH] Deduplicate signature packet creation --- src/key.js | 108 ++++++++++++++++++++++--------------------------- src/message.js | 22 ++-------- 2 files changed, 51 insertions(+), 79 deletions(-) diff --git a/src/key.js b/src/key.js index 8713cfac..2649f659 100644 --- a/src/key.js +++ b/src/key.js @@ -637,31 +637,16 @@ Key.prototype.revoke = async function(privateKey, { flag: reasonForRevocationFlag=enums.reasonForRevocation.no_reason, string: reasonForRevocationString='' } = {}, date=new Date()) { - if (privateKey.isPublic()) { - throw new Error('Need private key for revoking'); - } if (privateKey.primaryKey.getFingerprint() !== this.primaryKey.getFingerprint()) { throw new Error('Private key does not match public key'); } - await privateKey.verifyPrimaryUser(); - const signingKeyPacket = privateKey.getSigningKeyPacket(); - if (!signingKeyPacket) { - throw new Error(`Could not find valid signing key packet in key ${ - privateKey.primaryKey.getKeyId().toHex()}`); - } - if (!signingKeyPacket.isDecrypted) { - throw new Error('Private key is not decrypted.'); - } const dataToSign = { key: this.primaryKey }; - const signaturePacket = new packet.Signature(date); - signaturePacket.signatureType = enums.write(enums.signature, enums.signature.key_revocation); - signaturePacket.reasonForRevocationFlag = enums.write(enums.reasonForRevocation, reasonForRevocationFlag); - signaturePacket.reasonForRevocationString = reasonForRevocationString; - signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); - await signaturePacket.sign(signingKeyPacket, dataToSign); const key = new Key(this.toPacketlist()); - key.revocationSignature = signaturePacket; + key.revocationSignature = await createSignaturePacket(dataToSign, privateKey, { + signatureType: enums.signature.key_revocation, + reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag), + reasonForRevocationString + }, date); return key; }; @@ -833,29 +818,15 @@ User.prototype.toPacketlist = function() { User.prototype.sign = async function(primaryKey, privateKeys) { const dataToSign = { userid: this.userId || this.userAttribute, key: primaryKey }; const user = new User(dataToSign.userid); - user.otherCertifications = await Promise.all(privateKeys.map(async function(privateKey) { - if (privateKey.isPublic()) { - throw new Error('Need private key for signing'); - } + user.otherCertifications = await Promise.all(privateKeys.map(function(privateKey) { if (privateKey.primaryKey.getFingerprint() === primaryKey.getFingerprint()) { throw new Error('Not implemented for self signing'); } - const signingKeyPacket = await privateKey.getSigningKeyPacket(); - if (!signingKeyPacket) { - throw new Error('Could not find valid signing key packet in key ' + - privateKey.primaryKey.getKeyId().toHex()); - } - if (!signingKeyPacket.isDecrypted) { - throw new Error('Private key is not decrypted.'); - } - const signaturePacket = new packet.Signature(); - // Most OpenPGP implementations use generic certification (0x10) - 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 = await getPreferredHashAlgo(privateKey); - signaturePacket.sign(signingKeyPacket, dataToSign); - return signaturePacket; + return createSignaturePacket(dataToSign, privateKey, { + // Most OpenPGP implementations use generic certification (0x10) + signatureType: enums.signature.cert_generic, + keyFlags: [enums.keyFlags.certify_keys | enums.keyFlags.sign_data] + }); })); await user.update(this, primaryKey); return user; @@ -883,6 +854,38 @@ User.prototype.isRevoked = async function(primaryKey, certificate, key, date=new ); }; +/** + * Create signature packet + * @param {Object} dataToSign Contains packets to be signed + * @param {module:key~Key} privateKey private key with decrypted secret key data for signing + * @param {Object} signatureProperties (optional) properties to write on the signature packet before signing + * @param {Date} date (optional) override the creationtime of the signature + * @param {Object} userId (optional) user ID + * @return {module:packet/signature} signature packet + */ +export async function createSignaturePacket(dataToSign, privateKey, signatureProperties, date, userId) { + if (privateKey.isPublic()) { + throw new Error('Need private key for signing'); + } + await privateKey.verifyPrimaryUser(); + const signingKeyPacket = await privateKey.getSigningKeyPacket(undefined, date, userId); + if (!signingKeyPacket) { + throw new Error(`Could not find valid signing key packet in key ${ + privateKey.primaryKey.getKeyId().toHex()}`); + } + if (!signingKeyPacket.isDecrypted) { + throw new Error('Private key is not decrypted.'); + } + const signaturePacket = new packet.Signature(date); + for(const [prop, value] of Object.entries(signatureProperties)) { + signaturePacket[prop] = value; + } + signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; + signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, date, userId); + await signaturePacket.sign(signingKeyPacket, dataToSign); + return signaturePacket; +} + /** * Verifies the user certificate * @param {module:packet.SecretKey| @@ -1134,31 +1137,16 @@ SubKey.prototype.revoke = async function(primaryKey, privateKey, { flag: reasonForRevocationFlag=enums.reasonForRevocation.no_reason, string: reasonForRevocationString='' } = {}, date=new Date()) { - if (privateKey.isPublic()) { - throw new Error('Need private key for revoking'); - } if (privateKey.primaryKey.getFingerprint() !== primaryKey.getFingerprint()) { throw new Error('Private key does not match public key'); } - await privateKey.verifyPrimaryUser(); - const signingKeyPacket = privateKey.getSigningKeyPacket(); - if (!signingKeyPacket) { - throw new Error(`Could not find valid signing key packet in key ${ - privateKey.primaryKey.getKeyId().toHex()}`); - } - if (!signingKeyPacket.isDecrypted) { - throw new Error('Private key is not decrypted.'); - } const dataToSign = { key: primaryKey, bind: this.subKey }; - const signaturePacket = new packet.Signature(date); - signaturePacket.signatureType = enums.write(enums.signature, enums.signature.subkey_revocation); - signaturePacket.reasonForRevocationFlag = enums.write(enums.reasonForRevocation, reasonForRevocationFlag); - signaturePacket.reasonForRevocationString = reasonForRevocationString; - signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey); - await signaturePacket.sign(signingKeyPacket, dataToSign); const subKey = new SubKey(this.subKey); - subKey.revocationSignature = signaturePacket; + subKey.revocationSignature = await createSignaturePacket(dataToSign, privateKey, { + signatureType: enums.signature.subkey_revocation, + reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag), + reasonForRevocationString + }, date); await subKey.update(this, primaryKey); return subKey; }; diff --git a/src/message.js b/src/message.js index 2c3826db..ffba8a94 100644 --- a/src/message.js +++ b/src/message.js @@ -36,7 +36,7 @@ import enums from './enums'; import util from './util'; import packet from './packet'; import { Signature } from './signature'; -import { getPreferredHashAlgo, getPreferredAlgo, isAeadSupported } from './key'; +import { getPreferredHashAlgo, getPreferredAlgo, isAeadSupported, createSignaturePacket } from './key'; /** @@ -499,24 +499,8 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig const signatureType = literalDataPacket.text === null ? enums.signature.binary : enums.signature.text; - await Promise.all(privateKeys.map(async function(privateKey) { - if (privateKey.isPublic()) { - throw new Error('Need private key for signing'); - } - const signingKeyPacket = await privateKey.getSigningKeyPacket(undefined, date, userId); - if (!signingKeyPacket) { - throw new Error('Could not find valid key packet for signing in key ' + - privateKey.primaryKey.getKeyId().toHex()); - } - if (!signingKeyPacket.isDecrypted) { - throw new Error('Private key is not decrypted.'); - } - const signaturePacket = new packet.Signature(date); - signaturePacket.signatureType = signatureType; - signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm; - signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, date, userId); - await signaturePacket.sign(signingKeyPacket, literalDataPacket); - return signaturePacket; + await Promise.all(privateKeys.map(privateKey => { + return createSignaturePacket(literalDataPacket, privateKey, {signatureType}, date, userId); })).then(signatureList => { signatureList.forEach(signaturePacket => packetlist.push(signaturePacket)); });