Allow checking expiry of subkeys by capability, keyId or userId
This commit is contained in:
parent
06746b6a77
commit
a49276a158
74
src/key.js
74
src/key.js
|
@ -276,15 +276,14 @@ function isValidSigningKeyPacket(keyPacket, signature, date=new Date()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns last created key packet or key packet by given keyId that is available for signing and verification
|
* Returns last created key or key by given keyId that is available for signing and verification
|
||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Date} date use the given date for verification instead of the current time
|
* @param {Date} date use the given date for verification instead of the current time
|
||||||
* @param {Object} userId, optional user ID
|
* @param {Object} userId, optional user ID
|
||||||
* @returns {Promise<module:packet.SecretSubkey|
|
* @returns {Promise<Key|SubKey|null>} key or null if no signing key has been found
|
||||||
* module:packet.SecretKey|null>} key packet or null if no signing key has been found
|
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
Key.prototype.getSigningKeyPacket = async function (keyId=null, date=new Date(), userId={}) {
|
Key.prototype.getSigningKey = async function (keyId=null, date=new Date(), userId={}) {
|
||||||
const primaryKey = this.primaryKey;
|
const primaryKey = this.primaryKey;
|
||||||
if (await this.verifyPrimaryKey(date, userId) === enums.keyStatus.valid) {
|
if (await this.verifyPrimaryKey(date, userId) === enums.keyStatus.valid) {
|
||||||
const subKeys = this.subKeys.slice().sort((a, b) => b.created - a.created);
|
const subKeys = this.subKeys.slice().sort((a, b) => b.created - a.created);
|
||||||
|
@ -294,7 +293,7 @@ Key.prototype.getSigningKeyPacket = async function (keyId=null, date=new Date(),
|
||||||
if (await subKeys[i].verify(primaryKey, date) === enums.keyStatus.valid) {
|
if (await subKeys[i].verify(primaryKey, date) === enums.keyStatus.valid) {
|
||||||
const bindingSignature = getLatestSignature(subKeys[i].bindingSignatures, date);
|
const bindingSignature = getLatestSignature(subKeys[i].bindingSignatures, date);
|
||||||
if (isValidSigningKeyPacket(subKeys[i].subKey, bindingSignature, date)) {
|
if (isValidSigningKeyPacket(subKeys[i].subKey, bindingSignature, date)) {
|
||||||
return subKeys[i].subKey;
|
return subKeys[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,12 +301,26 @@ Key.prototype.getSigningKeyPacket = async function (keyId=null, date=new Date(),
|
||||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
const primaryUser = await this.getPrimaryUser(date, userId);
|
||||||
if (primaryUser && (!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
if (primaryUser && (!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
||||||
isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, date)) {
|
isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, date)) {
|
||||||
return primaryKey;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns last created key packet or key packet by given keyId that is available for signing and verification
|
||||||
|
* @param {module:type/keyid} keyId, optional
|
||||||
|
* @param {Date} date use the given date for verification instead of the current time
|
||||||
|
* @param {Object} userId, optional user ID
|
||||||
|
* @returns {Promise<module:packet.SecretSubkey|
|
||||||
|
* module:packet.SecretKey|null>} key packet or null if no signing key has been found
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
Key.prototype.getSigningKeyPacket = async function (keyId=null, date=new Date(), userId={}) {
|
||||||
|
const signingKey = await this.getSigningKey(keyId, date, userId);
|
||||||
|
return signingKey && (signingKey.subKey || signingKey.primaryKey);
|
||||||
|
};
|
||||||
|
|
||||||
function isValidEncryptionKeyPacket(keyPacket, signature, date=new Date()) {
|
function isValidEncryptionKeyPacket(keyPacket, signature, date=new Date()) {
|
||||||
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) &&
|
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) &&
|
||||||
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_sign) &&
|
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_sign) &&
|
||||||
|
@ -321,17 +334,14 @@ function isValidEncryptionKeyPacket(keyPacket, signature, date=new Date()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns last created key packet or key packet by given keyId that is available for encryption or decryption
|
* Returns last created key or key by given keyId that is available for encryption or decryption
|
||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Date} date, optional
|
* @param {Date} date, optional
|
||||||
* @param {String} userId, optional
|
* @param {String} userId, optional
|
||||||
* @returns {Promise<module:packet.PublicSubkey|
|
* @returns {Promise<Key|SubKey|null>} key or null if no encryption key has been found
|
||||||
* module:packet.SecretSubkey|
|
|
||||||
* module:packet.SecretKey|
|
|
||||||
* module:packet.PublicKey|null>} key packet or null if no encryption key has been found
|
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date(), userId={}) {
|
Key.prototype.getEncryptionKey = async function(keyId, date=new Date(), userId={}) {
|
||||||
const primaryKey = this.primaryKey;
|
const primaryKey = this.primaryKey;
|
||||||
if (await this.verifyPrimaryKey(date, userId) === enums.keyStatus.valid) {
|
if (await this.verifyPrimaryKey(date, userId) === enums.keyStatus.valid) {
|
||||||
// V4: by convention subkeys are preferred for encryption service
|
// V4: by convention subkeys are preferred for encryption service
|
||||||
|
@ -343,7 +353,7 @@ Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date(), us
|
||||||
if (await subKeys[i].verify(primaryKey, date) === enums.keyStatus.valid) {
|
if (await subKeys[i].verify(primaryKey, date) === enums.keyStatus.valid) {
|
||||||
const bindingSignature = getLatestSignature(subKeys[i].bindingSignatures, date);
|
const bindingSignature = getLatestSignature(subKeys[i].bindingSignatures, date);
|
||||||
if (isValidEncryptionKeyPacket(subKeys[i].subKey, bindingSignature, date)) {
|
if (isValidEncryptionKeyPacket(subKeys[i].subKey, bindingSignature, date)) {
|
||||||
return subKeys[i].subKey;
|
return subKeys[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,12 +362,28 @@ Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date(), us
|
||||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
const primaryUser = await this.getPrimaryUser(date, userId);
|
||||||
if (primaryUser && (!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
if (primaryUser && (!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
||||||
isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification, date)) {
|
isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification, date)) {
|
||||||
return primaryKey;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns last created key packet or key packet by given keyId that is available for encryption or decryption
|
||||||
|
* @param {module:type/keyid} keyId, optional
|
||||||
|
* @param {Date} date, optional
|
||||||
|
* @param {String} userId, optional
|
||||||
|
* @returns {Promise<module:packet.PublicSubkey|
|
||||||
|
* module:packet.SecretSubkey|
|
||||||
|
* module:packet.SecretKey|
|
||||||
|
* module:packet.PublicKey|null>} key packet or null if no encryption key has been found
|
||||||
|
* @async
|
||||||
|
*/
|
||||||
|
Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date(), userId={}) {
|
||||||
|
const encryptionKey = await this.getEncryptionKey(keyId, date, userId);
|
||||||
|
return encryptionKey && (encryptionKey.subKey || encryptionKey.primaryKey);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts all secret key and subkey packets matching keyId
|
* Encrypts all secret key and subkey packets matching keyId
|
||||||
* @param {String|Array<String>} passphrases - if multiple passphrases, then should be in same order as packets each should encrypt
|
* @param {String|Array<String>} passphrases - if multiple passphrases, then should be in same order as packets each should encrypt
|
||||||
|
@ -465,11 +491,16 @@ Key.prototype.verifyPrimaryKey = async function(date=new Date(), userId={}) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the expiration time of the primary key or Infinity if key does not expire
|
* Returns the latest date when the key can be used for encrypting, signing, or both, depending on the `capabilities` paramater.
|
||||||
|
* When `capabilities` is null, defaults to returning the expiry date of the primary key.
|
||||||
|
* Returns Infinity if the key doesn't expire.
|
||||||
|
* @param {encrypt|sign|encrypt_sign} capabilities, optional
|
||||||
|
* @param {module:type/keyid} keyId, optional
|
||||||
|
* @param {Object} userId, optional user ID
|
||||||
* @returns {Promise<Date>}
|
* @returns {Promise<Date>}
|
||||||
* @async
|
* @async
|
||||||
*/
|
*/
|
||||||
Key.prototype.getExpirationTime = async function() {
|
Key.prototype.getExpirationTime = async function(capabilities, keyId, userId) {
|
||||||
if (this.primaryKey.version === 3) {
|
if (this.primaryKey.version === 3) {
|
||||||
return getExpirationTime(this.primaryKey);
|
return getExpirationTime(this.primaryKey);
|
||||||
}
|
}
|
||||||
|
@ -478,7 +509,16 @@ Key.prototype.getExpirationTime = async function() {
|
||||||
const selfCert = primaryUser.selfCertification;
|
const selfCert = primaryUser.selfCertification;
|
||||||
const keyExpiry = getExpirationTime(this.primaryKey, selfCert);
|
const keyExpiry = getExpirationTime(this.primaryKey, selfCert);
|
||||||
const sigExpiry = selfCert.getExpirationTime();
|
const sigExpiry = selfCert.getExpirationTime();
|
||||||
return keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
|
let expiry = keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
|
||||||
|
if (capabilities === 'encrypt' || capabilities === 'encrypt_sign') {
|
||||||
|
const encryptExpiry = (await this.getEncryptionKey(keyId, null, userId)).getExpirationTime();
|
||||||
|
if (encryptExpiry < expiry) expiry = encryptExpiry;
|
||||||
|
}
|
||||||
|
if (capabilities === 'sign' || capabilities === 'encrypt_sign') {
|
||||||
|
const signExpiry = (await this.getSigningKey(keyId, null, userId)).getExpirationTime();
|
||||||
|
if (signExpiry < expiry) expiry = signExpiry;
|
||||||
|
}
|
||||||
|
return expiry;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1248,6 +1248,62 @@ const mergeKey2 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
|
||||||
'=REGo\n' +
|
'=REGo\n' +
|
||||||
'-----END PGP PUBLIC KEY BLOCK-----\n';
|
'-----END PGP PUBLIC KEY BLOCK-----\n';
|
||||||
|
|
||||||
|
const priv_key_2000_2008 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
t/ia1kMpSEiOVLlX5dfHZzhR3WNtBqU=
|
||||||
|
=C0fJ
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||||
|
|
||||||
|
|
||||||
it('Parsing armored text with two keys', function(done) {
|
it('Parsing armored text with two keys', function(done) {
|
||||||
const pubKeys = openpgp.key.readArmored(twoKeys);
|
const pubKeys = openpgp.key.readArmored(twoKeys);
|
||||||
|
@ -1387,6 +1443,16 @@ const mergeKey2 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
|
||||||
expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
|
expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Method getExpirationTime V4 Key with capabilities', async function() {
|
||||||
|
const pubKey = openpgp.key.readArmored(priv_key_2000_2008).keys[0];
|
||||||
|
expect(pubKey).to.exist;
|
||||||
|
expect(pubKey).to.be.an.instanceof(openpgp.key.Key);
|
||||||
|
const expirationTime = await pubKey.getExpirationTime();
|
||||||
|
expect(expirationTime).to.equal(Infinity);
|
||||||
|
const encryptExpirationTime = await pubKey.getExpirationTime('encrypt_sign');
|
||||||
|
expect(encryptExpirationTime.toISOString()).to.equal('2008-02-12T17:12:08.000Z');
|
||||||
|
});
|
||||||
|
|
||||||
it('update() - throw error if fingerprints not equal', function(done) {
|
it('update() - throw error if fingerprints not equal', function(done) {
|
||||||
const keys = openpgp.key.readArmored(twoKeys).keys;
|
const keys = openpgp.key.readArmored(twoKeys).keys;
|
||||||
expect(keys[0].update.bind(
|
expect(keys[0].update.bind(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user