Skip to content

Commit

Permalink
checkKeyStrength: whitelist Curve25519/448 algos (new format)
Browse files Browse the repository at this point in the history
These key algos have been standardized in RFC9580 and should not
be considered weak.
  • Loading branch information
larabr committed Nov 13, 2024
1 parent 651c034 commit c957336
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 37 deletions.
15 changes: 11 additions & 4 deletions lib/key/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,24 @@ export function checkKeyStrength(publicKey: PublicKey) {
const allowedCurves: Set<AlgorithmInfo['curve']> = new Set([
enums.curve.ed25519Legacy,
enums.curve.curve25519Legacy,
enums.curve.p256,
enums.curve.p384,
enums.curve.p521
enums.curve.nistP256,
enums.curve.nistP384,
enums.curve.nistP521
]);
const allowedPublicKeyAlgorithms = new Set([
enums.publicKey.rsaEncryptSign,
enums.publicKey.rsaSign,
enums.publicKey.rsaEncrypt,
enums.publicKey.ecdh,
enums.publicKey.ecdsa,
enums.publicKey.eddsaLegacy
enums.publicKey.eddsaLegacy,
// the following algos are currently only supported for v6 keys, but discriminating
// based on the key version is not important here, as we assume `checkKeyCompatibility`
// is used for that.
enums.publicKey.ed25519,
enums.publicKey.x25519,
enums.publicKey.ed448,
enums.publicKey.x448
]);

publicKey.getKeys().forEach(({ keyPacket }) => {
Expand Down
70 changes: 38 additions & 32 deletions test/key/check.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { expect } from 'chai';
import { checkKeyStrength, checkKeyCompatibility, readKey } from '../../lib';

export const ecc25519Key = `-----BEGIN PGP PUBLIC KEY BLOCK-----
export const curve25519KeyV6 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
-----END PGP PUBLIC KEY BLOCK-----`;

export const curve25519LegacyKeyV4 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
xjMEYRaiLRYJKwYBBAHaRw8BAQdAMrsrfniSJuxOLn+Q3VKP0WWqgizG4VOF
6t0HZYx8mSnNEHRlc3QgPHRlc3RAYS5pdD7CjAQQFgoAHQUCYRaiLQQLCQcI
Expand All @@ -15,7 +28,7 @@ po3C/804tJkeKgEA0ruKx9rcMTi4LxfYgijjPrI+GgrfegfREt/YN2KQ75gA
=8+ep
-----END PGP PUBLIC KEY BLOCK-----`;

export const eddsaElGamalSubkey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
export const eddsaLegacyElGamalSubkeyV4 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
xVgEYRU8lhYJKwYBBAHaRw8BAQdAixQ3oWfWg0zF8Dr8iCSKI7d87uR0D8KT
jaXmeP/BFLMAAQC6l0agypEfDhEsPXnooVeQ9RdbuQJt79G0X0fEMJUaHA6L
Expand All @@ -41,7 +54,7 @@ LAhjJS/ggyNCU/A+d6Eu9gacwFDD3j0IQLNe012Z2wU=
=qRad
-----END PGP PRIVATE KEY BLOCK-----`;

export const rsa512BitsKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
export const rsa512BitsKeyV4 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
xk0EYRam4gECALVRNFX0hcAEE2+FfdzawLPZJwyk2Lt4Rw/iWk+lBmbWuifM
b7vbYKV2gGBnyEIoo1P6eN6aN7sRFtYYL0uVWB0AEQEAAc0QdGVzdCA8dGVz
Expand All @@ -57,28 +70,33 @@ m53MXUW1fnpBPuv9RWJDN+tLhm5FPJktpuElr6hcBg==
-----END PGP PUBLIC KEY BLOCK-----`;

describe('key checks', () => {
it('it warns on insecure primary key (RSA 512 bits)', async () => {
const key = await readKey({ armoredKey: rsa512BitsKey });
it('checkKeyStrength - it warns on insecure primary key (RSA 512 bits)', async () => {
const key = await readKey({ armoredKey: rsa512BitsKeyV4 });
expect(
() => checkKeyStrength(key)
).to.throw(/Keys shorter than 2047 bits are considered unsafe/);
});

it('it warns on insecure subkey (ElGamal)', async () => {
const key = await readKey({ armoredKey: eddsaElGamalSubkey });
it('checkKeyStrength - it warns on insecure subkey (ElGamal)', async () => {
const key = await readKey({ armoredKey: eddsaLegacyElGamalSubkeyV4 });
expect(
() => checkKeyStrength(key)
).to.throw(/elgamal keys are considered unsafe/);
});

it('it does not warn on secure key (x25519)', async () => {
const key = await readKey({ armoredKey: ecc25519Key });
it('checkKeyStrength - it does not warn on secure key (curve25519Legacy)', async () => {
const v4Key = await readKey({ armoredKey: curve25519LegacyKeyV4 });
expect(
() => checkKeyStrength(key)
).to.not.throw;
() => checkKeyStrength(v4Key)
).to.not.throw();

const v6Key = await readKey({ armoredKey: curve25519KeyV6 });
expect(
() => checkKeyStrength(v6Key)
).to.not.throw();
});

it('compatibility - it rejects a v4 key using the new EdDSA format', async () => {
it('checkKeyCompatibility - it rejects a v4 key using the new EdDSA format', async () => {
const key = await readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
xiYEZIbSkxsHknQrXGfb+kM2iOsOvin8yE05ff5hF8KE6k+saspAZc0VdXNl
Expand All @@ -96,7 +114,7 @@ Gw0vQaiZn6HGITQw5nBGvXQPF9VpFpsXV9x/08dIdfZLAQVdQowgeBsxCw==
).to.throw(/key algorithm ed25519 is currently not supported/);
});

it('compatibility - it rejects a v5 key', async () => {
it('checkKeyCompatibility - it rejects a v5 key', async () => {
const key = await readKey({
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
Expand All @@ -114,39 +132,27 @@ FcJ6BRgWCAAsBYJkLu2/ApsMIqEFD9jz083B91dR0j+13lD2s2tg/2ZvsODq
T/efFOC6BDkAAHcjAPwIPNHnR9bKmkVop6cE05dCIpZ/W8zXDGnjKYrrC4Hb
4gEAmISD1GRkNOmCV8aHwN5svO6HuwXR4cR3o3l7HlYeag8=
=wpkQ
-----END PGP PRIVATE KEY BLOCK-----`,
config: { enableParsingV5Entities: true }
-----END PGP PRIVATE KEY BLOCK-----`
});
expect(
() => checkKeyCompatibility(key)
).to.throw(/Version 5 keys are currently not supported/);
});

it('compatibility - it rejects a v6 key unless explicitly allowed', async () => {
const key = await readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
-----END PGP PUBLIC KEY BLOCK-----` });
it('checkKeyCompatibility - it rejects a v6 key unless explicitly allowed', async () => {
const key = await readKey({ armoredKey: curve25519KeyV6 });
expect(
() => checkKeyCompatibility(key)
).to.throw(/Version 6 keys are currently not supported/);
expect(
() => checkKeyCompatibility(key, true)
).to.not.throw;
).to.not.throw();
});

it('compatibility - it does not reject a v4 key using the eddsa legacy format', async () => {
const key = await readKey({ armoredKey: ecc25519Key });
it('checkKeyCompatibility - it does not reject a v4 key using the eddsa legacy format', async () => {
const key = await readKey({ armoredKey: curve25519LegacyKeyV4 });
expect(
() => checkKeyCompatibility(key)
).to.not.throw;
).to.not.throw();
});
});
1 change: 0 additions & 1 deletion test/key/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ T/efFOC6BDkAAHcjAPwIPNHnR9bKmkVop6cE05dCIpZ/W8zXDGnjKYrrC4Hb
const { privateKey: reformattedKey } = await reformatKey({ privateKey, passphrase: '123', userIDs: [{ name: 'reformatted', email: '[email protected]' }], format: 'object' });
const primaryUser = await reformattedKey.getPrimaryUser();
expect(primaryUser.user.userID?.userID).to.equal('reformatted <[email protected]>');
// @ts-ignore missing `created` field declaration in signature packet
expect((await reformattedKey.getPrimaryUser()).selfCertification.created).to.deep.equal(date);
});

Expand Down

0 comments on commit c957336

Please sign in to comment.