mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00
For v6 keys, check direct-key signature for key properties
Key flags, expiration time, algorithm preferences, et cetera, are now read from the direct-key signature instead of the primary User ID binding signature for v6 keys. This also requires a direct-key signature to be present for v6 keys.
This commit is contained in:
parent
5391bcc1bc
commit
6f1eb06119
@ -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;
|
||||
}
|
||||
}));
|
||||
|
@ -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<SignaturePacket>} 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user