Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add checkKeyCompatibility() #191

Merged
merged 3 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ module.exports = function(config) {
},

webpack: {
optimization: {
nodeEnv: 'production', // silence OpenPGP.js debug errors, triggered by some tests
},
resolve: {
fallback: {
stream: false,
Expand Down
143 changes: 0 additions & 143 deletions lib/key/check.js

This file was deleted.

92 changes: 92 additions & 0 deletions lib/key/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { AlgorithmInfo, PublicKey, enums } from '../openpgp';

/**
* Checks whether the primary key and the subkeys meet our recommended security requirements.
* These checks are lightweight and do not verify the validity of the subkeys.
* A key is considered secure if it is:
* - RSA of size >= 2047 bits
* - ECC using curve 25519 or any of the NIST curves
* @param {OpenPGPKey} publicKey - key to check
* @throws {Error} if the key is considered too weak
*/
export function checkKeyStrength(publicKey: PublicKey) {
const minRSABits = 2047; // allow 1-bit short keys due to https://github.com/openpgpjs/openpgpjs/pull/1336
const allowedCurves: Set<AlgorithmInfo['curve']> = new Set([
enums.curve.ed25519Legacy,
enums.curve.curve25519Legacy,
enums.curve.p256,
enums.curve.p384,
enums.curve.p521
]);
const allowedPublicKeyAlgorithms = new Set([
enums.publicKey.rsaEncryptSign,
enums.publicKey.rsaSign,
enums.publicKey.rsaEncrypt,
enums.publicKey.ecdh,
enums.publicKey.ecdsa,
enums.publicKey.eddsaLegacy
]);

publicKey.getKeys().forEach(({ keyPacket }) => {
const keyInfo = keyPacket.getAlgorithmInfo();
// @ts-ignore missing `write` declaration
const keyAlgo = enums.write(enums.publicKey, keyInfo.algorithm);

if (!allowedPublicKeyAlgorithms.has(keyAlgo)) {
throw new Error(`${keyInfo.algorithm} keys are considered unsafe`);
}

if (keyInfo.curve && !allowedCurves.has(keyInfo.curve)) {
throw new Error(`Keys using curve ${keyInfo.curve} are considered unsafe`);
}

if (keyInfo.bits && keyInfo.bits < minRSABits) {
throw new Error(`Keys shorter than ${minRSABits} bits are considered unsafe`);
}
});
}

/**
* Checks whether the key is compatible with all Proton clients.
*/
export function checkKeyCompatibility(publicKey: PublicKey) {
const supportedPublicKeyAlgorithms = new Set([
enums.publicKey.dsa,
enums.publicKey.elgamal,
enums.publicKey.rsaEncryptSign,
enums.publicKey.rsaSign,
enums.publicKey.rsaEncrypt,
enums.publicKey.ecdh,
enums.publicKey.ecdsa,
enums.publicKey.eddsaLegacy
]);

const supportedCurves: Set<AlgorithmInfo['curve']> = new Set([
enums.curve.ed25519Legacy,
enums.curve.curve25519Legacy,
enums.curve.p256,
enums.curve.p384,
enums.curve.p521,
enums.curve.brainpoolP256r1,
enums.curve.brainpoolP384r1,
enums.curve.brainpoolP512r1
]);

if (publicKey.keyPacket.version > 5) {
throw new Error(`Version ${publicKey.keyPacket.version} keys are currently not supported.`);
}

publicKey.getKeys().forEach(({ keyPacket }) => {
const keyInfo = keyPacket.getAlgorithmInfo();
// @ts-ignore missing `write` declaration
const keyAlgo = enums.write(enums.publicKey, keyInfo.algorithm);

if (!supportedPublicKeyAlgorithms.has(keyAlgo)) {
throw new Error('The key algorithm is currently not supported.');
}

if (keyInfo.curve && !supportedCurves.has(keyInfo.curve)) {
throw new Error(`Keys using curve ${keyInfo.curve} are currently not supported.`);
}
});
}
115 changes: 0 additions & 115 deletions lib/key/info.js

This file was deleted.

11 changes: 7 additions & 4 deletions lib/pmcrypto.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import {
WebStream,
readMessage, readSignature, readCleartextMessage,
readKey, readKeys, readPrivateKey, readPrivateKeys,
PartialConfig
PartialConfig,
enums,
EllipticCurveName
} from 'openpgp/lightweight';

import { VERIFICATION_STATUS, SIGNATURE_TYPES } from './constants';
Expand Down Expand Up @@ -204,10 +206,11 @@ export {
stripArmor
} from './message/utils';

export type PublicKeyNames = enums.publicKeyNames | 'ed25519' | 'x25519'; // TODO drop once types are updated in OpenPGP.js v6
export interface AlgorithmInfo {
algorithm: string;
algorithm: PublicKeyNames;
bits?: number; // if algorithm == 'rsaEncryptSign' | 'rsaEncrypt' | 'rsaSign'
curve?: string; // if algorithm == 'ecdh' | 'eddsa' | 'ecdsa'
curve?: EllipticCurveName; // if algorithm == 'ecdh' | 'eddsa' | 'ecdsa'
}

export { SHA256, SHA512, unsafeMD5, unsafeSHA1 } from './crypto/hash';
Expand All @@ -219,4 +222,4 @@ export type { ContextSigningOptions, ContextVerificationOptions };
export { MIMEAttachment, ProcessMIMEOptions, default as processMIME, ProcessMIMEResult } from './message/processMIME';

export { serverTime, updateServerTime } from './serverTime';
export function checkKeyStrength(key: OpenPGPKey): void;
export { checkKeyStrength, checkKeyCompatibility } from './key/check';
Loading