Fix encoded length in unencrypted v5 secret key packets (#1278)

When unencrypted secret key packets are serialized, a 2-byte checksum is
appended after the key material. According to rfc4880bis, these 2 bytes are
not included in the length of the key material (this encoded length is a new
addition of rfc4880bis, specific to v5 keys). We erroneously included them,
causing other implementations to fail to parse unencrypted v5 private keys
generated by OpenPGP.js.
This commit is contained in:
Kostis Andrikopoulos 2021-04-06 15:00:45 +02:00 committed by GitHub
parent 2e19f1401c
commit 39aa742c7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 5 deletions

View File

@ -205,17 +205,17 @@ class SecretKeyPacket extends PublicKeyPacket {
if (!this.isDummy()) {
if (!this.s2kUsage) {
const algo = enums.write(enums.publicKey, this.algorithm);
const cleartextParams = crypto.serializeParams(algo, this.privateParams);
this.keyMaterial = util.concatUint8Array([
cleartextParams,
util.writeChecksum(cleartextParams)
]);
this.keyMaterial = crypto.serializeParams(algo, this.privateParams);
}
if (this.version === 5) {
arr.push(util.writeNumber(this.keyMaterial.length, 4));
}
arr.push(this.keyMaterial);
if (!this.s2kUsage) {
arr.push(util.writeChecksum(this.keyMaterial));
}
}
return util.concatUint8Array(arr);

View File

@ -858,6 +858,41 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+
expect(secretKeyPacket2.publicParams).to.deep.equal(secretKeyPacket.publicParams);
});
it('Writing of unencrypted v5 secret key packet', async function() {
const originalV5KeysSetting = openpgp.config.v5Keys;
openpgp.config.v5Keys = true;
try {
const packet = new openpgp.SecretKeyPacket();
packet.privateParams = { key: new Uint8Array([1, 2, 3]) };
packet.publicParams = { pubKey: new Uint8Array([4, 5, 6]) };
packet.algorithm = "rsaSign";
packet.isEncrypted = false;
packet.s2kUsage = 0;
const written = packet.write();
expect(written.length).to.equal(28);
/* The serialized length of private data */
expect(written[17]).to.equal(0);
expect(written[18]).to.equal(0);
expect(written[19]).to.equal(0);
expect(written[20]).to.equal(5);
/**
* The private data
*
* The 2 bytes missing here are the length prefix of the MPI
*/
expect(written[23]).to.equal(1);
expect(written[24]).to.equal(2);
expect(written[25]).to.equal(3);
} finally {
openpgp.config.v5Keys = originalV5KeysSetting;
}
});
it('Writing and encryption of a secret key packet (CFB)', async function() {
const rsa = openpgp.enums.publicKey.rsaEncryptSign;
const { privateParams, publicParams } = await crypto.generateParams(rsa, 1024, 65537);