Fix signatures with critical notations

Previously the signature parsing function ignored critical bit on
notations.

This change checks for notations that are marked "critical" but are not
on the known notations list (controlled by config array
`openpgp.config.known_notations`) and triggers parse error if such
a notation have been encountered.

See: #897.
This commit is contained in:
Wiktor Kwapisiewicz 2019-05-13 20:56:23 +02:00
parent 16b12d7f55
commit 82799390de
No known key found for this signature in database
GPG Key ID: B97A1EE09DB417EC
3 changed files with 56 additions and 1 deletions

View File

@ -183,5 +183,12 @@ export default {
* @memberof module:config
* @property {Integer} max_userid_length
*/
max_userid_length: 1024 * 5
max_userid_length: 1024 * 5,
/**
* Contains notatations that are considered "known". Known notations do not trigger
* validation error when the notation is marked as critical.
* @memberof module:config
* @property {Array} known_notations
*/
known_notations: ["preferred-email-encoding@pgp.com", "pka-address@gnupg.org"]
};

View File

@ -32,6 +32,7 @@ import type_mpi from '../type/mpi.js';
import crypto from '../crypto';
import enums from '../enums';
import util from '../util';
import config from '../config';
/**
* Implementation of the Signature Packet (Tag 2)
@ -446,6 +447,10 @@ Signature.prototype.read_sub_packet = function (bytes, trusted=true) {
const value = util.Uint8Array_to_str(bytes.subarray(mypos + m, mypos + m + n));
this.notations.push([name, value]);
if (critical && (config.known_notations.indexOf(name) === -1)) {
throw new Error("Unknown critical notation: " + name);
}
} else {
util.print_debug("Unsupported notation flag "+bytes[mypos]);
}

View File

@ -467,6 +467,16 @@ describe("Signature", function() {
'=NbaL',
'-----END PGP PRIVATE KEY BLOCK-----'].join("\n");
const signature_with_critical_notation = `-----BEGIN PGP MESSAGE-----
owGbwMvMwMH4oOW7S46CznTG09xJDDE3Wl1KUotLuDousDAwcjBYiSmyXL+48d6x
U1PSGUxcj8IUszKBVMpMaWAAAgEGZpAeh9SKxNyCnFS95PzcytRiBi5OAZjyXXzM
f8WYLqv7TXP61Sa4rqT12CI3xaN73YS2pt089f96odCKaEPnWJ3iSGmzJaW/ug10
2Zo8Wj2k4s7t8wt4H3HtTu+y5UZfV3VOO+l//sdE/o+Lsub8FZH7/eOq7OnbNp4n
vwjE8mqJXetNMfj8r2SCyvkEnlVRYR+/mnge+ib56FdJ8uKtqSxyvgA=
=fRXs
-----END PGP MESSAGE-----`;
it('Testing signature checking on CAST5-enciphered message', async function() {
const priv_key = (await openpgp.key.readArmored(priv_key_arm1)).keys[0];
const pub_key = (await openpgp.key.readArmored(pub_key_arm1)).keys[0];
@ -606,6 +616,39 @@ describe("Signature", function() {
});
});
it('Verify fails with signed message with critical notations', async function() {
let testFailed = true;
try {
openpgp.config.tolerant = false;
const sMsg = await openpgp.message.readArmored(signature_with_critical_notation);
const pub_key = (await openpgp.key.readArmored(pub_key_arm2)).keys[0];
const verified = await sMsg.verify([pub_key]);
await verified[0].verified;
testFailed = false;
} catch (e) {
expect(e.message).to.equal('Unknown critical notation: test@example.com');
} finally {
openpgp.config.tolerant = true;
}
// fail the test if execution does not throw an exception
expect(testFailed).to.be.true;
});
it('Verify succeeds with known signed message with critical notations', async function() {
openpgp.config.tolerant = false;
openpgp.config.known_notations.push('test@example.com');
try {
const sMsg = await openpgp.message.readArmored(signature_with_critical_notation);
const pub_key = (await openpgp.key.readArmored(pub_key_arm2)).keys[0];
const verified = await sMsg.verify([pub_key]);
openpgp.stream.pipe(sMsg.getLiteralData(), new WritableStream());
expect(await verified[0].verified).to.be.true;
} finally {
openpgp.config.known_notations.pop();
openpgp.config.tolerant = true;
}
});
it('Verify cleartext signed message with two signatures with openpgp.verify', async function() {
const msg_armor =
['-----BEGIN PGP SIGNED MESSAGE-----',