diff --git a/src/key/helper.js b/src/key/helper.js index f80b31dd..55fb5ff2 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -116,9 +116,9 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us let hashAlgo = config.preferredHashAlgorithm; let prefAlgo = hashAlgo; if (key) { - const primaryUser = await key.getPrimaryUser(date, userID, config); - if (primaryUser.selfCertification.preferredHashAlgorithms) { - [prefAlgo] = primaryUser.selfCertification.preferredHashAlgorithms; + const selfCertification = await key.getPrimarySelfSignature(date, userID, config); + if (selfCertification.preferredHashAlgorithms) { + [prefAlgo] = selfCertification.preferredHashAlgorithms; hashAlgo = crypto.hash.getHashByteLength(hashAlgo) <= crypto.hash.getHashByteLength(prefAlgo) ? prefAlgo : hashAlgo; } @@ -164,8 +164,8 @@ export async function getPreferredAlgo(type, keys = [], date = new Date(), userI // otherwise we use the default algo // if no keys are available, preferredSenderAlgo is returned const senderAlgoSupport = await Promise.all(keys.map(async function(key, i) { - const primaryUser = await key.getPrimaryUser(date, userIDs[i], config); - const recipientPrefs = primaryUser.selfCertification[prefPropertyName]; + const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config); + const recipientPrefs = selfCertification[prefPropertyName]; return !!recipientPrefs && recipientPrefs.indexOf(preferredSenderAlgo) >= 0; })); return senderAlgoSupport.every(Boolean) ? preferredSenderAlgo : defaultAlgo; @@ -306,9 +306,9 @@ export async function isAEADSupported(keys, date = new Date(), userIDs = [], con let supported = true; // TODO replace when Promise.some or Promise.any are implemented await Promise.all(keys.map(async function(key, i) { - const primaryUser = await key.getPrimaryUser(date, userIDs[i], config); - if (!primaryUser.selfCertification.features || - !(primaryUser.selfCertification.features[0] & enums.features.aead)) { + const selfCertification = await key.getPrimarySelfSignature(date, userIDs[i], config); + if (!selfCertification.features || + !(selfCertification.features[0] & enums.features.aead)) { supported = false; } })); diff --git a/src/key/key.js b/src/key/key.js index 72286b1c..3b1ed8c2 100644 --- a/src/key/key.js +++ b/src/key/key.js @@ -288,9 +288,9 @@ class Key { } try { - const primaryUser = await this.getPrimaryUser(date, userID, config); + const selfCertification = await this.getPrimarySelfSignature(date, userID, config); if ((!keyID || primaryKey.getKeyID().equals(keyID)) && - helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, config)) { + helper.isValidSigningKeyPacket(primaryKey, selfCertification, config)) { helper.checkKeyRequirements(primaryKey, config); return this; } @@ -334,9 +334,9 @@ class Key { try { // if no valid subkey for encryption, evaluate primary key - const primaryUser = await this.getPrimaryUser(date, userID, config); + const selfCertification = await this.getPrimarySelfSignature(date, userID, config); if ((!keyID || primaryKey.getKeyID().equals(keyID)) && - helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) { + helper.isValidEncryptionKeyPacket(primaryKey, selfCertification)) { helper.checkKeyRequirements(primaryKey, config); return this; } @@ -380,18 +380,20 @@ class Key { throw new Error('Primary key is revoked'); } // check for valid, unrevoked, unexpired self signature - const { selfCertification } = await this.getPrimaryUser(date, userID, config); + const selfCertification = await this.getPrimarySelfSignature(date, userID, config); // check for expiration time in binding signatures if (helper.isDataExpired(primaryKey, selfCertification, date)) { throw new Error('Primary key is expired'); } - // check for expiration time in direct signatures - const directSignature = await helper.getLatestValidSignature( - this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config - ).catch(() => {}); // invalid signatures are discarded, to avoid breaking the key + if (primaryKey.version !== 6) { + // check for expiration time in direct signatures (for V6 keys, the above already did so) + const directSignature = await helper.getLatestValidSignature( + this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config + ).catch(() => {}); // invalid signatures are discarded, to avoid breaking the key - if (directSignature && helper.isDataExpired(primaryKey, directSignature, date)) { - throw new Error('Primary key is expired'); + if (directSignature && helper.isDataExpired(primaryKey, directSignature, date)) { + throw new Error('Primary key is expired'); + } } } @@ -406,12 +408,13 @@ class Key { async getExpirationTime(userID, config = defaultConfig) { let primaryKeyExpiry; try { - const { selfCertification } = await this.getPrimaryUser(null, userID, config); + const selfCertification = await this.getPrimarySelfSignature(null, userID, config); const selfSigKeyExpiry = helper.getKeyExpirationTime(this.keyPacket, selfCertification); const selfSigExpiry = selfCertification.getExpirationTime(); - const directSignature = await helper.getLatestValidSignature( - this.directSignatures, this.keyPacket, enums.signature.key, { key: this.keyPacket }, null, config - ).catch(() => {}); + const directSignature = this.keyPacket.version !== 6 && // For V6 keys, the above already returns the direct-key signature. + await helper.getLatestValidSignature( + this.directSignatures, this.keyPacket, enums.signature.key, { key: this.keyPacket }, null, config + ).catch(() => {}); if (directSignature) { const directSigKeyExpiry = helper.getKeyExpirationTime(this.keyPacket, directSignature); // We do not support the edge case where the direct signature expires, since it would invalidate the corresponding key expiration, @@ -428,6 +431,28 @@ class Key { } + /** + * For V4 keys, returns the self-signature of the primary user. + * For V5 keys, returns the latest valid direct-key self-signature. + * This self-signature is to be used to check the key expiration, + * algorithm preferences, and so on. + * @param {Date} [date] - Use the given date for verification instead of the current time + * @param {Object} [userID] - User ID to get instead of the primary user for V4 keys, if it exists + * @param {Object} [config] - Full configuration, defaults to openpgp.config + * @returns {Promise} The primary self-signature + * @async + */ + async getPrimarySelfSignature(date = new Date(), userID = {}, config = defaultConfig) { + const primaryKey = this.keyPacket; + if (primaryKey.version === 6) { + return helper.getLatestValidSignature( + this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config + ); + } + const { selfCertification } = await this.getPrimaryUser(date, userID, config); + return selfCertification; + } + /** * Returns primary user and most significant (latest valid) self signature * - if multiple primary users exist, returns the one with the latest self signature diff --git a/src/key/private_key.js b/src/key/private_key.js index 384a94ec..055de008 100644 --- a/src/key/private_key.js +++ b/src/key/private_key.js @@ -93,9 +93,9 @@ class PrivateKey extends PublicKey { } // evaluate primary key - const primaryUser = await this.getPrimaryUser(date, userID, config); + const selfCertification = await this.getPrimarySelfSignature(date, userID, config); if ((!keyID || primaryKey.getKeyID().equals(keyID, true)) && - helper.isValidDecryptionKeyPacket(primaryUser.selfCertification, config)) { + helper.isValidDecryptionKeyPacket(selfCertification, config)) { keys.push(this); } diff --git a/src/message.js b/src/message.js index 5a88e7b0..611dfbc8 100644 --- a/src/message.js +++ b/src/message.js @@ -204,9 +204,9 @@ export class Message { enums.symmetric.cast5 // Golang OpenPGP fallback ]; try { - const primaryUser = await decryptionKey.getPrimaryUser(date, undefined, config); // TODO: Pass userID from somewhere. - if (primaryUser.selfCertification.preferredSymmetricAlgorithms) { - algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms); + const selfCertification = await decryptionKey.getPrimarySelfSignature(date, undefined, config); // TODO: Pass userID from somewhere. + if (selfCertification.preferredSymmetricAlgorithms) { + algos = algos.concat(selfCertification.preferredSymmetricAlgorithms); } } catch (e) {}