mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00
Disable support for parsing v5 entities by default (add config.enableParsingV5Entities
) (#1774)
Parsing of v5 keys, v5 signatures and AEAD-encrypted data packets now requires turning on the corresponding config flag. The affected entities are non-standard, and in the crypto-refresh RFC they have been superseded by v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively. However, generation of v5 entities was supported behind config flag in OpenPGP.js v5, and some other libraries, hence parsing them might be necessary in some cases.
This commit is contained in:
parent
9efdaf14b1
commit
5268c484e9
@ -81,6 +81,15 @@ export default {
|
||||
* @property {Boolean} v6Keys
|
||||
*/
|
||||
v6Keys: false,
|
||||
/**
|
||||
* Enable parsing v5 keys, v5 signatures and AEAD-encrypted data packets
|
||||
* (which is different from the AEAD-encrypted SEIPDv2 packet).
|
||||
* These are non-standard entities, which in the crypto-refresh have been superseded
|
||||
* by v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively.
|
||||
* However, generation of v5 entities was supported behind config flag in OpenPGP.js v5, and some other libraries,
|
||||
* hence parsing them might be necessary in some cases.
|
||||
*/
|
||||
enableParsingV5Entities: false,
|
||||
/**
|
||||
* S2K (String to Key) type, used for key derivation in the context of secret key encryption
|
||||
* and password-encrypted data. Weaker s2k options are not allowed.
|
||||
|
@ -68,7 +68,10 @@ class AEADEncryptedDataPacket {
|
||||
* @param {Uint8Array | ReadableStream<Uint8Array>} bytes
|
||||
* @throws {Error} on parsing failure
|
||||
*/
|
||||
async read(bytes) {
|
||||
async read(bytes, config = defaultConfig) {
|
||||
if (!config.enableParsingV5Entities) {
|
||||
throw new UnsupportedError('Support for parsing v5 entities is disabled; turn on `config.enableParsingV5Entities` if needed');
|
||||
}
|
||||
await stream.parse(bytes, async reader => {
|
||||
const version = await reader.readByte();
|
||||
if (version !== VERSION) { // The only currently defined value is 1.
|
||||
|
@ -104,10 +104,13 @@ class PublicKeyPacket {
|
||||
* @returns {Object} This object with attributes set by the parser
|
||||
* @async
|
||||
*/
|
||||
async read(bytes) {
|
||||
async read(bytes, config = defaultConfig) {
|
||||
let pos = 0;
|
||||
// A one-octet version number (4, 5 or 6).
|
||||
this.version = bytes[pos++];
|
||||
if (this.version === 5 && !config.enableParsingV5Entities) {
|
||||
throw new UnsupportedError('Support for parsing v5 entities is disabled; turn on `config.enableParsingV5Entities` if needed');
|
||||
}
|
||||
|
||||
if (this.version === 4 || this.version === 5 || this.version === 6) {
|
||||
// - A four-octet number denoting the time that the key was created.
|
||||
|
@ -102,7 +102,7 @@ class SecretKeyPacket extends PublicKeyPacket {
|
||||
*/
|
||||
async read(bytes, config = defaultConfig) {
|
||||
// - A Public-Key or Public-Subkey packet, as described above.
|
||||
let i = await this.readPublicKey(bytes);
|
||||
let i = await this.readPublicKey(bytes, config);
|
||||
const startOfSecretKeyData = i;
|
||||
|
||||
// - One octet indicating string-to-key usage conventions. Zero
|
||||
|
@ -117,9 +117,12 @@ class SignaturePacket {
|
||||
* @param {String} bytes - Payload of a tag 2 packet
|
||||
* @returns {SignaturePacket} Object representation.
|
||||
*/
|
||||
read(bytes) {
|
||||
read(bytes, config = defaultConfig) {
|
||||
let i = 0;
|
||||
this.version = bytes[i++];
|
||||
if (this.version === 5 && !config.enableParsingV5Entities) {
|
||||
throw new UnsupportedError('Support for v5 entities is disabled; turn on `config.enableParsingV5Entities` if needed');
|
||||
}
|
||||
|
||||
if (this.version !== 4 && this.version !== 5 && this.version !== 6) {
|
||||
throw new UnsupportedError(`Version ${this.version} of the signature packet is unsupported.`);
|
||||
|
@ -2951,19 +2951,6 @@ function versionSpecificTests() {
|
||||
await expect(privateKey.verifyPrimaryKey()).to.be.fulfilled;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('Parses V5 sample key', async function() {
|
||||
// sec ed25519 2019-03-20 [SC]
|
||||
// 19347BC9872464025F99DF3EC2E0000ED9884892E1F7B3EA4C94009159569B54
|
||||
// uid emma.goldman@example.net
|
||||
// ssb cv25519 2019-03-20 [E]
|
||||
// E4557C2B02FFBF4B04F87401EC336AF7133D0F85BE7FD09BAEFD9CAEB8C93965
|
||||
const key = await openpgp.readKey({ armoredKey: v5_sample_key });
|
||||
expect(await key.keyPacket.getFingerprint()).to.equal('19347bc9872464025f99df3ec2e0000ed9884892e1f7b3ea4c94009159569b54');
|
||||
expect(await key.subkeys[0].getFingerprint()).to.equal('e4557c2b02ffbf4b04f87401ec336af7133d0f85be7fd09baefd9caeb8c93965');
|
||||
await key.verifyPrimaryKey();
|
||||
});
|
||||
}
|
||||
|
||||
export default () => describe('Key', function() {
|
||||
@ -3032,6 +3019,18 @@ export default () => describe('Key', function() {
|
||||
expect(key.write()).to.deep.equal(expectedSerializedKey.data);
|
||||
});
|
||||
|
||||
it('Parses V5 sample key', async function() {
|
||||
// sec ed25519 2019-03-20 [SC]
|
||||
// 19347BC9872464025F99DF3EC2E0000ED9884892E1F7B3EA4C94009159569B54
|
||||
// uid emma.goldman@example.net
|
||||
// ssb cv25519 2019-03-20 [E]
|
||||
// E4557C2B02FFBF4B04F87401EC336AF7133D0F85BE7FD09BAEFD9CAEB8C93965
|
||||
const key = await openpgp.readKey({ armoredKey: v5_sample_key, config: { enableParsingV5Entities: true } });
|
||||
expect(await key.keyPacket.getFingerprint()).to.equal('19347bc9872464025f99df3ec2e0000ed9884892e1f7b3ea4c94009159569b54');
|
||||
expect(await key.subkeys[0].getFingerprint()).to.equal('e4557c2b02ffbf4b04f87401ec336af7133d0f85be7fd09baefd9caeb8c93965');
|
||||
await key.verifyPrimaryKey();
|
||||
});
|
||||
|
||||
it('Parsing V5 public key packet', async function() {
|
||||
// Manually modified from https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b2092/back.mkd#sample-eddsa-key
|
||||
const packetBytes = util.hexToUint8Array(`
|
||||
@ -3065,7 +3064,7 @@ T/efFOC6BDkAAHcjAPwIPNHnR9bKmkVop6cE05dCIpZ/W8zXDGnjKYrrC4Hb
|
||||
=wpkQ
|
||||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||
const passphrase = 'password';
|
||||
const encryptedKey = await openpgp.readKey({ armoredKey });
|
||||
const encryptedKey = await openpgp.readKey({ armoredKey, config: { enableParsingV5Entities: true } });
|
||||
const decryptedKey = await openpgp.decryptKey({
|
||||
privateKey: encryptedKey,
|
||||
passphrase
|
||||
@ -3485,7 +3484,7 @@ PzIEeL7UH3trraFmi+Gq8u4kAA==
|
||||
});
|
||||
|
||||
it('should pad an ECDSA P-521 key with shorter secret key', async function() {
|
||||
const key = await openpgp.readKey({ armoredKey: shortP521Key });
|
||||
const key = await openpgp.readKey({ armoredKey: shortP521Key, config: { enableParsingV5Entities: true } });
|
||||
// secret key should be padded
|
||||
expect(key.keyPacket.privateParams.d.length === 66);
|
||||
// sanity check
|
||||
|
@ -174,7 +174,7 @@ export default () => describe('Packet', function() {
|
||||
const msg2 = new openpgp.PacketList();
|
||||
|
||||
return enc.encrypt(algo, key, undefined, openpgp.config).then(async function() {
|
||||
await msg2.read(msg.write(), allAllowedPackets);
|
||||
await msg2.read(msg.write(), allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
return msg2[0].decrypt(algo, key);
|
||||
}).then(async function() {
|
||||
expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||
@ -229,7 +229,7 @@ export default () => describe('Packet', function() {
|
||||
|
||||
try {
|
||||
await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 0 });
|
||||
await msg2.read(msg.write(), allAllowedPackets);
|
||||
await msg2.read(msg.write(), allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
await msg2[0].decrypt(algo, key);
|
||||
expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||
expect(encryptStub.callCount > 1).to.be.true;
|
||||
@ -276,7 +276,7 @@ export default () => describe('Packet', function() {
|
||||
await enc.encrypt(algo, key, { ...openpgp.config, aeadChunkSizeByte: 14 });
|
||||
const data = msg.write();
|
||||
expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
|
||||
await msg2.read(data, allAllowedPackets);
|
||||
await msg2.read(data, allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
await msg2[0].decrypt(algo, key);
|
||||
expect(await stream.readToEnd(msg2[0].packets[0].data)).to.deep.equal(literal.data);
|
||||
} finally {
|
||||
@ -706,7 +706,7 @@ export default () => describe('Packet', function() {
|
||||
await aeadEnc.encrypt(algo, key, undefined, openpgp.config);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
await msg2.read(msg.write(), allAllowedPackets);
|
||||
await msg2.read(msg.write(), allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
|
||||
await msg2[0].decrypt(passphrase);
|
||||
const key2 = msg2[0].sessionKey;
|
||||
@ -744,7 +744,7 @@ export default () => describe('Packet', function() {
|
||||
await aeadEnc.encrypt(algo, key, undefined, openpgp.config);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
await msg2.read(msg.write(), allAllowedPackets);
|
||||
await msg2.read(msg.write(), allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
|
||||
await msg2[0].decrypt(passphrase);
|
||||
const key2 = msg2[0].sessionKey;
|
||||
@ -820,7 +820,7 @@ export default () => describe('Packet', function() {
|
||||
expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
await msg2.read(data, allAllowedPackets);
|
||||
await msg2.read(data, allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
|
||||
await msg2[0].decrypt(passphrase);
|
||||
const key2 = msg2[0].sessionKey;
|
||||
@ -899,7 +899,7 @@ export default () => describe('Packet', function() {
|
||||
expect(await stream.readToEnd(stream.clone(data))).to.deep.equal(packetBytes);
|
||||
|
||||
const msg2 = new openpgp.PacketList();
|
||||
await msg2.read(data, allAllowedPackets);
|
||||
await msg2.read(data, allAllowedPackets, { ...openpgp.config, enableParsingV5Entities: true });
|
||||
|
||||
await msg2[0].decrypt(passphrase);
|
||||
const key2 = msg2[0].sessionKey;
|
||||
|
@ -2417,7 +2417,7 @@ oaBUyhCKt8tz6Q==
|
||||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||
const key = await openpgp.readKey({ armoredKey });
|
||||
const decrypted = await openpgp.decrypt({
|
||||
message: await openpgp.readMessage({ armoredMessage: encrypted }),
|
||||
message: await openpgp.readMessage({ armoredMessage: encrypted, config: { enableParsingV5Entities: true } }),
|
||||
verificationKeys: key,
|
||||
decryptionKeys: key,
|
||||
config: { minRSABits: 1024 }
|
||||
@ -2476,7 +2476,8 @@ EYaN9YdDOU2jF+HOaSNaJAsPF8J6BRgTCAAJBQJf0mstAhsMACMiIQUee6Tb
|
||||
AcvDfr9a0Cp4WAVzKDKLUzrRMgEAozi0VyjiBo1U2LcwTPJkA4PEQqQRVW1D
|
||||
KZTMSAH7JEo=
|
||||
=tqWy
|
||||
-----END PGP PRIVATE KEY BLOCK-----`
|
||||
-----END PGP PRIVATE KEY BLOCK-----`,
|
||||
config: { enableParsingV5Entities: true }
|
||||
});
|
||||
const signed = `-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA256
|
||||
@ -2489,7 +2490,7 @@ A3X6psihFkcA+Nuog2qpAq20Zc2lzVjDZzQosb8MLvKMg3UFCX12Oc0BAJwd
|
||||
JImeZLY02MctIpGZULbqgcUGK0P/yqrPL8Pe4lQM
|
||||
=Pacb
|
||||
-----END PGP SIGNATURE-----`;
|
||||
const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
||||
const message = await openpgp.readCleartextMessage({ cleartextMessage: signed, config: { enableParsingV5Entities: true } });
|
||||
const verified = await openpgp.verify({ verificationKeys: key, message });
|
||||
expect(await verified.signatures[0].verified).to.be.true;
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user