openpgpjs/test/security/subkey_trust.js
larabr d49d92e5cb Update to Mocha v10 in tests, declare lib as module and add exports to package.json
Mocha v10 requires the lib to be esm compliant.
ESM mandates the use of file extensions in imports, so to minimize the
changes (for now), we rely on the flag `experimental-specifier-resolution=node`
and on `ts-node` (needed only for Node 20).

Breaking changes:
downstream bundlers might be affected by the package.json changes depending on
how they load the library.
NB: legacy package.json entrypoints are still available.
2023-10-25 12:53:10 +02:00

73 lines
2.8 KiB
JavaScript

import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised';
chaiUse(chaiAsPromised);
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : await import('openpgp');
const { readKey, PublicKey, readCleartextMessage, createCleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
async function generateTestData() {
const { privateKey: victimPrivKey } = await openpgp.generateKey({
userIDs: [{ name: 'Victim', email: 'victim@example.com' }],
type: 'rsa',
rsaBits: 2048,
subkeys: [{ sign: true }],
format: 'object'
});
const { privateKey: attackerPrivKey } = await openpgp.generateKey({
userIDs: [{ name: 'Attacker', email: 'attacker@example.com' }],
type: 'rsa',
rsaBits: 2048,
subkeys: [],
format: 'object'
});
const signed = await openpgp.sign({
message: await createCleartextMessage({ text: 'I am batman' }),
signingKeys: victimPrivKey
});
return {
victimPubKey: victimPrivKey.toPublic(),
attackerPrivKey,
signed
};
}
export default () => it('Does not trust subkeys without Primary Key Binding Signature', async function() {
// attacker only has his own private key,
// the victim's public key and a signed message
const { victimPubKey, attackerPrivKey, signed } = await generateTestData();
const pktPubVictim = victimPubKey.toPacketList();
const pktPubAttacker = attackerPrivKey.toPublic().toPacketList();
const dataToSign = {
key: attackerPrivKey.toPublic().keyPacket,
bind: pktPubVictim[3] // victim subkey
};
const fakeBindingSignature = new SignaturePacket();
fakeBindingSignature.signatureType = enums.signature.subkeyBinding;
fakeBindingSignature.publicKeyAlgorithm = attackerPrivKey.keyPacket.algorithm;
fakeBindingSignature.hashAlgorithm = enums.hash.sha256;
fakeBindingSignature.keyFlags = [enums.keyFlags.signData];
await fakeBindingSignature.sign(attackerPrivKey.keyPacket, dataToSign);
const newList = new PacketList();
newList.push(
pktPubAttacker[0], // attacker private key
pktPubAttacker[1], // attacker user
pktPubAttacker[2], // attacker self signature
pktPubVictim[3], // victim subkey
fakeBindingSignature // faked key binding
);
let fakeKey = new PublicKey(newList);
fakeKey = await readKey({ armoredKey: await fakeKey.toPublic().armor() });
const verifyAttackerIsBatman = await openpgp.verify({
message: await readCleartextMessage({ cleartextMessage: signed }),
verificationKeys: fakeKey
});
// expect the signature to have the expected keyID, but be invalid due to fake key binding signature in the subkey
expect(verifyAttackerIsBatman.signatures[0].keyID.equals(victimPubKey.subkeys[0].getKeyID())).to.be.true;
await expect(verifyAttackerIsBatman.signatures[0].verified).to.be.rejectedWith(/Could not find valid signing key packet/);
});