From 25bf08087122aebee2e3f60f26adcedd0897236c Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Mon, 3 Aug 2020 15:52:50 +0200 Subject: [PATCH] Add SecretKey.prototype.makeDummy (#1131) --- src/key/key.js | 2 +- src/packet/secret_key.js | 20 ++++++++++++++++++++ test/general/key.js | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/key/key.js b/src/key/key.js index 8c8d29d4..da4bd047 100644 --- a/src/key/key.js +++ b/src/key/key.js @@ -457,7 +457,7 @@ Key.prototype.validate = async function() { } let signingKeyPacket; - if (!this.keyPacket.isDummy()) { + if (!this.primaryKey.isDummy()) { signingKeyPacket = this.primaryKey; } else { /** diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 2904f6a0..c8de668a 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -267,6 +267,26 @@ SecretKey.prototype.isDummy = function() { return !!(this.s2k && this.s2k.type === 'gnu-dummy'); }; +/** + * Remove private key material, converting the key to a dummy one + * The resulting key cannot be used for signing/decrypting but can still verify signatures + */ +SecretKey.prototype.makeDummy = function () { + if (this.isDummy()) { + return; + } + if (!this.isDecrypted()) { + // this is technically not needed, but makes the conversion simpler + throw new Error("Key is not decrypted"); + } + this.clearPrivateParams(); + this.isEncrypted = false; + this.s2k = new type_s2k(); + this.s2k.algorithm = 0; + this.s2k.c = 0; + this.s2k.type = 'gnu-dummy'; +}; + /** * Encrypt the payload. By default, we use aes256 and iterated, salted string * to key specifier. If the key is in a decrypted state (isEncrypted === false) diff --git a/test/general/key.js b/test/general/key.js index cc06027c..7db4f4a7 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -2748,6 +2748,25 @@ describe('Key', function() { await expect(key.validate()).to.be.rejectedWith('Key is invalid'); }); + it('makeDummy() - the converted key is valid but can no longer sign', async function() { + const { keys: [key] } = await openpgp.key.readArmored(priv_key_rsa); + await key.decrypt('hello world'); + expect(key.primaryKey.isDummy()).to.be.false; + key.primaryKey.makeDummy(); + expect(key.primaryKey.isDummy()).to.be.true; + await key.validate(); + await expect(openpgp.reformatKey({ privateKey: key, userIds: 'test2 ' })).to.be.rejectedWith(/Missing private key parameters/); + }); + + it('makeDummy() - subkeys of the converted key can still sign', async function() { + const { keys: [key] } = await openpgp.key.readArmored(priv_key_rsa); + await key.decrypt('hello world'); + expect(key.primaryKey.isDummy()).to.be.false; + key.primaryKey.makeDummy(); + expect(key.primaryKey.isDummy()).to.be.true; + await expect(openpgp.sign({ message: openpgp.message.fromText('test'), privateKeys: [key] })).to.be.fulfilled; + }); + it('clearPrivateParams() - check that private key can no longer be used', async function() { const { keys: [key] } = await openpgp.key.readArmored(priv_key_rsa); await key.decrypt('hello world');