Add config.rejectPublicKeyAlgorithms (#1264)

- Add `config.rejectPublicKeyAlgorithms` to disallow using the given algorithms
  to verify, sign or encrypt new messages or third-party certifications.

- Consider `config.minRsaBits` when signing, verifying and encrypting messages
  and third-party certifications, not just on key generation.

- When verifying a message, if the verification key is not found (i.e. not
  provided or too weak), the corresponding `signature` will have
  `signature.valid=false` (used to be `signature.valid=null`).
  `signature.error` will detail whether the key is missing/too weak/etc.

Generating and verifying key certification signatures is still permitted in all cases.
This commit is contained in:
larabr 2021-03-25 15:08:49 +01:00 committed by GitHub
parent 3e808c1578
commit 8a57246ec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 759 additions and 518 deletions

View File

@ -215,7 +215,7 @@ module.exports = {
"no-restricted-imports": "error", "no-restricted-imports": "error",
"no-restricted-modules": "error", "no-restricted-modules": "error",
"no-restricted-properties": "error", "no-restricted-properties": "error",
"no-restricted-syntax": "error", "no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"],
"no-return-assign": "error", "no-return-assign": "error",
"no-return-await": "error", "no-return-await": "error",
"no-script-url": "error", "no-script-url": "error",
@ -344,7 +344,7 @@ module.exports = {
"no-use-before-define": [ 2, { "functions": false, "classes": true, "variables": false }], "no-use-before-define": [ 2, { "functions": false, "classes": true, "variables": false }],
"no-constant-condition": [ 2, { "checkLoops": false } ], "no-constant-condition": [ 2, { "checkLoops": false } ],
"new-cap": [ 2, { "properties": false, "capIsNewExceptionPattern": "EAX|OCB|GCM|CMAC|CBC|OMAC|CTR", "newIsCapExceptionPattern": "type|hash*"}], "new-cap": [ 2, { "properties": false, "capIsNewExceptionPattern": "EAX|OCB|GCM|CMAC|CBC|OMAC|CTR", "newIsCapExceptionPattern": "type|hash*"}],
"max-lines": [ 2, { "max": 600, "skipBlankLines": true, "skipComments": true } ], "max-lines": [ 2, { "max": 620, "skipBlankLines": true, "skipComments": true } ],
"no-unused-expressions": 0, "no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": [ 2, { "allowShortCircuit": true } ], "chai-friendly/no-unused-expressions": [ 2, { "allowShortCircuit": true } ],

View File

@ -77,7 +77,9 @@ export class CleartextMessage {
* @param {Array<Key>} keys - Array of keys to verify signatures * @param {Array<Key>} keys - Array of keys to verify signatures
* @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time * @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Array<{keyid: module:type/keyid~Keyid, valid: Boolean}>} List of signer's keyid and validity of signature. * @returns {Array<{keyid: module:type/keyid~Keyid,
* signature: Promise<Signature>,
* verified: Promise<Boolean>}>} List of signer's keyid and validity of signature.
* @async * @async
*/ */
verify(keys, date = new Date(), config = defaultConfig) { verify(keys, date = new Date(), config = defaultConfig) {

View File

@ -105,7 +105,7 @@ export default {
checksumRequired: false, checksumRequired: false,
/** /**
* @memberof module:config * @memberof module:config
* @property {Number} minRsaBits Minimum RSA key size allowed for key generation * @property {Number} minRsaBits Minimum RSA key size allowed for key generation and message signing, verification and encryption
*/ */
minRsaBits: 2048, minRsaBits: 2048,
/** /**
@ -180,13 +180,21 @@ export default {
*/ */
useIndutnyElliptic: true, useIndutnyElliptic: true,
/** /**
* Reject insecure hash algorithms
* @memberof module:config * @memberof module:config
* @property {Set<Integer>} reject_hash_algorithms Reject insecure hash algorithms {@link module:enums.hash} * @property {Set<Integer>} rejectHashAlgorithms {@link module:enums.hash}
*/ */
rejectHashAlgorithms: new globalThis.Set([enums.hash.md5, enums.hash.ripemd]), rejectHashAlgorithms: new Set([enums.hash.md5, enums.hash.ripemd]),
/** /**
* Reject insecure message hash algorithms
* @memberof module:config * @memberof module:config
* @property {Set<Integer>} reject_message_hash_algorithms Reject insecure message hash algorithms {@link module:enums.hash} * @property {Set<Integer>} rejectMessageHashAlgorithms {@link module:enums.hash}
*/ */
rejectMessageHashAlgorithms: new globalThis.Set([enums.hash.md5, enums.hash.ripemd, enums.hash.sha1]) rejectMessageHashAlgorithms: new Set([enums.hash.md5, enums.hash.ripemd, enums.hash.sha1]),
/**
* Reject insecure public key algorithms for message encryption, signing or verification
* @memberof module:config
* @property {Set<Integer>} rejectPublicKeyAlgorithms {@link module:enums.publicKey}
*/
rejectPublicKeyAlgorithms: new Set([enums.publicKey.elgamal, enums.publicKey.dsa])
}; };

View File

@ -67,42 +67,42 @@ export async function generate(options, config) {
*/ */
export async function reformat(options, config) { export async function reformat(options, config) {
options = sanitize(options); options = sanitize(options);
const { privateKey } = options;
if (options.privateKey.primaryKey.isDummy()) { if (privateKey.isPublic()) {
throw new Error('Cannot reformat a public key');
}
if (privateKey.primaryKey.isDummy()) {
throw new Error('Cannot reformat a gnu-dummy primary key'); throw new Error('Cannot reformat a gnu-dummy primary key');
} }
const isDecrypted = options.privateKey.getKeys().every(({ keyPacket }) => keyPacket.isDecrypted()); const isDecrypted = privateKey.getKeys().every(({ keyPacket }) => keyPacket.isDecrypted());
if (!isDecrypted) { if (!isDecrypted) {
throw new Error('Key is not decrypted'); throw new Error('Key is not decrypted');
} }
const packetlist = options.privateKey.toPacketlist(); const secretKeyPacket = privateKey.keyPacket;
let secretKeyPacket;
const secretSubkeyPackets = [];
for (let i = 0; i < packetlist.length; i++) {
if (packetlist[i].tag === enums.packet.secretKey) {
secretKeyPacket = packetlist[i];
} else if (packetlist[i].tag === enums.packet.secretSubkey) {
secretSubkeyPackets.push(packetlist[i]);
}
}
if (!secretKeyPacket) {
throw new Error('Key does not contain a secret key packet');
}
if (!options.subkeys) { if (!options.subkeys) {
options.subkeys = await Promise.all(secretSubkeyPackets.map(async secretSubkeyPacket => ({ options.subkeys = await Promise.all(privateKey.subKeys.map(async subkey => {
sign: await options.privateKey.getSigningKey(secretSubkeyPacket.getKeyId(), null, undefined, config).catch(() => {}) && const secretSubkeyPacket = subkey.keyPacket;
!await options.privateKey.getEncryptionKey(secretSubkeyPacket.getKeyId(), null, undefined, config).catch(() => {}) const dataToVerify = { key: secretKeyPacket, bind: secretSubkeyPacket };
}))); const bindingSignature = await (
helper.getLatestValidSignature(subkey.bindingSignatures, secretKeyPacket, enums.signature.subkeyBinding, dataToVerify, null, config)
).catch(() => ({}));
return {
sign: bindingSignature.keyFlags && (bindingSignature.keyFlags[0] & enums.keyFlags.signData)
};
}));
} }
const secretSubkeyPackets = privateKey.subKeys.map(subkey => subkey.keyPacket);
if (options.subkeys.length !== secretSubkeyPackets.length) { if (options.subkeys.length !== secretSubkeyPackets.length) {
throw new Error('Number of subkey options does not match number of subkeys'); throw new Error('Number of subkey options does not match number of subkeys');
} }
options.subkeys = options.subkeys.map(function(subkey, index) { return sanitize(options.subkeys[index], options); }); options.subkeys = options.subkeys.map(subkeyOptions => sanitize(subkeyOptions, options));
return wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config); return wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config);

View File

@ -370,9 +370,11 @@ export function isValidSigningKeyPacket(keyPacket, signature) {
if (!signature.verified || signature.revoked !== false) { // Sanity check if (!signature.verified || signature.revoked !== false) { // Sanity check
throw new Error('Signature not verified'); throw new Error('Signature not verified');
} }
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsaEncrypt) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.elgamal) && const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm);
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdh) && return keyAlgo !== enums.publicKey.rsaEncrypt &&
keyAlgo !== enums.publicKey.elgamal &&
keyAlgo !== enums.publicKey.ecdh &&
(!signature.keyFlags || (!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.signData) !== 0); (signature.keyFlags[0] & enums.keyFlags.signData) !== 0);
} }
@ -381,10 +383,12 @@ export function isValidEncryptionKeyPacket(keyPacket, signature) {
if (!signature.verified || signature.revoked !== false) { // Sanity check if (!signature.verified || signature.revoked !== false) { // Sanity check
throw new Error('Signature not verified'); throw new Error('Signature not verified');
} }
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsaSign) && const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm);
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdsa) && return keyAlgo !== enums.publicKey.dsa &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.eddsa) && keyAlgo !== enums.publicKey.rsaSign &&
keyAlgo !== enums.publicKey.ecdsa &&
keyAlgo !== enums.publicKey.eddsa &&
(!signature.keyFlags || (!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 || (signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0); (signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0);
@ -396,7 +400,7 @@ export function isValidDecryptionKeyPacket(signature, config) {
} }
if (config.allowInsecureDecryptionWithSigningKeys) { if (config.allowInsecureDecryptionWithSigningKeys) {
// This is only relevant for RSA keys, all other signing ciphers cannot decrypt // This is only relevant for RSA keys, all other signing algorithms cannot decrypt
return true; return true;
} }
@ -404,3 +408,14 @@ export function isValidDecryptionKeyPacket(signature, config) {
(signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 || (signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0; (signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0;
} }
export function checkKeyStrength(keyPacket, config) {
const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm);
if (config.rejectPublicKeyAlgorithms.has(keyAlgo)) {
throw new Error(`${keyPacket.algorithm} keys are considered too weak.`);
}
const rsaAlgos = new Set([enums.publicKey.rsaEncryptSign, enums.publicKey.rsaSign, enums.publicKey.rsaEncrypt]);
if (rsaAlgos.has(keyAlgo) && util.uint8ArrayBitLength(keyPacket.publicParams.n) < config.minRsaBits) {
throw new Error(`RSA keys shorter than ${config.minRsaBits} bits are considered too weak.`);
}
}

View File

@ -291,29 +291,41 @@ class Key {
const primaryKey = this.keyPacket; const primaryKey = this.keyPacket;
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created); const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
let exception; let exception;
for (let i = 0; i < subKeys.length; i++) { for (const subKey of subKeys) {
if (!keyId || subKeys[i].getKeyId().equals(keyId)) { if (!keyId || subKey.getKeyId().equals(keyId)) {
try { try {
await subKeys[i].verify(primaryKey, date, config); await subKey.verify(primaryKey, date, config);
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket }; const dataToVerify = { key: primaryKey, bind: subKey.keyPacket };
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config); const bindingSignature = await helper.getLatestValidSignature(
if ( subKey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config
bindingSignature && );
bindingSignature.embeddedSignature && if (!helper.isValidSigningKeyPacket(subKey.keyPacket, bindingSignature)) {
helper.isValidSigningKeyPacket(subKeys[i].keyPacket, bindingSignature) && continue;
await helper.getLatestValidSignature([bindingSignature.embeddedSignature], subKeys[i].keyPacket, enums.signature.keyBinding, dataToVerify, date, config)
) {
return subKeys[i];
} }
if (!bindingSignature.embeddedSignature) {
throw new Error('Missing embedded signature');
}
// verify embedded signature
await helper.getLatestValidSignature(
[bindingSignature.embeddedSignature], subKey.keyPacket, enums.signature.keyBinding, dataToVerify, date, config
);
helper.checkKeyStrength(subKey.keyPacket, config);
return subKey;
} catch (e) { } catch (e) {
exception = e; exception = e;
} }
} }
} }
const primaryUser = await this.getPrimaryUser(date, userId, config);
if ((!keyId || primaryKey.getKeyId().equals(keyId)) && try {
helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification)) { const primaryUser = await this.getPrimaryUser(date, userId, config);
return this; if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, config)) {
helper.checkKeyStrength(primaryKey, config);
return this;
}
} catch (e) {
exception = e;
} }
throw util.wrapError('Could not find valid signing key packet in key ' + this.getKeyId().toHex(), exception); throw util.wrapError('Could not find valid signing key packet in key ' + this.getKeyId().toHex(), exception);
} }
@ -333,25 +345,32 @@ class Key {
// V4: by convention subkeys are preferred for encryption service // V4: by convention subkeys are preferred for encryption service
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created); const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
let exception; let exception;
for (let i = 0; i < subKeys.length; i++) { for (const subKey of subKeys) {
if (!keyId || subKeys[i].getKeyId().equals(keyId)) { if (!keyId || subKey.getKeyId().equals(keyId)) {
try { try {
await subKeys[i].verify(primaryKey, date, config); await subKey.verify(primaryKey, date, config);
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket }; const dataToVerify = { key: primaryKey, bind: subKey.keyPacket };
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config); const bindingSignature = await helper.getLatestValidSignature(subKey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
if (bindingSignature && helper.isValidEncryptionKeyPacket(subKeys[i].keyPacket, bindingSignature)) { if (helper.isValidEncryptionKeyPacket(subKey.keyPacket, bindingSignature)) {
return subKeys[i]; helper.checkKeyStrength(subKey.keyPacket, config);
return subKey;
} }
} catch (e) { } catch (e) {
exception = e; exception = e;
} }
} }
} }
// if no valid subkey for encryption, evaluate primary key
const primaryUser = await this.getPrimaryUser(date, userId, config); try {
if ((!keyId || primaryKey.getKeyId().equals(keyId)) && // if no valid subkey for encryption, evaluate primary key
helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) { const primaryUser = await this.getPrimaryUser(date, userId, config);
return this; if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
helper.checkKeyStrength(primaryKey, config);
return this;
}
} catch (e) {
exception = e;
} }
throw util.wrapError('Could not find valid encryption key packet in key ' + this.getKeyId().toHex(), exception); throw util.wrapError('Could not find valid encryption key packet in key ' + this.getKeyId().toHex(), exception);
} }
@ -374,7 +393,7 @@ class Key {
try { try {
const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket }; const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket };
const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config); const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
if (bindingSignature && helper.isValidDecryptionKeyPacket(bindingSignature, config)) { if (helper.isValidDecryptionKeyPacket(bindingSignature, config)) {
keys.push(this.subKeys[i]); keys.push(this.subKeys[i]);
} }
} catch (e) {} } catch (e) {}
@ -486,7 +505,7 @@ class Key {
* It is enough to validate any signing keys * It is enough to validate any signing keys
* since its binding signatures are also checked * since its binding signatures are also checked
*/ */
const signingKey = await this.getSigningKey(null, null, undefined, config); const signingKey = await this.getSigningKey(null, null, undefined, { ...config, rejectPublicKeyAlgorithms: new Set(), minRsaBits: 0 });
// This could again be a dummy key // This could again be a dummy key
if (signingKey && !signingKey.keyPacket.isDummy()) { if (signingKey && !signingKey.keyPacket.isDummy()) {
signingKeyPacket = signingKey.keyPacket; signingKeyPacket = signingKey.keyPacket;
@ -581,16 +600,16 @@ class Key {
let expiry = keyExpiry < sigExpiry ? keyExpiry : sigExpiry; let expiry = keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
if (capabilities === 'encrypt' || capabilities === 'encrypt_sign') { if (capabilities === 'encrypt' || capabilities === 'encrypt_sign') {
const encryptKey = const encryptKey =
await this.getEncryptionKey(keyId, expiry, userId, config).catch(() => {}) || await this.getEncryptionKey(keyId, expiry, userId, { ...config, rejectPublicKeyAlgorithms: new Set(), minRsaBits: 0 }).catch(() => {}) ||
await this.getEncryptionKey(keyId, null, userId, config).catch(() => {}); await this.getEncryptionKey(keyId, null, userId, { ...config, rejectPublicKeyAlgorithms: new Set(), minRsaBits: 0 }).catch(() => {});
if (!encryptKey) return null; if (!encryptKey) return null;
const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket, undefined, config); const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket, undefined, config);
if (encryptExpiry < expiry) expiry = encryptExpiry; if (encryptExpiry < expiry) expiry = encryptExpiry;
} }
if (capabilities === 'sign' || capabilities === 'encrypt_sign') { if (capabilities === 'sign' || capabilities === 'encrypt_sign') {
const signKey = const signKey =
await this.getSigningKey(keyId, expiry, userId, config).catch(() => {}) || await this.getSigningKey(keyId, expiry, userId, { ...config, rejectPublicKeyAlgorithms: new Set(), minRsaBits: 0 }).catch(() => {}) ||
await this.getSigningKey(keyId, null, userId, config).catch(() => {}); await this.getSigningKey(keyId, null, userId, { ...config, rejectPublicKeyAlgorithms: new Set(), minRsaBits: 0 }).catch(() => {});
if (!signKey) return null; if (!signKey) return null;
const signExpiry = await signKey.getExpirationTime(this.keyPacket, undefined, config); const signExpiry = await signKey.getExpirationTime(this.keyPacket, undefined, config);
if (signExpiry < expiry) expiry = signExpiry; if (signExpiry < expiry) expiry = signExpiry;

View File

@ -523,7 +523,9 @@ export class Message {
* @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time * @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @param {Boolean} [streaming] - Whether to process data as a stream * @param {Boolean} [streaming] - Whether to process data as a stream
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Array<({keyid: module:type/keyid~Keyid, valid: Boolean})>} List of signer's keyid and validity of signature. * @returns {Array<{keyid: module:type/keyid~Keyid,
* signature: Promise<Signature>,
* verified: Promise<Boolean>}>} List of signer's keyid and validity of signatures.
* @async * @async
*/ */
async verify(keys, date = new Date(), streaming, config = defaultConfig) { async verify(keys, date = new Date(), streaming, config = defaultConfig) {
@ -576,7 +578,9 @@ export class Message {
* @param {Signature} signature * @param {Signature} signature
* @param {Date} date - Verify the signature against the given date, i.e. check signature creation time < date < expiration time * @param {Date} date - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Array<({keyid: module:type/keyid~Keyid, valid: Boolean})>} List of signer's keyid and validity of signature. * @returns {Array<{keyid: module:type/keyid~Keyid,
* signature: Promise<Signature>,
* verified: Promise<Boolean>}>} List of signer's keyid and validity of signature.
* @async * @async
*/ */
verifyDetached(signature, keys, date = new Date(), streaming, config = defaultConfig) { verifyDetached(signature, keys, date = new Date(), streaming, config = defaultConfig) {
@ -733,28 +737,39 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
* i.e. check signature creation time < date < expiration time * i.e. check signature creation time < date < expiration time
* @param {Boolean} [detached] - Whether to verify detached signature packets * @param {Boolean} [detached] - Whether to verify detached signature packets
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<Array<{keyid: module:type/keyid~Keyid, * @returns {{keyid: module:type/keyid~Keyid,
* valid: Boolean|null}>>} list of signer's keyid and validity of signature * signature: Promise<Signature>,
* verified: Promise<Boolean>}} signer's keyid and validity of signature
* @async * @async
* @private * @private
*/ */
async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, streaming = false, config = defaultConfig) { async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, streaming = false, config = defaultConfig) {
let primaryKey = null; let primaryKey;
let signingKey = null; let signingKey;
await Promise.all(keys.map(async function(key) { let keyError;
// Look for the unique key that matches issuerKeyId of signature
try {
signingKey = await key.getSigningKey(signature.issuerKeyId, null, undefined, config);
primaryKey = key;
} catch (e) {}
}));
for (const key of keys) {
const issuerKeys = key.getKeys(signature.issuerKeyId);
if (issuerKeys.length > 0) {
primaryKey = key;
break;
}
}
if (!primaryKey) {
keyError = new Error(`Could not find signing key with key ID ${signature.issuerKeyId.toHex()}`);
} else {
try {
signingKey = await primaryKey.getSigningKey(signature.issuerKeyId, null, undefined, config);
} catch (e) {
keyError = e;
}
}
const signaturePacket = signature.correspondingSig || signature; const signaturePacket = signature.correspondingSig || signature;
const verifiedSig = { const verifiedSig = {
keyid: signature.issuerKeyId, keyid: signature.issuerKeyId,
verified: (async () => { verified: (async () => {
if (!signingKey) { if (keyError) {
return null; throw keyError;
} }
await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming, config); await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming, config);
const sig = await signaturePacket; const sig = await signaturePacket;
@ -796,8 +811,9 @@ async function createVerificationObject(signature, literalDataList, keys, date =
* i.e. check signature creation time < date < expiration time * i.e. check signature creation time < date < expiration time
* @param {Boolean} [detached] - Whether to verify detached signature packets * @param {Boolean} [detached] - Whether to verify detached signature packets
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<Array<{keyid: module:type/keyid~Keyid, * @returns {Array<{keyid: module:type/keyid~Keyid,
* valid: Boolean}>>} list of signer's keyid and validity of signature * signature: Promise<Signature>,
* verified: Promise<Boolean>}>} list of signer's keyid and validity of signatures
* @async * @async
* @private * @private
*/ */

View File

@ -234,7 +234,7 @@ class PublicKeyPacket {
// RSA, DSA or ElGamal public modulo // RSA, DSA or ElGamal public modulo
const modulo = this.publicParams.n || this.publicParams.p; const modulo = this.publicParams.n || this.publicParams.p;
if (modulo) { if (modulo) {
result.bits = modulo.length * 8; result.bits = util.uint8ArrayBitLength(modulo);
} else { } else {
result.curve = this.publicParams.oid.getName(); result.curve = this.publicParams.oid.getName();
} }

View File

@ -652,7 +652,7 @@ class SignaturePacket {
/** /**
* verifies the signature packet. Note: not all signature types are implemented * verifies the signature packet. Note: not all signature types are implemented
* @param {PublicSubkeyPacket|PublicKeyPacket| * @param {PublicSubkeyPacket|PublicKeyPacket|
* SecretSubkeyPacket|SecretKeyPacket} key the public key to verify the signature * SecretSubkeyPacket|SecretKeyPacket} key - the public key to verify the signature
* @param {module:enums.signature} signatureType - Expected signature type * @param {module:enums.signature} signatureType - Expected signature type
* @param {String|Object} data - Data which on the signature applies * @param {String|Object} data - Data which on the signature applies
* @param {Boolean} [detached] - Whether to verify a detached signature * @param {Boolean} [detached] - Whether to verify a detached signature

View File

@ -192,15 +192,28 @@ const util = {
* @returns {Uint8Array} MPI-formatted Uint8Array. * @returns {Uint8Array} MPI-formatted Uint8Array.
*/ */
uint8ArrayToMpi: function (bin) { uint8ArrayToMpi: function (bin) {
const bitSize = util.uint8ArrayBitLength(bin);
if (bitSize === 0) {
throw new Error('Zero MPI');
}
const stripped = bin.subarray(bin.length - Math.ceil(bitSize / 8));
const prefix = Uint8Array.from([(bitSize & 0xFF00) >> 8, bitSize & 0xFF]);
return util.concatUint8Array([prefix, stripped]);
},
/**
* Return bit length of the input data
* @param {Uint8Array} bin input data (big endian)
* @returns bit length
*/
uint8ArrayBitLength: function (bin) {
let i; // index of leading non-zero byte let i; // index of leading non-zero byte
for (i = 0; i < bin.length; i++) if (bin[i] !== 0) break; for (i = 0; i < bin.length; i++) if (bin[i] !== 0) break;
if (i === bin.length) { if (i === bin.length) {
throw new Error('Zero MPI'); return 0;
} }
const stripped = bin.subarray(i); const stripped = bin.subarray(i);
const size = (stripped.length - 1) * 8 + util.nbits(stripped[0]); return (stripped.length - 1) * 8 + util.nbits(stripped[0]);
const prefix = Uint8Array.from([(size & 0xFF00) >> 8, size & 0xFF]);
return util.concatUint8Array([prefix, stripped]);
}, },
/** /**

View File

@ -62,7 +62,8 @@ module.exports = () => describe('Custom configuration', function() {
const config = { const config = {
showComment: true, showComment: true,
preferredCompressionAlgorithm: openpgp.enums.compression.zip, preferredCompressionAlgorithm: openpgp.enums.compression.zip,
preferredHashAlgorithm: openpgp.enums.hash.sha512 preferredHashAlgorithm: openpgp.enums.hash.sha512,
rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsa]) // should not matter in this context
}; };
const opt2 = { privateKey: origKey, userIds, config }; const opt2 = { privateKey: origKey, userIds, config };
const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2); const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2);
@ -171,12 +172,54 @@ module.exports = () => describe('Custom configuration', function() {
const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config); const { packets: [compressed] } = await encrypted2.decrypt(null, passwords, null, encrypted2.fromStream, openpgp.config);
expect(compressed.tag).to.equal(openpgp.enums.packet.compressedData); expect(compressed.tag).to.equal(openpgp.enums.packet.compressedData);
expect(compressed.algorithm).to.equal("zip"); expect(compressed.algorithm).to.equal("zip");
const userIds = { name: 'Test User', email: 'text2@example.com' };
const { key } = await openpgp.generateKey({ userIds });
await expect(openpgp.encrypt({
message, publicKeys: [key], config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.ecdh]) }
})).to.be.eventually.rejectedWith(/ecdh keys are considered too weak/);
} finally { } finally {
openpgp.config.aeadProtect = aeadProtectVal; openpgp.config.aeadProtect = aeadProtectVal;
openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal; openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal;
} }
}); });
it('openpgp.decrypt', async function() {
const plaintext = 'test';
const message = openpgp.Message.fromText(plaintext);
const userIds = { name: 'Test User', email: 'text2@example.com' };
const { key } = await openpgp.generateKey({ userIds, type: 'rsa', rsaBits: 2048 });
const armoredMessage = await openpgp.encrypt({ message, publicKeys:[key], privateKeys: [key] });
const { data, signatures } = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage }),
privateKeys: [key],
publicKeys: [key]
});
expect(data).to.equal(plaintext);
expect(signatures[0].valid).to.be.true;
const { data: data2, signatures: signatures2 } = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage }),
privateKeys: [key],
publicKeys: [key],
config: { minRsaBits: 4096 }
});
expect(data2).to.equal(plaintext);
expect(signatures2[0].valid).to.be.false;
expect(signatures2[0].error).to.match(/keys shorter than 4096 bits are considered too weak/);
const { data: data3, signatures: signatures3 } = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage }),
privateKeys: [key],
publicKeys: [key],
config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.rsaEncryptSign]) }
});
expect(data3).to.equal(plaintext);
expect(signatures3[0].valid).to.be.false;
expect(signatures3[0].error).to.match(/rsaEncryptSign keys are considered too weak/);
});
it('openpgp.sign', async function() { it('openpgp.sign', async function() {
const userIds = { name: 'Test User', email: 'text2@example.com' }; const userIds = { name: 'Test User', email: 'text2@example.com' };
const { privateKeyArmored } = await openpgp.generateKey({ userIds }); const { privateKeyArmored } = await openpgp.generateKey({ userIds });
@ -199,6 +242,10 @@ module.exports = () => describe('Custom configuration', function() {
config: { rejectHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) } config: { rejectHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }
}; };
await expect(openpgp.sign(opt2)).to.be.rejectedWith(/Insecure hash algorithm/); await expect(openpgp.sign(opt2)).to.be.rejectedWith(/Insecure hash algorithm/);
await expect(openpgp.sign({
message, privateKeys: [key], config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsa]) }
})).to.be.eventually.rejectedWith(/eddsa keys are considered too weak/);
}); });
it('openpgp.verify', async function() { it('openpgp.verify', async function() {
@ -237,6 +284,14 @@ module.exports = () => describe('Custom configuration', function() {
const { signatures: [sig3] } = await openpgp.verify(opt3); const { signatures: [sig3] } = await openpgp.verify(opt3);
await expect(sig3.error).to.match(/Insecure message hash algorithm/); await expect(sig3.error).to.match(/Insecure message hash algorithm/);
const opt4 = {
message: await openpgp.readMessage({ armoredMessage: signed }),
publicKeys: [key],
config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsa]) }
};
const { signatures: [sig4] } = await openpgp.verify(opt4);
await expect(sig4.valid).to.be.false;
await expect(sig4.error).to.match(/eddsa keys are considered too weak/);
}); });
}); });

View File

@ -2421,15 +2421,22 @@ function versionSpecificTests() {
let publicKey = await openpgp.readKey({ armoredKey: pub_sig_test }); let publicKey = await openpgp.readKey({ armoredKey: pub_sig_test });
const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa });
await privateKey.decrypt('hello world'); await privateKey.decrypt('hello world');
publicKey = await publicKey.signPrimaryUser([privateKey]);
const signatures = await publicKey.verifyPrimaryUser([privateKey]); const { minRsaBits } = openpgp.config;
const publicSigningKey = await publicKey.getSigningKey(); openpgp.config.minRsaBits = 1024;
const privateSigningKey = await privateKey.getSigningKey(); try {
expect(signatures.length).to.equal(2); publicKey = await publicKey.signPrimaryUser([privateKey]);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); const signatures = await publicKey.verifyPrimaryUser([privateKey]);
expect(signatures[0].valid).to.be.null; const publicSigningKey = await publicKey.getSigningKey();
expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex()); const privateSigningKey = await privateKey.getSigningKey();
expect(signatures[1].valid).to.be.true; expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
} finally {
openpgp.config.minRsaBits = minRsaBits;
}
}); });
it('Sign key and verify with wrong key - primary user', async function() { it('Sign key and verify with wrong key - primary user', async function() {
@ -2437,38 +2444,52 @@ function versionSpecificTests() {
const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa });
const wrongKey = await openpgp.readKey({ armoredKey: wrong_key }); const wrongKey = await openpgp.readKey({ armoredKey: wrong_key });
await privateKey.decrypt('hello world'); await privateKey.decrypt('hello world');
publicKey = await publicKey.signPrimaryUser([privateKey]);
const signatures = await publicKey.verifyPrimaryUser([wrongKey]); const { minRsaBits } = openpgp.config;
const publicSigningKey = await publicKey.getSigningKey(); openpgp.config.minRsaBits = 1024;
const privateSigningKey = await privateKey.getSigningKey(); try {
expect(signatures.length).to.equal(2); publicKey = await publicKey.signPrimaryUser([privateKey]);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); const signatures = await publicKey.verifyPrimaryUser([wrongKey]);
expect(signatures[0].valid).to.be.null; const publicSigningKey = await publicKey.getSigningKey();
expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex()); const privateSigningKey = await privateKey.getSigningKey();
expect(signatures[1].valid).to.be.null; expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.null;
} finally {
openpgp.config.minRsaBits = minRsaBits;
}
}); });
it('Sign and verify key - all users', async function() { it('Sign and verify key - all users', async function() {
let publicKey = await openpgp.readKey({ armoredKey: multi_uid_key }); let publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa });
await privateKey.decrypt('hello world'); await privateKey.decrypt('hello world');
publicKey = await publicKey.signAllUsers([privateKey]);
const signatures = await publicKey.verifyAllUsers([privateKey]); const { minRsaBits } = openpgp.config;
const publicSigningKey = await publicKey.getSigningKey(); openpgp.config.minRsaBits = 1024;
const privateSigningKey = await privateKey.getSigningKey(); try {
expect(signatures.length).to.equal(4); publicKey = await publicKey.signAllUsers([privateKey]);
expect(signatures[0].userid).to.equal(publicKey.users[0].userId.userid); const signatures = await publicKey.verifyAllUsers([privateKey]);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); const publicSigningKey = await publicKey.getSigningKey();
expect(signatures[0].valid).to.be.null; const privateSigningKey = await privateKey.getSigningKey();
expect(signatures[1].userid).to.equal(publicKey.users[0].userId.userid); expect(signatures.length).to.equal(4);
expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex()); expect(signatures[0].userid).to.equal(publicKey.users[0].userId.userid);
expect(signatures[1].valid).to.be.true; expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[2].userid).to.equal(publicKey.users[1].userId.userid); expect(signatures[0].valid).to.be.null;
expect(signatures[2].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); expect(signatures[1].userid).to.equal(publicKey.users[0].userId.userid);
expect(signatures[2].valid).to.be.null; expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex());
expect(signatures[3].userid).to.equal(publicKey.users[1].userId.userid); expect(signatures[1].valid).to.be.true;
expect(signatures[3].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex()); expect(signatures[2].userid).to.equal(publicKey.users[1].userId.userid);
expect(signatures[3].valid).to.be.true; expect(signatures[2].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[2].valid).to.be.null;
expect(signatures[3].userid).to.equal(publicKey.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex());
expect(signatures[3].valid).to.be.true;
} finally {
openpgp.config.minRsaBits = minRsaBits;
}
}); });
it('Sign key and verify with wrong key - all users', async function() { it('Sign key and verify with wrong key - all users', async function() {
@ -2476,23 +2497,30 @@ function versionSpecificTests() {
const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa }); const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa });
const wrongKey = await openpgp.readKey({ armoredKey: wrong_key }); const wrongKey = await openpgp.readKey({ armoredKey: wrong_key });
await privateKey.decrypt('hello world'); await privateKey.decrypt('hello world');
publicKey = await publicKey.signAllUsers([privateKey]);
const signatures = await publicKey.verifyAllUsers([wrongKey]); const { minRsaBits } = openpgp.config;
const publicSigningKey = await publicKey.getSigningKey(); openpgp.config.minRsaBits = 1024;
const privateSigningKey = await privateKey.getSigningKey(); try {
expect(signatures.length).to.equal(4); publicKey = await publicKey.signAllUsers([privateKey]);
expect(signatures[0].userid).to.equal(publicKey.users[0].userId.userid); const signatures = await publicKey.verifyAllUsers([wrongKey]);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); const publicSigningKey = await publicKey.getSigningKey();
expect(signatures[0].valid).to.be.null; const privateSigningKey = await privateKey.getSigningKey();
expect(signatures[1].userid).to.equal(publicKey.users[0].userId.userid); expect(signatures.length).to.equal(4);
expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex()); expect(signatures[0].userid).to.equal(publicKey.users[0].userId.userid);
expect(signatures[1].valid).to.be.null; expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[2].userid).to.equal(publicKey.users[1].userId.userid); expect(signatures[0].valid).to.be.null;
expect(signatures[2].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); expect(signatures[1].userid).to.equal(publicKey.users[0].userId.userid);
expect(signatures[2].valid).to.be.null; expect(signatures[1].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex());
expect(signatures[3].userid).to.equal(publicKey.users[1].userId.userid); expect(signatures[1].valid).to.be.null;
expect(signatures[3].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex()); expect(signatures[2].userid).to.equal(publicKey.users[1].userId.userid);
expect(signatures[3].valid).to.be.null; expect(signatures[2].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[2].valid).to.be.null;
expect(signatures[3].userid).to.equal(publicKey.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateSigningKey.getKeyId().toHex());
expect(signatures[3].valid).to.be.null;
} finally {
openpgp.config.minRsaBits = minRsaBits;
}
}); });
it('Reformat key without passphrase', function() { it('Reformat key without passphrase', function() {
@ -2782,29 +2810,36 @@ module.exports = () => describe('Key', function() {
}); });
it('Verify status of key with non-self revocation signature', async function() { it('Verify status of key with non-self revocation signature', async function() {
const pubKey = await openpgp.readKey({ armoredKey: key_with_revoked_third_party_cert }); const { rejectPublicKeyAlgorithms } = openpgp.config;
const [selfCertification] = await pubKey.verifyPrimaryUser(); openpgp.config.rejectPublicKeyAlgorithms = new Set();
const publicSigningKey = await pubKey.getSigningKey();
expect(selfCertification.keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(selfCertification.valid).to.be.true;
const certifyingKey = await openpgp.readKey({ armoredKey: certifying_key }); try {
const certifyingSigningKey = await certifyingKey.getSigningKey(); const pubKey = await openpgp.readKey({ armoredKey: key_with_revoked_third_party_cert });
const signatures = await pubKey.verifyPrimaryUser([certifyingKey]); const [selfCertification] = await pubKey.verifyPrimaryUser();
expect(signatures.length).to.equal(2); const publicSigningKey = await pubKey.getSigningKey();
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex()); expect(selfCertification.keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[0].valid).to.be.null; expect(selfCertification.valid).to.be.true;
expect(signatures[1].keyid.toHex()).to.equal(certifyingSigningKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.false;
const { user } = await pubKey.getPrimaryUser(); const certifyingKey = await openpgp.readKey({ armoredKey: certifying_key });
await expect(user.verifyCertificate(pubKey.primaryKey, user.otherCertifications[0], [certifyingKey])).to.be.rejectedWith('User certificate is revoked'); const certifyingSigningKey = await certifyingKey.getSigningKey();
const signatures = await pubKey.verifyPrimaryUser([certifyingKey]);
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(publicSigningKey.getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(certifyingSigningKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.false;
const { user } = await pubKey.getPrimaryUser();
await expect(user.verifyCertificate(pubKey.primaryKey, user.otherCertifications[0], [certifyingKey], undefined, openpgp.config)).to.be.rejectedWith('User certificate is revoked');
} finally {
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
}
}); });
it('Verify certificate of key with future creation date', async function() { it('Verify certificate of key with future creation date', async function() {
const pubKey = await openpgp.readKey({ armoredKey: key_created_2030 }); const pubKey = await openpgp.readKey({ armoredKey: key_created_2030 });
const user = pubKey.users[0]; const user = pubKey.users[0];
await user.verifyCertificate(pubKey.primaryKey, user.selfCertifications[0], [pubKey], pubKey.primaryKey.created); await user.verifyCertificate(pubKey.primaryKey, user.selfCertifications[0], [pubKey], pubKey.primaryKey.created, openpgp.config);
const verifyAllResult = await user.verifyAllCertifications(pubKey.primaryKey, [pubKey], pubKey.primaryKey.created); const verifyAllResult = await user.verifyAllCertifications(pubKey.primaryKey, [pubKey], pubKey.primaryKey.created);
expect(verifyAllResult[0].valid).to.be.true; expect(verifyAllResult[0].valid).to.be.true;
await user.verify(pubKey.primaryKey, pubKey.primaryKey.created); await user.verify(pubKey.primaryKey, pubKey.primaryKey.created);
@ -2976,7 +3011,7 @@ module.exports = () => describe('Key', function() {
expect(key.primaryKey.isDummy()).to.be.false; expect(key.primaryKey.isDummy()).to.be.false;
key.primaryKey.makeDummy(); key.primaryKey.makeDummy();
expect(key.primaryKey.isDummy()).to.be.true; expect(key.primaryKey.isDummy()).to.be.true;
await expect(openpgp.sign({ message: openpgp.Message.fromText('test'), privateKeys: [key] })).to.be.fulfilled; await expect(openpgp.sign({ message: openpgp.Message.fromText('test'), privateKeys: [key], config: { minRsaBits: 1024 } })).to.be.fulfilled;
}); });
it('makeDummy() - should work for encrypted keys', async function() { it('makeDummy() - should work for encrypted keys', async function() {
@ -3381,8 +3416,13 @@ VYGdb3eNlV8CfoEC
publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128]; publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
const sessionKey = await openpgp.generateSessionKey({ publicKeys: publicKey, toUserIds: { name: 'Test User', email: 'b@c.com' } }); const sessionKey = await openpgp.generateSessionKey({ publicKeys: publicKey, toUserIds: { name: 'Test User', email: 'b@c.com' } });
expect(sessionKey.algorithm).to.equal('aes128'); expect(sessionKey.algorithm).to.equal('aes128');
await openpgp.encrypt({ message: openpgp.Message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserIds: { name: 'Test User', email: 'b@c.com' }, armor: false }); const config = { minRsaBits: 1024 };
await expect(openpgp.encrypt({ message: openpgp.Message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserIds: { name: 'Test User', email: 'c@c.com' }, armor: false })).to.be.rejectedWith('Could not find user that matches that user ID'); await openpgp.encrypt({
message: openpgp.Message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserIds: { name: 'Test User', email: 'b@c.com' }, armor: false, config
});
await expect(openpgp.encrypt({
message: openpgp.Message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, toUserIds: { name: 'Test User', email: 'c@c.com' }, armor: false, config
})).to.be.rejectedWith('Could not find user that matches that user ID');
}); });
it('Fails to encrypt to User ID-less key', async function() { it('Fails to encrypt to User ID-less key', async function() {
@ -3406,18 +3446,25 @@ VYGdb3eNlV8CfoEC
privateKey.users[0].userId = openpgp.UserIDPacket.fromObject({ name: 'Test User', email: 'b@c.com' }); privateKey.users[0].userId = openpgp.UserIDPacket.fromObject({ name: 'Test User', email: 'b@c.com' });
// Set second user to prefer aes128. We will select this user. // Set second user to prefer aes128. We will select this user.
privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512]; privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512];
const signed = await openpgp.sign({ message: openpgp.Message.fromText('hello'), privateKeys: privateKey, fromUserIds: { name: 'Test McTestington', email: 'test@example.com' }, armor: false }); const config = { minRsaBits: 1024 };
const signed = await openpgp.sign({
message: openpgp.Message.fromText('hello'), privateKeys: privateKey, fromUserIds: { name: 'Test McTestington', email: 'test@example.com' }, armor: false, config
});
const signature = await openpgp.readMessage({ binaryMessage: signed }); const signature = await openpgp.readMessage({ binaryMessage: signed });
expect(signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); expect(signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
const encrypted = await openpgp.encrypt({ message: openpgp.Message.fromText('hello'), passwords: 'test', privateKeys: privateKey, fromUserIds: { name: 'Test McTestington', email: 'test@example.com' }, armor: false }); const encrypted = await openpgp.encrypt({
message: openpgp.Message.fromText('hello'), passwords: 'test', privateKeys: privateKey, fromUserIds: { name: 'Test McTestington', email: 'test@example.com' }, armor: false, config
});
const { signatures } = await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), passwords: 'test' }); const { signatures } = await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), passwords: 'test' });
expect(signatures[0].signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512); expect(signatures[0].signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
await expect(openpgp.encrypt({ message: openpgp.Message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, fromUserIds: { name: 'Not Test McTestington', email: 'test@example.com' }, armor: false })).to.be.rejectedWith('Could not find user that matches that user ID'); await expect(openpgp.encrypt({
message: openpgp.Message.fromText('hello'), publicKeys: publicKey, privateKeys: privateKey, fromUserIds: { name: 'Not Test McTestington', email: 'test@example.com' }, armor: false, config
})).to.be.rejectedWith('Could not find user that matches that user ID');
}); });
it('Find a valid subkey binding signature among many invalid ones', async function() { it('Find a valid subkey binding signature among many invalid ones', async function() {
const key = await openpgp.readKey({ armoredKey: valid_binding_sig_among_many_expired_sigs_pub }); const key = await openpgp.readKey({ armoredKey: valid_binding_sig_among_many_expired_sigs_pub });
expect(await key.getEncryptionKey()).to.not.be.null; expect(await key.getEncryptionKey(undefined, undefined, undefined, { ...openpgp.config, minRsaBits: 1024 })).to.not.be.null;
}); });
it('Selects the most recent subkey binding signature', async function() { it('Selects the most recent subkey binding signature', async function() {

View File

@ -821,11 +821,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
let privateKey; let privateKey;
let publicKey; let publicKey;
let publicKeyNoAEAD; let publicKeyNoAEAD;
let privateKeyMismatchingParams;
let aeadProtectVal; let aeadProtectVal;
let preferredAeadAlgorithmVal; let preferredAeadAlgorithmVal;
let aeadChunkSizeByteVal; let aeadChunkSizeByteVal;
let v5KeysVal; let v5KeysVal;
let privateKeyMismatchingParams; let minRsaBitsVal;
beforeEach(async function() { beforeEach(async function() {
publicKey = await openpgp.readKey({ armoredKey: pub_key }); publicKey = await openpgp.readKey({ armoredKey: pub_key });
@ -843,6 +845,9 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
preferredAeadAlgorithmVal = openpgp.config.preferredAeadAlgorithm; preferredAeadAlgorithmVal = openpgp.config.preferredAeadAlgorithm;
aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte; aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
v5KeysVal = openpgp.config.v5Keys; v5KeysVal = openpgp.config.v5Keys;
minRsaBitsVal = openpgp.config.minRsaBits;
openpgp.config.minRsaBits = 512;
}); });
afterEach(function() { afterEach(function() {
@ -850,6 +855,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
openpgp.config.preferredAeadAlgorithm = preferredAeadAlgorithmVal; openpgp.config.preferredAeadAlgorithm = preferredAeadAlgorithmVal;
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal; openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
openpgp.config.v5Keys = v5KeysVal; openpgp.config.v5Keys = v5KeysVal;
openpgp.config.minRsaBits = minRsaBitsVal;
}); });
it('Configuration', async function() { it('Configuration', async function() {
@ -1547,48 +1553,55 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
}); });
it('should encrypt and decrypt/verify with detached signature as input for encryption', async function () { it('should encrypt and decrypt/verify with detached signature as input for encryption', async function () {
const plaintext = " \t┍ͤ޵၂༫዇◧˘˻ᙑ᎚⏴ំந⛑nٓኵΉⅶ⋋ŵ⋲΂ͽᣏ₅ᄶɼ┋⌔û᬴Ƚᔡᧅ≃ṱἆ⃷݂૿ӌ᰹෇ٹჵ⛇໶⛌ \t\n한국어/조선말"; const { rejectPublicKeyAlgorithms } = openpgp.config;
try {
openpgp.config.rejectPublicKeyAlgorithms = new Set();
const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de }); const plaintext = " \t┍ͤ޵၂༫዇◧˘˻ᙑ᎚⏴ំந⛑nٓኵΉⅶ⋋ŵ⋲΂ͽᣏ₅ᄶɼ┋⌔û᬴Ƚᔡᧅ≃ṱἆ⃷݂૿ӌ᰹෇ٹჵ⛇໶⛌ \t\n한국어/조선말";
await privKeyDE.decrypt(passphrase);
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de }); const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de });
await privKeyDE.decrypt(passphrase);
const signOpt = { const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
message: openpgp.Message.fromText(plaintext),
privateKeys: privKeyDE,
detached: true
};
const encOpt = { const signOpt = {
message: openpgp.Message.fromText(plaintext), message: openpgp.Message.fromText(plaintext),
publicKeys: publicKey, privateKeys: privKeyDE,
privateKeys: privateKey detached: true
}; };
const decOpt = { const encOpt = {
privateKeys: privateKey, message: openpgp.Message.fromText(plaintext),
publicKeys: [publicKey, pubKeyDE] publicKeys: publicKey,
}; privateKeys: privateKey
};
return openpgp.sign(signOpt).then(async function (armoredSignature) { const decOpt = {
encOpt.signature = await openpgp.readSignature({ armoredSignature }); privateKeys: privateKey,
return openpgp.encrypt(encOpt); publicKeys: [publicKey, pubKeyDE]
}).then(async function (armoredMessage) { };
decOpt.message = await openpgp.readMessage({ armoredMessage });
return openpgp.decrypt(decOpt); await openpgp.sign(signOpt).then(async function (armoredSignature) {
}).then(async function (decrypted) { encOpt.signature = await openpgp.readSignature({ armoredSignature });
let signingKey; return openpgp.encrypt(encOpt);
expect(decrypted.data).to.equal(plaintext); }).then(async function (armoredMessage) {
expect(decrypted.signatures[0].valid).to.be.true; decOpt.message = await openpgp.readMessage({ armoredMessage });
signingKey = await privateKey.getSigningKey(); return openpgp.decrypt(decOpt);
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); }).then(async function (decrypted) {
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); let signingKey;
expect(decrypted.signatures[1].valid).to.be.true; expect(decrypted.data).to.equal(plaintext);
signingKey = await privKeyDE.getSigningKey(); expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[1].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[1].signature.packets.length).to.equal(1); expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
}); expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
expect(decrypted.signatures[1].valid).to.be.true;
signingKey = await privKeyDE.getSigningKey();
expect(decrypted.signatures[1].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[1].signature.packets.length).to.equal(1);
});
} finally {
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
}
}); });
it('should fail to encrypt and decrypt/verify with detached signature as input for encryption with wrong public key', async function () { it('should fail to encrypt and decrypt/verify with detached signature as input for encryption with wrong public key', async function () {
@ -1614,12 +1627,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
}).then(async function (armoredMessage) { }).then(async function (armoredMessage) {
decOpt.message = await openpgp.readMessage({ armoredMessage }); decOpt.message = await openpgp.readMessage({ armoredMessage });
return openpgp.decrypt(decOpt); return openpgp.decrypt(decOpt);
}).then(async function (decrypted) { }).then(async function ({ signatures, data }) {
expect(decrypted.data).to.equal(plaintext); expect(data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1636,12 +1650,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
return openpgp.encrypt(encOpt).then(async function (encrypted) { return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted }); decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
return openpgp.decrypt(decOpt); return openpgp.decrypt(decOpt);
}).then(async function (decrypted) { }).then(async function ({ signatures, data }) {
expect(decrypted.data).to.equal(plaintext); expect(data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1658,12 +1673,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
return openpgp.encrypt(encOpt).then(async function (encrypted) { return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted }); decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
return openpgp.decrypt(decOpt); return openpgp.decrypt(decOpt);
}).then(async function (decrypted) { }).then(async function ({ signatures, data }) {
expect(decrypted.data).to.equal(''); expect(data).to.equal('');
expect(decrypted.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1679,12 +1695,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
return openpgp.encrypt(encOpt).then(async function (encrypted) { return openpgp.encrypt(encOpt).then(async function (encrypted) {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted }); decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
return openpgp.decrypt(decOpt); return openpgp.decrypt(decOpt);
}).then(async function (decrypted) { }).then(async function ({ signatures, data }) {
expect(decrypted.data).to.equal(plaintext); expect(data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1698,51 +1715,59 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
privateKeys: privateKey, privateKeys: privateKey,
detached: true detached: true
}); });
const decrypted = await openpgp.decrypt({ const { signatures, data } = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage: encrypted }), message: await openpgp.readMessage({ armoredMessage: encrypted }),
signature: await openpgp.readSignature({ armoredSignature: signed }), signature: await openpgp.readSignature({ armoredSignature: signed }),
privateKeys: privateKey, privateKeys: privateKey,
publicKeys: await openpgp.readKey({ armoredKey: wrong_pubkey }) publicKeys: await openpgp.readKey({ armoredKey: wrong_pubkey })
}); });
expect(decrypted.data).to.equal(plaintext); expect(data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
it('should encrypt and decrypt/verify both signatures when signed with two private keys', async function () { it('should encrypt and decrypt/verify both signatures when signed with two private keys', async function () {
const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de }); const { rejectPublicKeyAlgorithms } = openpgp.config;
await privKeyDE.decrypt(passphrase); try {
openpgp.config.rejectPublicKeyAlgorithms = new Set();
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de }); const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de });
await privKeyDE.decrypt(passphrase);
const encOpt = { const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
message: openpgp.Message.fromText(plaintext),
publicKeys: publicKey,
privateKeys: [privateKey, privKeyDE]
};
const decOpt = { const encOpt = {
privateKeys: privateKey, message: openpgp.Message.fromText(plaintext),
publicKeys: [publicKey, pubKeyDE] publicKeys: publicKey,
}; privateKeys: [privateKey, privKeyDE]
};
return openpgp.encrypt(encOpt).then(async function (encrypted) { const decOpt = {
decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted }); privateKeys: privateKey,
return openpgp.decrypt(decOpt); publicKeys: [publicKey, pubKeyDE]
}).then(async function (decrypted) { };
let signingKey;
expect(decrypted.data).to.equal(plaintext); await openpgp.encrypt(encOpt).then(async function (encrypted) {
expect(decrypted.signatures[0].valid).to.be.true; decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted });
signingKey = await privateKey.getSigningKey(); return openpgp.decrypt(decOpt);
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); }).then(async function (decrypted) {
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); let signingKey;
expect(decrypted.signatures[1].valid).to.be.true; expect(decrypted.data).to.equal(plaintext);
signingKey = await privKeyDE.getSigningKey(); expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[1].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); signingKey = await privateKey.getSigningKey();
expect(decrypted.signatures[1].signature.packets.length).to.equal(1); expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
}); expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
expect(decrypted.signatures[1].valid).to.be.true;
signingKey = await privKeyDE.getSigningKey();
expect(decrypted.signatures[1].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[1].signature.packets.length).to.equal(1);
});
} finally {
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
}
}); });
it('should fail to decrypt modified message', async function() { it('should fail to decrypt modified message', async function() {
@ -1812,28 +1837,35 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
describe('ELG / DSA encrypt, decrypt, sign, verify', function() { describe('ELG / DSA encrypt, decrypt, sign, verify', function() {
it('round trip test', async function () { it('round trip test', async function () {
const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de }); const { rejectPublicKeyAlgorithms } = openpgp.config;
const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de }); try {
await privKeyDE.decrypt(passphrase); openpgp.config.rejectPublicKeyAlgorithms = new Set();
pubKeyDE.users[0].selfCertifications[0].features = [7]; // Monkey-patch AEAD feature flag
return openpgp.encrypt({ const pubKeyDE = await openpgp.readKey({ armoredKey: pub_key_de });
publicKeys: pubKeyDE, const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de });
privateKeys: privKeyDE, await privKeyDE.decrypt(passphrase);
message: openpgp.Message.fromText(plaintext) pubKeyDE.users[0].selfCertifications[0].features = [7]; // Monkey-patch AEAD feature flag
}).then(async function (encrypted) { await openpgp.encrypt({
return openpgp.decrypt({
privateKeys: privKeyDE,
publicKeys: pubKeyDE, publicKeys: pubKeyDE,
message: await openpgp.readMessage({ armoredMessage: encrypted }) privateKeys: privKeyDE,
message: openpgp.Message.fromText(plaintext)
}).then(async function (encrypted) {
return openpgp.decrypt({
privateKeys: privKeyDE,
publicKeys: pubKeyDE,
message: await openpgp.readMessage({ armoredMessage: encrypted })
});
}).then(async function (decrypted) {
expect(decrypted.data).to.exist;
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.true;
const signingKey = await privKeyDE.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
}); });
}).then(async function (decrypted) { } finally {
expect(decrypted.data).to.exist; openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
expect(decrypted.data).to.equal(plaintext); }
expect(decrypted.signatures[0].valid).to.be.true;
const signingKey = await privKeyDE.getSigningKey();
expect(decrypted.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
}); });
}); });
@ -2078,33 +2110,40 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
}); });
it('should sign and verify cleartext message with multiple private keys', async function () { it('should sign and verify cleartext message with multiple private keys', async function () {
const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de }); const { rejectPublicKeyAlgorithms } = openpgp.config;
await privKeyDE.decrypt(passphrase); try {
openpgp.config.rejectPublicKeyAlgorithms = new Set();
const message = openpgp.CleartextMessage.fromText(plaintext); const privKeyDE = await openpgp.readKey({ armoredKey: priv_key_de });
const signOpt = { await privKeyDE.decrypt(passphrase);
message,
privateKeys: [privateKey, privKeyDE] const message = openpgp.CleartextMessage.fromText(plaintext);
}; const signOpt = {
const verifyOpt = { message,
publicKeys: [publicKey, privKeyDE.toPublic()] privateKeys: [privateKey, privKeyDE]
}; };
return openpgp.sign(signOpt).then(async function (signed) { const verifyOpt = {
expect(signed).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/); publicKeys: [publicKey, privKeyDE.toPublic()]
verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed }); };
return openpgp.verify(verifyOpt); await openpgp.sign(signOpt).then(async function (signed) {
}).then(async function (verified) { expect(signed).to.match(/-----BEGIN PGP SIGNED MESSAGE-----/);
let signingKey; verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
expect(verified.data).to.equal(plaintext.replace(/[ \t]+$/mg, '')); return openpgp.verify(verifyOpt);
expect(verified.signatures[0].valid).to.be.true; }).then(async function (verified) {
signingKey = await privateKey.getSigningKey(); let signingKey;
expect(verified.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(verified.data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
expect(verified.signatures[0].signature.packets.length).to.equal(1); expect(verified.signatures[0].valid).to.be.true;
expect(verified.signatures[1].valid).to.be.true; signingKey = await privateKey.getSigningKey();
signingKey = await privKeyDE.getSigningKey(); expect(verified.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(verified.signatures[1].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(verified.signatures[0].signature.packets.length).to.equal(1);
expect(verified.signatures[1].signature.packets.length).to.equal(1); expect(verified.signatures[1].valid).to.be.true;
}); signingKey = await privKeyDE.getSigningKey();
expect(verified.signatures[1].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(verified.signatures[1].signature.packets.length).to.equal(1);
});
} finally {
openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
}
}); });
it('should sign and verify data with detached signatures', function () { it('should sign and verify data with detached signatures', function () {
@ -2142,12 +2181,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
return openpgp.sign(signOpt).then(async function (signed) { return openpgp.sign(signOpt).then(async function (signed) {
verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed }); verifyOpt.message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
return openpgp.verify(verifyOpt); return openpgp.verify(verifyOpt);
}).then(async function (verified) { }).then(async function ({ data, signatures }) {
expect(verified.data).to.equal(plaintext.replace(/[ \t]+$/mg, '')); expect(data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
expect(verified.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(verified.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(verified.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -2165,12 +2205,13 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
return openpgp.sign(signOpt).then(async function (armoredSignature) { return openpgp.sign(signOpt).then(async function (armoredSignature) {
verifyOpt.signature = await openpgp.readSignature({ armoredSignature }); verifyOpt.signature = await openpgp.readSignature({ armoredSignature });
return openpgp.verify(verifyOpt); return openpgp.verify(verifyOpt);
}).then(async function (verified) { }).then(async function ({ data, signatures }) {
expect(verified.data).to.equal(plaintext); expect(data).to.equal(plaintext);
expect(verified.signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.false;
expect(signatures[0].error).to.match(/Could not find signing key/);
const signingKey = await privateKey.getSigningKey(); const signingKey = await privateKey.getSigningKey();
expect(verified.signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signingKey.getKeyId().toHex());
expect(verified.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -2500,7 +2541,8 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
pubKeyDE.subKeys[0] = revSubKey; pubKeyDE.subKeys[0] = revSubKey;
return openpgp.encrypt({ return openpgp.encrypt({
message: openpgp.Message.fromText(plaintext), message: openpgp.Message.fromText(plaintext),
publicKeys: pubKeyDE publicKeys: pubKeyDE,
config: { rejectPublicKeyAlgorithms: new Set() }
}).then(function() { }).then(function() {
throw new Error('Should not encrypt with revoked subkey'); throw new Error('Should not encrypt with revoked subkey');
}).catch(function(error) { }).catch(function(error) {
@ -2515,12 +2557,14 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
await privKeyDE.decrypt(passphrase); await privKeyDE.decrypt(passphrase);
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: openpgp.Message.fromText(plaintext), message: openpgp.Message.fromText(plaintext),
publicKeys: pubKeyDE publicKeys: pubKeyDE,
config: { rejectPublicKeyAlgorithms: new Set() }
}); });
privKeyDE.subKeys[0] = await privKeyDE.subKeys[0].revoke(privKeyDE.primaryKey); privKeyDE.subKeys[0] = await privKeyDE.subKeys[0].revoke(privKeyDE.primaryKey);
const decOpt = { const decOpt = {
message: await openpgp.readMessage({ armoredMessage: encrypted }), message: await openpgp.readMessage({ armoredMessage: encrypted }),
privateKeys: privKeyDE privateKeys: privKeyDE,
config: { rejectPublicKeyAlgorithms: new Set() }
}; };
const decrypted = await openpgp.decrypt(decOpt); const decrypted = await openpgp.decrypt(decOpt);
expect(decrypted.data).to.equal(plaintext); expect(decrypted.data).to.equal(plaintext);
@ -2535,7 +2579,8 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
await privKeyDE.decrypt(passphrase); await privKeyDE.decrypt(passphrase);
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: openpgp.Message.fromText(plaintext), message: openpgp.Message.fromText(plaintext),
publicKeys: pubKeyDE publicKeys: pubKeyDE,
config: { rejectPublicKeyAlgorithms: new Set() }
}); });
const decOpt = { const decOpt = {
message: await openpgp.readMessage({ armoredMessage: encrypted }), message: await openpgp.readMessage({ armoredMessage: encrypted }),

View File

@ -847,20 +847,18 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
`; `;
it('Testing signature checking on CAST5-enciphered message', async function() { it('Testing signature checking on CAST5-enciphered message', async function() {
const { rejectMessageHashAlgorithms } = openpgp.config; const priv_key = await openpgp.readKey({ armoredKey: priv_key_arm1 });
Object.assign(openpgp.config, { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]) }); const pub_key = await openpgp.readKey({ armoredKey: pub_key_arm1 });
try { const msg = await openpgp.readMessage({ armoredMessage: msg_arm1 });
const priv_key = await openpgp.readKey({ armoredKey: priv_key_arm1 }); await priv_key.decrypt("abcd");
const pub_key = await openpgp.readKey({ armoredKey: pub_key_arm1 }); const config = {
const msg = await openpgp.readMessage({ armoredMessage: msg_arm1 }); rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]),
await priv_key.decrypt("abcd"); rejectPublicKeyAlgorithms: new Set()
const decrypted = await openpgp.decrypt({ privateKeys: priv_key, publicKeys:[pub_key], message:msg }); };
expect(decrypted.data).to.exist; const decrypted = await openpgp.decrypt({ privateKeys: priv_key, publicKeys:[pub_key], message:msg, config });
expect(decrypted.signatures[0].valid).to.be.true; expect(decrypted.data).to.exist;
expect(decrypted.signatures[0].signature.packets.length).to.equal(1); expect(decrypted.signatures[0].valid).to.be.true;
} finally { expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
Object.assign(openpgp.config, { rejectMessageHashAlgorithms });
}
}); });
it('Supports decrypting with GnuPG stripped-key extension', async function() { it('Supports decrypting with GnuPG stripped-key extension', async function() {
@ -878,12 +876,14 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
await priv_key_gnupg_ext.decrypt("abcd"); await priv_key_gnupg_ext.decrypt("abcd");
await priv_key_gnupg_ext_2.decrypt("abcd"); await priv_key_gnupg_ext_2.decrypt("abcd");
expect(priv_key_gnupg_ext.isDecrypted()).to.be.true; expect(priv_key_gnupg_ext.isDecrypted()).to.be.true;
const msg = await openpgp.decrypt({ message, privateKeys: [priv_key_gnupg_ext], publicKeys: [pub_key] }); const msg = await openpgp.decrypt({ message, privateKeys: [priv_key_gnupg_ext], publicKeys: [pub_key], config: { rejectPublicKeyAlgorithms: new Set() } });
expect(msg.signatures).to.exist; expect(msg.signatures).to.exist;
expect(msg.signatures).to.have.length(1); expect(msg.signatures).to.have.length(1);
expect(msg.signatures[0].valid).to.be.true; expect(msg.signatures[0].valid).to.be.true;
expect(msg.signatures[0].signature.packets.length).to.equal(1); expect(msg.signatures[0].signature.packets.length).to.equal(1);
await expect(openpgp.sign({ message: openpgp.Message.fromText('test'), privateKeys: [priv_key_gnupg_ext] })).to.eventually.be.rejectedWith(/Cannot sign with a gnu-dummy key/); await expect(openpgp.sign({
message: openpgp.Message.fromText('test'), privateKeys: [priv_key_gnupg_ext], config: { rejectPublicKeyAlgorithms: new Set() }
})).to.eventually.be.rejectedWith(/Cannot sign with a gnu-dummy key/);
await expect(openpgp.reformatKey({ userIds: { name: 'test' }, privateKey: priv_key_gnupg_ext })).to.eventually.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/); await expect(openpgp.reformatKey({ userIds: { name: 'test' }, privateKey: priv_key_gnupg_ext })).to.eventually.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/);
await expect(openpgp.reformatKey({ userIds: { name: 'test' }, privateKey: priv_key_gnupg_ext_2, passphrase: 'test' })).to.eventually.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/); await expect(openpgp.reformatKey({ userIds: { name: 'test' }, privateKey: priv_key_gnupg_ext_2, passphrase: 'test' })).to.eventually.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/);
await priv_key_gnupg_ext.encrypt("abcd"); await priv_key_gnupg_ext.encrypt("abcd");
@ -918,8 +918,11 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
}); });
it('Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)', async function() { it('Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)', async function() {
const { rejectMessageHashAlgorithms } = openpgp.config; const { rejectMessageHashAlgorithms, minRsaBits } = openpgp.config;
Object.assign(openpgp.config, { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]) }); Object.assign(openpgp.config, {
rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]),
minRsaBits: 1024
});
try { try {
const signedArmor = const signedArmor =
['-----BEGIN PGP MESSAGE-----', ['-----BEGIN PGP MESSAGE-----',
@ -942,7 +945,7 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
expect(await verified[0].verified).to.be.true; expect(await verified[0].verified).to.be.true;
expect((await verified[0].signature).packets.length).to.equal(1); expect((await verified[0].signature).packets.length).to.equal(1);
} finally { } finally {
Object.assign(openpgp.config, { rejectMessageHashAlgorithms }); Object.assign(openpgp.config, { rejectMessageHashAlgorithms, minRsaBits });
} }
}); });
@ -970,7 +973,7 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
await Promise.all(esMsg.getEncryptionKeyIds().map(keyId => privKey.decrypt('hello world', keyId))); await Promise.all(esMsg.getEncryptionKeyIds().map(keyId => privKey.decrypt('hello world', keyId)));
return openpgp.decrypt({ privateKeys: privKey, publicKeys:[pubKey], message:esMsg }).then(function(decrypted) { return openpgp.decrypt({ privateKeys: privKey, publicKeys:[pubKey], message:esMsg, config: { minRsaBits: 1024 } }).then(function(decrypted) {
expect(decrypted.data).to.exist; expect(decrypted.data).to.exist;
expect(decrypted.data).to.equal(plaintext); expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures).to.have.length(1); expect(decrypted.signatures).to.have.length(1);
@ -997,46 +1000,44 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
's8PvkyWmVM0O0fB/ZSHovHNNPffDg/rWhzOmXQ9/7vTn477F+aWm5sYzJ75/BQA=', 's8PvkyWmVM0O0fB/ZSHovHNNPffDg/rWhzOmXQ9/7vTn477F+aWm5sYzJ75/BQA=',
'=+L0S', '=+L0S',
'-----END PGP MESSAGE-----'].join('\n'); '-----END PGP MESSAGE-----'].join('\n');
const plaintext = 'short message\nnext line\n한국어/조선말'; const plaintext = 'short message\nnext line\n한국어/조선말';
const sMsg = await openpgp.readMessage({ armoredMessage: msg_armor }); const sMsg = await openpgp.readMessage({ armoredMessage: msg_armor });
const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const pubKey3 = await openpgp.readKey({ armoredKey: pub_key_arm3 }); const pubKey3 = await openpgp.readKey({ armoredKey: pub_key_arm3 });
const keyids = sMsg.getSigningKeyIds(); const keyids = sMsg.getSigningKeyIds();
expect(pubKey2.getKeys(keyids[1])).to.not.be.empty; expect(pubKey2.getKeys(keyids[1])).to.not.be.empty;
expect(pubKey3.getKeys(keyids[0])).to.not.be.empty; expect(pubKey3.getKeys(keyids[0])).to.not.be.empty;
return sMsg.verify([pubKey2, pubKey3]).then(async verifiedSig => { const { data, signatures } = await openpgp.verify({ message: sMsg, publicKeys: [pubKey2, pubKey3], config: { minRsaBits: 1024 } });
expect(await openpgp.stream.readToEnd(sMsg.getText())).to.equal(plaintext); expect(data).to.equal(plaintext);
expect(verifiedSig).to.exist; expect(signatures).to.exist;
expect(verifiedSig).to.have.length(2); expect(signatures).to.have.length(2);
expect(await verifiedSig[0].verified).to.be.true; expect(await signatures[0].verified).to.be.true;
expect(await verifiedSig[1].verified).to.be.true; expect(await signatures[1].verified).to.be.true;
expect((await verifiedSig[0].signature).packets.length).to.equal(1); expect((await signatures[0].signature).packets.length).to.equal(1);
expect((await verifiedSig[1].signature).packets.length).to.equal(1); expect((await signatures[1].signature).packets.length).to.equal(1);
});
}); });
it('Verify fails with signed message with critical notations', async function() { it('Verify fails with signed message with critical notations', async function() {
const message = await openpgp.readMessage({ armoredMessage: signature_with_critical_notation }); const message = await openpgp.readMessage({ armoredMessage: signature_with_critical_notation });
const key = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const key = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const { signatures: [sig] } = await openpgp.verify({ message, publicKeys: key }); const { signatures: [sig] } = await openpgp.verify({ message, publicKeys: key, config: { minRsaBits: 1024 } });
expect(sig.valid).to.be.false; expect(sig.valid).to.be.false;
expect(sig.error).to.match(/Unknown critical notation: test@example.com/); expect(sig.error).to.match(/Unknown critical notation: test@example.com/);
}); });
it('Verify succeeds with known signed message with critical notations', async function() { it('Verify succeeds with known signed message with critical notations', async function() {
const config = { knownNotations: ['test@example.com'] };
const message = await openpgp.readMessage({ armoredMessage: signature_with_critical_notation }); const message = await openpgp.readMessage({ armoredMessage: signature_with_critical_notation });
const key = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const key = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const config = { knownNotations: ['test@example.com'], minRsaBits: 1024 };
const { signatures: [sig] } = await openpgp.verify({ message, publicKeys: key, config }); const { signatures: [sig] } = await openpgp.verify({ message, publicKeys: key, config });
expect(sig.valid).to.be.true; expect(sig.valid).to.be.true;
}); });
it('Verify cleartext signed message with two signatures with openpgp.verify', async function() { it('Verify cleartext signed message with two signatures with openpgp.verify', async function() {
const msg_armor = const cleartextMessage =
['-----BEGIN PGP SIGNED MESSAGE-----', ['-----BEGIN PGP SIGNED MESSAGE-----',
'Hash: SHA256', 'Hash: SHA256',
'', '',
@ -1060,16 +1061,16 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
'-----END PGP SIGNATURE-----'].join('\n'); '-----END PGP SIGNATURE-----'].join('\n');
const plaintext = 'short message\nnext line\n한국어/조선말'; const plaintext = 'short message\nnext line\n한국어/조선말';
const csMsg = await openpgp.readCleartextMessage({ cleartextMessage: msg_armor }); const message = await openpgp.readCleartextMessage({ cleartextMessage });
const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const pubKey3 = await openpgp.readKey({ armoredKey: pub_key_arm3 }); const pubKey3 = await openpgp.readKey({ armoredKey: pub_key_arm3 });
const keyids = csMsg.getSigningKeyIds(); const keyids = message.getSigningKeyIds();
expect(pubKey2.getKeys(keyids[0])).to.not.be.empty; expect(pubKey2.getKeys(keyids[0])).to.not.be.empty;
expect(pubKey3.getKeys(keyids[1])).to.not.be.empty; expect(pubKey3.getKeys(keyids[1])).to.not.be.empty;
return openpgp.verify({ publicKeys:[pubKey2, pubKey3], message:csMsg }).then(function(cleartextSig) { return openpgp.verify({ publicKeys:[pubKey2, pubKey3], message, config: { minRsaBits: 1024 } }).then(function(cleartextSig) {
expect(cleartextSig).to.exist; expect(cleartextSig).to.exist;
expect(cleartextSig.data).to.equal(plaintext); expect(cleartextSig.data).to.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(2); expect(cleartextSig.signatures).to.have.length(2);
@ -1114,11 +1115,8 @@ PAAeuQTUrcJdZeJ86eQ9cCUB216HCwSKOWTQRzL+hBWKXij4WD4=
it('Verify cleartext signed message with trailing spaces from GPG', async function() { it('Verify cleartext signed message with trailing spaces from GPG', async function() {
const { rejectMessageHashAlgorithms } = openpgp.config; const cleartextMessage =
Object.assign(openpgp.config, { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]) }); `-----BEGIN PGP SIGNED MESSAGE-----
try {
const msg_armor =
`-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1 Hash: SHA1
space: space:
@ -1137,28 +1135,29 @@ zmuVOdNuWQqxT9Sqa84=
=bqAR =bqAR
-----END PGP SIGNATURE-----`; -----END PGP SIGNATURE-----`;
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t '; const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
const csMsg = await openpgp.readCleartextMessage({ cleartextMessage: msg_armor }); const message = await openpgp.readCleartextMessage({ cleartextMessage });
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const keyids = csMsg.getSigningKeyIds(); const keyids = message.getSigningKeyIds();
expect(pubKey.getKeys(keyids[0])).to.not.be.empty; expect(pubKey.getKeys(keyids[0])).to.not.be.empty;
const cleartextSig = await openpgp.verify({ publicKeys:[pubKey], message:csMsg }); const cleartextSig = await openpgp.verify({
expect(cleartextSig).to.exist; publicKeys:[pubKey],
expect(cleartextSig.data).to.equal(plaintext.replace(/[ \t]+$/mg, '')); message,
expect(cleartextSig.signatures).to.have.length(1); config: { minRsaBits: 1024, rejectMessageHashAlgorithms: new Set() }
expect(cleartextSig.signatures[0].valid).to.be.true; });
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1); expect(cleartextSig).to.exist;
} finally { expect(cleartextSig.data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
Object.assign(openpgp.config, { rejectMessageHashAlgorithms }); expect(cleartextSig.signatures).to.have.length(1);
} expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
function tests() { function tests() {
it('Verify signed message with trailing spaces from GPG', async function() { it('Verify signed message with trailing spaces from GPG', async function() {
const msg_armor = const armoredMessage =
`-----BEGIN PGP MESSAGE----- `-----BEGIN PGP MESSAGE-----
Version: GnuPG v1 Version: GnuPG v1
@ -1172,24 +1171,22 @@ yYDnCgA=
-----END PGP MESSAGE-----`; -----END PGP MESSAGE-----`;
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t '; const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
const sMsg = await openpgp.readMessage({ armoredMessage: msg_armor }); const message = await openpgp.readMessage({ armoredMessage });
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const keyids = sMsg.getSigningKeyIds(); const keyids = message.getSigningKeyIds();
expect(pubKey.getKeys(keyids[0])).to.not.be.empty; expect(pubKey.getKeys(keyids[0])).to.not.be.empty;
return openpgp.verify({ publicKeys: [pubKey], message: sMsg }).then(function(cleartextSig) { return openpgp.verify({ publicKeys: [pubKey], message, config: { minRsaBits: 1024 } }).then(({ data, signatures }) => {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext);
expect(cleartextSig.data).to.equal(plaintext); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures[0].valid).to.equal(!openpgp.config.rejectMessageHashAlgorithms.has(openpgp.enums.hash.sha1));
expect(cleartextSig.signatures[0].valid).to.equal(!openpgp.config.rejectMessageHashAlgorithms.has(openpgp.enums.hash.sha1)); expect(signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
it('Streaming verify signed message with trailing spaces from GPG', async function() { it('Streaming verify signed message with trailing spaces from GPG', async function() {
const msg_armor = const armoredMessage =
`-----BEGIN PGP MESSAGE----- `-----BEGIN PGP MESSAGE-----
Version: GnuPG v1 Version: GnuPG v1
@ -1203,22 +1200,21 @@ yYDnCgA=
-----END PGP MESSAGE-----`.split(''); -----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t '; const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
const sMsg = await openpgp.readMessage({ const message = await openpgp.readMessage({
armoredMessage: new openpgp.stream.ReadableStream({ armoredMessage: new openpgp.stream.ReadableStream({
async pull(controller) { async pull(controller) {
await new Promise(setTimeout); await new Promise(setTimeout);
controller.enqueue(msg_armor.shift()); controller.enqueue(armoredMessage.shift());
if (!msg_armor.length) controller.close(); if (!armoredMessage.length) controller.close();
} }
}) })
}); });
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const keyids = sMsg.getSigningKeyIds(); const keyids = message.getSigningKeyIds();
expect(pubKey.getKeys(keyids[0])).to.not.be.empty; expect(pubKey.getKeys(keyids[0])).to.not.be.empty;
return openpgp.verify({ publicKeys: [pubKey], message: sMsg }).then(async function(cleartextSig) { return openpgp.verify({ publicKeys: [pubKey], message, config: { minRsaBits: 1024 } }).then(async function(cleartextSig) {
expect(cleartextSig).to.exist; expect(cleartextSig).to.exist;
expect(await openpgp.stream.readToEnd(cleartextSig.data)).to.equal(plaintext); expect(await openpgp.stream.readToEnd(cleartextSig.data)).to.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(1); expect(cleartextSig.signatures).to.have.length(1);
@ -1232,7 +1228,7 @@ yYDnCgA=
}); });
it('Verify signed message with missing signature packet', async function() { it('Verify signed message with missing signature packet', async function() {
const msg_armor = const armoredMessage =
`-----BEGIN PGP MESSAGE----- `-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js v3.1.3 Version: OpenPGP.js v3.1.3
Comment: https://openpgpjs.org Comment: https://openpgpjs.org
@ -1244,22 +1240,20 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
-----END PGP MESSAGE-----`; -----END PGP MESSAGE-----`;
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t '; const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
const sMsg = await openpgp.readMessage({ armoredMessage: msg_armor }); const message = await openpgp.readMessage({ armoredMessage });
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const keyids = sMsg.getSigningKeyIds(); const keyids = message.getSigningKeyIds();
expect(pubKey.getKeys(keyids[0])).to.not.be.empty; expect(pubKey.getKeys(keyids[0])).to.not.be.empty;
return openpgp.verify({ publicKeys: [pubKey], message: sMsg }).then(async function(cleartextSig) { return openpgp.verify({ publicKeys: [pubKey], message, config: { minRsaBits: 1024 } }).then(async ({ data, signatures }) => {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext);
expect(await openpgp.stream.readToEnd(cleartextSig.data)).to.equal(plaintext); expect(signatures).to.have.length(0);
expect(cleartextSig.signatures).to.have.length(0);
}); });
}); });
it('Streaming verify signed message with missing signature packet', async function() { it('Streaming verify signed message with missing signature packet', async function() {
const msg_armor = const armoredMessage =
`-----BEGIN PGP MESSAGE----- `-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js v3.1.3 Version: OpenPGP.js v3.1.3
Comment: https://openpgpjs.org Comment: https://openpgpjs.org
@ -1271,27 +1265,25 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
-----END PGP MESSAGE-----`.split(''); -----END PGP MESSAGE-----`.split('');
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t '; const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
const sMsg = await openpgp.readMessage({ const message = await openpgp.readMessage({
armoredMessage: new openpgp.stream.ReadableStream({ armoredMessage: new openpgp.stream.ReadableStream({
async pull(controller) { async pull(controller) {
await new Promise(setTimeout); await new Promise(setTimeout);
controller.enqueue(msg_armor.shift()); controller.enqueue(armoredMessage.shift());
if (!msg_armor.length) controller.close(); if (!armoredMessage.length) controller.close();
} }
}) })
}); });
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const keyids = sMsg.getSigningKeyIds(); const keyids = message.getSigningKeyIds();
expect(pubKey.getKeys(keyids[0])).to.not.be.empty; expect(pubKey.getKeys(keyids[0])).to.not.be.empty;
return openpgp.verify({ publicKeys: [pubKey], message: sMsg }).then(async function(cleartextSig) { return openpgp.verify({ publicKeys: [pubKey], message, config: { minRsaBits: 1024 } }).then(async ({ data, signatures }) => {
expect(cleartextSig).to.exist; expect(await openpgp.stream.readToEnd(data)).to.equal(plaintext);
expect(await openpgp.stream.readToEnd(cleartextSig.data)).to.equal(plaintext); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); await expect(signatures[0].verified).to.be.rejectedWith('Corresponding signature packet missing');
await expect(cleartextSig.signatures[0].verified).to.be.rejectedWith('Corresponding signature packet missing'); expect((await signatures[0].signature).packets.length).to.equal(0);
expect((await cleartextSig.signatures[0].signature).packets.length).to.equal(0);
}); });
}); });
} }
@ -1316,17 +1308,17 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.CleartextMessage.fromText(plaintext) }).then(async function(signed) { const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.CleartextMessage.fromText(plaintext), config }).then(async function(signed) {
const csMsg = await openpgp.readCleartextMessage({ cleartextMessage: signed }); const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
return openpgp.verify({ publicKeys:[pubKey], message:csMsg }); return openpgp.verify({ publicKeys:[pubKey], message, config });
}).then(function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext.replace(/[ \t\r]+$/mg, ''));
expect(cleartextSig.data).to.equal(plaintext.replace(/[ \t\r]+$/mg, '')); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1336,17 +1328,17 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.CleartextMessage.fromText(plaintext) }).then(async function(signed) { const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.CleartextMessage.fromText(plaintext), config }).then(async function(signed) {
const csMsg = await openpgp.readCleartextMessage({ cleartextMessage: signed }); const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
return openpgp.verify({ publicKeys:[pubKey], message:csMsg }); return openpgp.verify({ publicKeys:[pubKey], message, config });
}).then(function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext);
expect(cleartextSig.data).to.equal(plaintext); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1356,17 +1348,17 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.CleartextMessage.fromText(plaintext) }).then(async function(signed) { const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.CleartextMessage.fromText(plaintext), config }).then(async function(signed) {
const csMsg = await openpgp.readCleartextMessage({ cleartextMessage: signed }); const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
return openpgp.verify({ publicKeys:[pubKey], message:csMsg }); return openpgp.verify({ publicKeys:[pubKey], message, config });
}).then(function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
expect(cleartextSig.data).to.equal(plaintext.replace(/[ \t]+$/mg, '')); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1376,17 +1368,17 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromBinary(plaintext) }).then(async function(signed) { const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromBinary(plaintext), config }).then(async function(signed) {
const csMsg = await openpgp.readMessage({ armoredMessage: signed }); const message = await openpgp.readMessage({ armoredMessage: signed });
return openpgp.verify({ publicKeys:[pubKey], message:csMsg, format: 'binary' }); return openpgp.verify({ publicKeys:[pubKey], message, format: 'binary', config });
}).then(async function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.deep.equal(plaintext);
expect(cleartextSig.data).to.deep.equal(plaintext); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1396,17 +1388,17 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromBinary(plaintext), armor:false }).then(async function(signed) { const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromBinary(plaintext), armor:false, config }).then(async function(signed) {
const csMsg = await openpgp.readMessage({ binaryMessage: signed }); const message = await openpgp.readMessage({ binaryMessage: signed });
return openpgp.verify({ publicKeys:[pubKey], message:csMsg, format: 'binary' }); return openpgp.verify({ publicKeys:[pubKey], message, format: 'binary', config });
}).then(function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.deep.equal(plaintext);
expect(cleartextSig.data).to.deep.equal(plaintext); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1415,31 +1407,35 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromText(plaintext), detached: true }).then(async function(armoredSignature) {
const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromText(plaintext), detached: true, config }).then(async function(armoredSignature) {
const signature = await openpgp.readSignature({ armoredSignature }); const signature = await openpgp.readSignature({ armoredSignature });
return openpgp.verify({ publicKeys:[pubKey], message: openpgp.Message.fromBinary(util.encodeUtf8(plaintext)), signature: signature }); return openpgp.verify({ publicKeys:[pubKey], message: openpgp.Message.fromBinary(util.encodeUtf8(plaintext)), signature, config });
}).then(function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
it('Should verify cleartext message correctly when using a detached binary signature and text literal data', async function () { it('Should verify cleartext message correctly when using a detached binary signature and text literal data', async function () {
const plaintext = 'short message\nnext line \n한국어/조선말'; const plaintext = util.encodeUtf8('short message\nnext line \n한국어/조선말');
const plaintextArray = util.encodeUtf8(plaintext); const binaryPlaintext = util.encodeUtf8(plaintext);
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey.decrypt('hello world'); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message:openpgp.Message.fromBinary(plaintextArray), detached: true }).then(async function(armoredSignature) {
const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message:openpgp.Message.fromBinary(binaryPlaintext), detached: true, config }).then(async function(armoredSignature) {
const signature = await openpgp.readSignature({ armoredSignature }); const signature = await openpgp.readSignature({ armoredSignature });
return openpgp.verify({ publicKeys:[pubKey], message: openpgp.Message.fromText(plaintext), signature: signature }); return openpgp.verify({ publicKeys:[pubKey], message: openpgp.Message.fromText(plaintext), signature, config });
}).then(function(cleartextSig) { }).then(function({ data, signatures }) {
expect(cleartextSig).to.exist; expect(data).to.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(1); expect(signatures).to.have.length(1);
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1447,18 +1443,22 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const plaintext = 'short message\nnext line \n한국어/조선말'; const plaintext = 'short message\nnext line \n한국어/조선말';
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await Promise.all([privKey.primaryKey.decrypt('hello world'), privKey.subKeys[0].keyPacket.decrypt('hello world')]); await privKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromText(plaintext), detached: true }).then(async function(armoredSignature) {
const config = { minRsaBits: 1024 };
return openpgp.sign({ privateKeys:[privKey], message: openpgp.Message.fromText(plaintext), detached: true, config }).then(async function(armoredSignature) {
const signature = await openpgp.readSignature({ armoredSignature }); const signature = await openpgp.readSignature({ armoredSignature });
return openpgp.encrypt({ message: openpgp.Message.fromBinary(util.encodeUtf8(plaintext)), publicKeys: [pubKey], signature }); return openpgp.encrypt({ message: openpgp.Message.fromBinary(util.encodeUtf8(plaintext)), publicKeys: [pubKey], signature, config });
}).then(async armoredMessage => { }).then(async armoredMessage => {
const csMsg = await openpgp.readMessage({ armoredMessage }); const message = await openpgp.readMessage({ armoredMessage });
return openpgp.decrypt({ message: csMsg, privateKeys: [privKey], publicKeys: [pubKey] }); return openpgp.decrypt({ message, privateKeys: [privKey], publicKeys: [pubKey], config });
}).then(function(cleartextSig) {
expect(cleartextSig).to.exist; }).then(function({ data, signatures }) {
expect(cleartextSig.signatures).to.have.length(1); expect(data).to.equal(plaintext);
expect(cleartextSig.signatures[0].valid).to.be.true; expect(signatures).to.have.length(1);
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1); expect(signatures[0].valid).to.be.true;
expect(signatures[0].signature.packets.length).to.equal(1);
}); });
}); });
@ -1565,27 +1565,30 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const publicKeyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - https://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----'; const publicKeyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - https://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----';
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored }); const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
// Text const message = openpgp.Message.fromText(content);
const msg = openpgp.Message.fromText(content); await message.appendSignature(detachedSig);
await msg.appendSignature(detachedSig); const { data, signatures } = await openpgp.verify({ publicKeys:[publicKey], message, config: { minRsaBits: 1024 } });
return msg.verify([publicKey]).then(async result => { expect(data).to.equal(content);
openpgp.stream.pipe(msg.getLiteralData(), new openpgp.stream.WritableStream()); expect(signatures).to.have.length(1);
expect(await result[0].verified).to.be.true; expect(signatures[0].valid).to.be.true;
}); expect(signatures[0].signature.packets.length).to.equal(1);
expect(await signatures[0].verified).to.be.true;
}); });
it('Detached signature signing and verification', async function() { it('Detached signature signing and verification', async function() {
const msg = openpgp.Message.fromText('hello'); const message = openpgp.Message.fromText('hello');
const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 });
const privKey2 = await openpgp.readKey({ armoredKey: priv_key_arm2 }); const privKey2 = await openpgp.readKey({ armoredKey: priv_key_arm2 });
await privKey2.decrypt('hello world'); await privKey2.decrypt('hello world');
const opt = { rsaBits: 2048, userIds: { name:'test', email:'a@b.com' }, passphrase: null }; const opt = { rsaBits: 2048, userIds: { name:'test', email:'a@b.com' }, passphrase: null };
const { key: generatedKey } = await openpgp.generateKey(opt); const { key: generatedKey } = await openpgp.generateKey(opt);
const detachedSig = await msg.signDetached([generatedKey, privKey2]); const armoredSignature = await openpgp.sign({ privateKeys:[generatedKey, privKey2], message, detached: true, config: { minRsaBits: 1024 } });
const result = await msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]); const signature = await openpgp.readSignature({ armoredSignature });
expect(await result[0].verified).to.be.true; const { data, signatures } = await openpgp.verify({ publicKeys:[generatedKey.toPublic(), pubKey2], message, signature, config: { minRsaBits: 1024 } });
expect(await result[1].verified).to.be.true; expect(data).to.equal('hello');
expect(await signatures[0].verified).to.be.true;
expect(await signatures[1].verified).to.be.true;
}); });
it('Sign message with key without password', function() { it('Sign message with key without password', function() {
@ -1627,7 +1630,7 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
const signedKey = await openpgp.readKey({ armoredKey: signedArmor }); const signedKey = await openpgp.readKey({ armoredKey: signedArmor });
const signerKey = await openpgp.readKey({ armoredKey: priv_key_arm1 }); const signerKey = await openpgp.readKey({ armoredKey: priv_key_arm1 });
return signedKey.verifyPrimaryUser([signerKey]).then(signatures => { return signedKey.verifyPrimaryUser([signerKey], undefined, undefined, { ...openpgp.config, rejectPublicKeyAlgorithms: new Set() }).then(signatures => {
expect(signatures[0].valid).to.be.null; expect(signatures[0].valid).to.be.null;
expect(signatures[0].keyid.toHex()).to.equal(signedKey.getKeyId().toHex()); expect(signatures[0].keyid.toHex()).to.equal(signedKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.true; expect(signatures[1].valid).to.be.true;
@ -1724,11 +1727,12 @@ CftAJDBez44ZofZ8ahPfkAhJe6opxaqgS47s4FIQVOEJcF9RgwLTU6uooSzA
oaBUyhCKt8tz6Q== oaBUyhCKt8tz6Q==
=52k1 =52k1
-----END PGP PRIVATE KEY BLOCK-----`; -----END PGP PRIVATE KEY BLOCK-----`;
const key = await openpgp.readKey({ armoredKey: armoredKey }); const key = await openpgp.readKey({ armoredKey });
const decrypted = await openpgp.decrypt({ const decrypted = await openpgp.decrypt({
message: await openpgp.readMessage({ armoredMessage: encrypted }), message: await openpgp.readMessage({ armoredMessage: encrypted }),
publicKeys: key, publicKeys: key,
privateKeys: key privateKeys: key,
config: { minRsaBits: 1024 }
}); });
expect(decrypted.signatures[0].valid).to.be.true; expect(decrypted.signatures[0].valid).to.be.true;
}); });

View File

@ -237,7 +237,8 @@ function tests() {
it('Sign: Input stream should be canceled when canceling encrypted stream', async function() { it('Sign: Input stream should be canceled when canceling encrypted stream', async function() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
const reader = openpgp.stream.getReader(signed); const reader = openpgp.stream.getReader(signed);
expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\n/); expect(await reader.readBytes(1024)).to.match(/^-----BEGIN PGP MESSAGE-----\n/);
@ -312,7 +313,8 @@ function tests() {
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
publicKeys: pubKey, publicKeys: pubKey,
privateKeys: privKey, privateKeys: privKey,
armor: false armor: false,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(encrypted)).to.equal(expectedType); expect(openpgp.stream.isStream(encrypted)).to.equal(expectedType);
@ -443,7 +445,8 @@ function tests() {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
publicKeys: pubKey, publicKeys: pubKey,
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(encrypted)).to.equal(expectedType); expect(openpgp.stream.isStream(encrypted)).to.equal(expectedType);
@ -480,7 +483,8 @@ function tests() {
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
publicKeys: pubKey, publicKeys: pubKey,
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(encrypted)).to.equal(expectedType); expect(openpgp.stream.isStream(encrypted)).to.equal(expectedType);
@ -504,7 +508,7 @@ function tests() {
dataArrived(); dataArrived();
await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check on message failed'); await expect(reader.readToEnd()).to.be.rejectedWith('Ascii armor integrity check on message failed');
expect(decrypted.signatures).to.exist.and.have.length(1); expect(decrypted.signatures).to.exist.and.have.length(1);
expect(await decrypted.signatures[0].verified).to.be.null; await expect(decrypted.signatures[0].verified).to.be.eventually.rejectedWith(/Could not find signing key/);
} finally { } finally {
openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStreamValue; openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStreamValue;
} }
@ -513,7 +517,8 @@ function tests() {
it('Sign/verify: Detect armor checksum error', async function() { it('Sign/verify: Detect armor checksum error', async function() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
@ -529,7 +534,8 @@ function tests() {
publicKeys: pubKey, publicKeys: pubKey,
message, message,
streaming: expectedType, streaming: expectedType,
format: 'binary' format: 'binary',
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(verified.data)).to.equal(expectedType); expect(openpgp.stream.isStream(verified.data)).to.equal(expectedType);
const reader = openpgp.stream.getReader(verified.data); const reader = openpgp.stream.getReader(verified.data);
@ -567,7 +573,8 @@ function tests() {
it('Sign/verify: Input stream should be canceled when canceling verified stream', async function() { it('Sign/verify: Input stream should be canceled when canceling verified stream', async function() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
@ -575,7 +582,8 @@ function tests() {
const verified = await openpgp.verify({ const verified = await openpgp.verify({
publicKeys: pubKey, publicKeys: pubKey,
message, message,
format: 'binary' format: 'binary',
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(verified.data)).to.equal(expectedType); expect(openpgp.stream.isStream(verified.data)).to.equal(expectedType);
const reader = openpgp.stream.getReader(verified.data); const reader = openpgp.stream.getReader(verified.data);
@ -605,7 +613,8 @@ function tests() {
it("Sign: Don't pull entire input stream when we're not pulling signed stream", async function() { it("Sign: Don't pull entire input stream when we're not pulling signed stream", async function() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
@ -619,7 +628,8 @@ function tests() {
it("Sign/verify: Don't pull entire input stream when we're not pulling verified stream", async function() { it("Sign/verify: Don't pull entire input stream when we're not pulling verified stream", async function() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey privateKeys: privKey,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
const message = await openpgp.readMessage({ armoredMessage: signed }); const message = await openpgp.readMessage({ armoredMessage: signed });
@ -649,7 +659,8 @@ function tests() {
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey, privateKeys: privKey,
detached: true, detached: true,
streaming: expectedType streaming: expectedType,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
const armoredSignature = await openpgp.stream.readToEnd(signed); const armoredSignature = await openpgp.stream.readToEnd(signed);
@ -657,7 +668,8 @@ function tests() {
const verified = await openpgp.verify({ const verified = await openpgp.verify({
signature, signature,
publicKeys: pubKey, publicKeys: pubKey,
message: openpgp.Message.fromText('hello world') message: openpgp.Message.fromText('hello world'),
config: { minRsaBits: 1024 }
}); });
expect(verified.data).to.equal('hello world'); expect(verified.data).to.equal('hello world');
expect(verified.signatures).to.exist.and.have.length(1); expect(verified.signatures).to.exist.and.have.length(1);
@ -678,14 +690,16 @@ function tests() {
privateKeys: privKey, privateKeys: privKey,
detached: true, detached: true,
streaming: false, streaming: false,
armor: false armor: false,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.be.false; expect(openpgp.stream.isStream(signed)).to.be.false;
const signature = await openpgp.readMessage({ binaryMessage: signed }); const signature = await openpgp.readMessage({ binaryMessage: signed });
const verified = await openpgp.verify({ const verified = await openpgp.verify({
signature, signature,
publicKeys: pubKey, publicKeys: pubKey,
message: openpgp.Message.fromText('hello world') message: openpgp.Message.fromText('hello world'),
config: { minRsaBits: 1024 }
}); });
expect(verified.data).to.equal('hello world'); expect(verified.data).to.equal('hello world');
expect(verified.signatures).to.exist.and.have.length(1); expect(verified.signatures).to.exist.and.have.length(1);
@ -758,7 +772,8 @@ function tests() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey, privateKeys: privKey,
detached: true detached: true,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
const reader = openpgp.stream.getReader(signed); const reader = openpgp.stream.getReader(signed);
@ -772,7 +787,8 @@ function tests() {
const signed = await openpgp.sign({ const signed = await openpgp.sign({
message: openpgp.Message.fromBinary(data), message: openpgp.Message.fromBinary(data),
privateKeys: privKey, privateKeys: privKey,
detached: true detached: true,
config: { minRsaBits: 1024 }
}); });
expect(openpgp.stream.isStream(signed)).to.equal(expectedType); expect(openpgp.stream.isStream(signed)).to.equal(expectedType);
const reader = openpgp.stream.getReader(signed); const reader = openpgp.stream.getReader(signed);

View File

@ -409,7 +409,7 @@ function omnibus() {
certificate.verified = null; certificate.verified = null;
await user.verifyCertificate( await user.verifyCertificate(
primaryKey, certificate, [hi.toPublic()] primaryKey, certificate, [hi.toPublic()], undefined, openpgp.config
).then(async () => expect(certificate.verified).to.be.true); ).then(async () => expect(certificate.verified).to.be.true);
const options = { const options = {
@ -432,7 +432,7 @@ function omnibus() {
).then(async () => expect(certificate.verified).to.be.true); ).then(async () => expect(certificate.verified).to.be.true);
certificate.verified = null; certificate.verified = null;
await user.verifyCertificate( await user.verifyCertificate(
bye.primaryKey, user.selfCertifications[0], [bye.toPublic()] bye.primaryKey, user.selfCertifications[0], [bye.toPublic()], undefined, openpgp.config
).then(async () => expect(certificate.verified).to.be.true); ).then(async () => expect(certificate.verified).to.be.true);
return Promise.all([ return Promise.all([

View File

@ -72,7 +72,8 @@ async function testSubkeyTrust() {
streaming: false streaming: false
}); });
expect(verifyAttackerIsBatman.signatures[0].keyid.equals(victimPubKey.subKeys[0].getKeyId())).to.be.true; expect(verifyAttackerIsBatman.signatures[0].keyid.equals(victimPubKey.subKeys[0].getKeyId())).to.be.true;
expect(verifyAttackerIsBatman.signatures[0].valid).to.be.null; expect(verifyAttackerIsBatman.signatures[0].valid).to.be.false;
expect(verifyAttackerIsBatman.signatures[0].error).to.match(/Could not find valid signing key packet/);
} }
module.exports = () => it('Does not trust subkeys without Primary Key Binding Signature', testSubkeyTrust); module.exports = () => it('Does not trust subkeys without Primary Key Binding Signature', testSubkeyTrust);