From 368d80245a384063bbd2c71f7169f591a9fc1ea1 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Sat, 24 Feb 2018 18:32:04 +0100 Subject: [PATCH] Subkey revocation --- src/key.js | 43 +++++++++++++++++++++++++++++++++++++++++++ test/general/key.js | 19 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/key.js b/src/key.js index bb9dab1d..118ed8ce 100644 --- a/src/key.js +++ b/src/key.js @@ -1070,6 +1070,49 @@ SubKey.prototype.update = async function(subKey, primaryKey) { }); }; +/** + * Revokes the subkey + * @param {module:packet/signature} primaryKey primary key used for revocation + * @param {module:key~Key} privateKey decrypted private key for revocation + * @param {Object} reasonForRevocation optional, object indicating the reason for revocation + * @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation + * @param {String} reasonForRevocation.string optional, string explaining the reason for revocation + * @param {Date} date optional, override the creationtime of the revocation signature + * @return {module:key~SubKey} new subkey with revocation signature + */ +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; + await subKey.update(this, primaryKey); + return subKey; +}; + /** * Reads an unarmored OpenPGP key list and returns one or multiple key objects * @param {Uint8Array} data to be parsed diff --git a/test/general/key.js b/test/general/key.js index e57479a9..4ee5970e 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -1448,6 +1448,25 @@ const mergeKey2 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + }); }); + it('revoke() - subkey', function(done) { + const pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0]; + const privKey = openpgp.key.readArmored(priv_key_arm2).keys[0]; + privKey.decrypt('hello world'); + + const subKey = pubKey.subKeys[0]; + subKey.revoke(pubKey.primaryKey, privKey, { + flag: openpgp.enums.reasonForRevocation.key_superseded + }).then(revKey => { + expect(revKey.revocationSignature).to.exist; + expect(revKey.revocationSignature.signatureType).to.equal(openpgp.enums.signature.subkey_revocation); + expect(revKey.revocationSignature.reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.key_superseded); + expect(revKey.revocationSignature.reasonForRevocationString).to.equal(''); + + expect(subKey.verify(pubKey.primaryKey)).to.eventually.equal(openpgp.enums.keyStatus.valid); + expect(revKey.verify(pubKey.primaryKey)).to.eventually.equal(openpgp.enums.keyStatus.revoked).notify(done); + }); + }); + it("getPreferredAlgo('symmetric') - one key - AES256", async function() { const key1 = openpgp.key.readArmored(twoKeys).keys[0]; const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1]);