Indicate an error when parsing a key with an authorized revocation key

Since we will ignore revocation signatures from authorized revocation keys,
it is dangerous to use these keys.
This commit is contained in:
Daniel Huigens 2018-09-20 15:28:03 +02:00
parent 5cf61daa19
commit a1c47ecdea
3 changed files with 59 additions and 101 deletions

View File

@ -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;
}

View File

@ -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<Uint8Array>} 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<Boolean>}
* @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
*/

View File

@ -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(`