diff --git a/src/key.js b/src/key.js index ac6d2f4f..c96138db 100644 --- a/src/key.js +++ b/src/key.js @@ -1220,9 +1220,16 @@ SubKey.prototype.revoke = async function(primaryKey, { export async function read(data) { const result = {}; result.keys = []; + const err = []; try { const packetlist = new packet.List(); await packetlist.read(data); + if (packetlist.filterByTag(enums.packet.signature).some( + signature => signature.revocationKeyClass !== null + )) { + // Indicate an error, but still parse the key. + err.push(new Error('This key is intended to be revoked with an authorized key, which OpenPGP.js does not support.')); + } const keyIndex = packetlist.indexOfTag(enums.packet.publicKey, enums.packet.secretKey); if (keyIndex.length === 0) { throw new Error('No key packet found'); @@ -1233,13 +1240,14 @@ export async function read(data) { const newKey = new Key(oneKeyList); result.keys.push(newKey); } catch (e) { - result.err = result.err || []; - result.err.push(e); + err.push(e); } } } catch (e) { - result.err = result.err || []; - result.err.push(e); + err.push(e); + } + if (err.length) { + result.err = err; } return result; } diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index 12b09754..f1394017 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -21,6 +21,7 @@ import util from '../util'; * are stored as numerical indices. * @memberof module:packet * @constructor + * @extends Array */ function List() { /** @@ -31,6 +32,8 @@ function List() { this.length = 0; } +List.prototype = []; + /** * Reads a stream of binary data and interprents it as a list of packets. * @param {Uint8Array | ReadableStream} A Uint8Array of bytes. @@ -145,37 +148,6 @@ List.prototype.push = function (packet) { this.length++; }; -/** - * Remove a packet from the list and return it. - * @returns {Object} The packet that was removed - */ -List.prototype.pop = function() { - if (this.length === 0) { - return; - } - - const packet = this[this.length - 1]; - delete this[this.length - 1]; - this.length--; - - return packet; -}; - -/** - * Creates a new PacketList with all packets that pass the test implemented by the provided function. - */ -List.prototype.filter = function (callback) { - const filtered = new List(); - - for (let i = 0; i < this.length; i++) { - if (callback(this[i], i, this)) { - filtered.push(this[i]); - } - } - - return filtered; -}; - /** * Creates a new PacketList with all packets from the given types */ @@ -193,58 +165,6 @@ List.prototype.filterByTag = function (...args) { return filtered; }; -/** - * Executes the provided callback once for each element - */ -List.prototype.forEach = function (callback) { - for (let i = 0; i < this.length; i++) { - callback(this[i], i, this); - } -}; - -/** - * Returns an array containing return values of callback - * on each element - */ -List.prototype.map = function (callback) { - const packetArray = []; - - for (let i = 0; i < this.length; i++) { - packetArray.push(callback(this[i], i, this)); - } - - return packetArray; -}; - -/** - * Executes the callback function once for each element - * until it finds one where callback returns a truthy value - * @param {Function} callback - * @returns {Promise} - * @async - */ -List.prototype.some = async function (callback) { - for (let i = 0; i < this.length; i++) { - if (await callback(this[i], i, this)) { - return true; - } - } - return false; -}; - -/** - * Executes the callback function once for each element, - * returns true if all callbacks returns a truthy value - */ -List.prototype.every = function (callback) { - for (let i = 0; i < this.length; i++) { - if (!callback(this[i], i, this)) { - return false; - } - } - return true; -}; - /** * Traverses packet tree and returns first matching packet * @param {module:enums.packet} type The packet type @@ -285,20 +205,6 @@ List.prototype.indexOfTag = function (...args) { return tagIndex; }; -/** - * Returns slice of packetlist - */ -List.prototype.slice = function (begin, end) { - if (!end) { - end = this.length; - } - const part = new List(); - for (let i = begin; i < end; i++) { - part.push(this[i]); - } - return part; -}; - /** * Concatenates packetlist or array of packets */ diff --git a/test/general/key.js b/test/general/key.js index 9de32570..cd37ed34 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -1223,6 +1223,41 @@ t/ia1kMpSEiOVLlX5dfHZzhR3WNtBqU= =C0fJ -----END PGP PRIVATE KEY BLOCK-----`; +const key_with_authorized_revocation_key = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: OpenPGP.js VERSION +Comment: https://openpgpjs.org + +xsBNBFujnwwBCADK1xX03tSCmktPDS9Ncij3O5wG+F5/5Zm7QJDc39Wt1t/K +szCSobWtm/UObQVZjsTGwg0ZUPgepgWGGDBL0dlc1NObwUiOhGYnJnd4V25P +iU5Mg3+DhRq+LzNK+oGlpVPDpwQ48S8HOphbswKUpuaDcEQ2f+NKIc0eXe5m +ut5x9uoVj8jneUNsHYq6FIlxh4knzpJWFj5+LNi7plMCwKip6srVNf8He/q0 +0xA/4vjSIOfGIE7TCBH33CbHEr98p81Cf4g0E+kswEz5iWE2SDCyYgQkMrkz +H9mtVqk3nFT8NR0USxKqH9bGhaTx1AWq/HDgsphayPEWQ0usjQDrbQUnABEB +AAHNDnRlc3QgPGFAYi5jb20+wsCNBBABCABBBQJbo58MBgsJBwgDAhcMgAH0 +cOUNyxrV8eZOCGRKY2E6TW5AlAkQWICi/ReDcrkEFQgKAgMWAgECGQECGwMC +HgEAADgHB/0WIHh6maX2LZ0u5ujk1tZxWMrCycccopdQNKN0RGD98X4fyY6J +wfmKb107gcidJBFct0sVWFW8GU42w9pVMU5qWD6kyFkgcmov319UL+7aZ19b +HOWVKUTb6rFG8/qAbq3BF7YB/cZIBWMFKAS3BRJ4Kz23GheAB2A9oVLmuq5o +gW5c2R1YC0T0XyXEFiw9uZ+AS6kEZymFPRQfPUIbJs1ct/lAN+mC9Qp0Y6CL +60Hd6jlKUb6TgljaQ6CtLfT9v72GeKznapKr9IEtsgYv69j0c/MRM2nmu50c +g+fICiiHrTbNS6jkUz0pZLe7hdhWHeEiqcA9+GC1DxOQCRCS/YNfzsBNBFuj +nwwBCADK1xX03tSCmktPDS9Ncij3O5wG+F5/5Zm7QJDc39Wt1t/KszCSobWt +m/UObQVZjsTGwg0ZUPgepgWGGDBL0dlc1NObwUiOhGYnJnd4V25PiU5Mg3+D +hRq+LzNK+oGlpVPDpwQ48S8HOphbswKUpuaDcEQ2f+NKIc0eXe5mut5x9uoV +j8jneUNsHYq6FIlxh4knzpJWFj5+LNi7plMCwKip6srVNf8He/q00xA/4vjS +IOfGIE7TCBH33CbHEr98p81Cf4g0E+kswEz5iWE2SDCyYgQkMrkzH9mtVqk3 +nFT8NR0USxKqH9bGhaTx1AWq/HDgsphayPEWQ0usjQDrbQUnABEBAAHCwF8E +GAEIABMFAlujnwwJEFiAov0Xg3K5AhsMAACI/QgArvTcutod+7n1D8wCwM50 +jo3x4KPuQw+NwbOnMbFwv0R8i8NqtSFf2bYkkZ7RLViTmphvSon4h2WgfczL +SBulZ1QZF7zCKXmXDg8/HZgRUflC1XMixpB8Hqouin5AVgMbsbHg30V2uPco +V3DeFQ8HWxQC9symaMW/20MkqNXgCjM0us7kVwTEJQqZ6KYrFVjKyprSQRyP +rfckEBuZnj91OS+kAHlZ+ScZIuV4QVF0e2U6oEuB+qFXppR030PJoO6WDOzm +67hkzfrc3VpKw/I+vVJnZb4GOhNTSpa+p8i4gTyWmrOZ0G85QoldHWlWaRBg +lbjwPj3QUTbLFvHisYzXEQ== +=aT8U +-----END PGP PUBLIC KEY BLOCK----- +`; + function versionSpecificTests() { it('Preferences of generated key', function() { const testPref = function(key) { @@ -1688,6 +1723,15 @@ describe('Key', function() { expect(pubKeys.keys[1].getKeyId().toHex()).to.equal('dbf223e870534df4'); }); + it('Parsing armored key with an authorized revocation key', async function() { + const pubKeys = await openpgp.key.readArmored(key_with_authorized_revocation_key); + expect(pubKeys).to.exist; + expect(pubKeys.err).to.exist.and.have.length(1); + expect(pubKeys.err[0].message).to.equal('This key is intended to be revoked with an authorized key, which OpenPGP.js does not support.'); + expect(pubKeys.keys).to.have.length(1); + expect(pubKeys.keys[0].getKeyId().toHex()).to.equal('5880a2fd178372b9'); + }); + it('Parsing V5 public key packet', async function() { // Manually modified from https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b2092/back.mkd#sample-eddsa-key let packetBytes = openpgp.util.hex_to_Uint8Array(`