From 50940b2a1e1d087aa6ac07784ae9751ed28c22b8 Mon Sep 17 00:00:00 2001 From: Sanjana Rajan Date: Wed, 17 Jan 2018 18:37:25 +0100 Subject: [PATCH] flag to allow verification with expired keys --- src/config/config.js | 1 + src/key.js | 64 +++++++++++++++++--------------------------- src/message.js | 2 +- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index 131205d3..ef8a2611 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -41,6 +41,7 @@ export default { integrity_protect: true, // use integrity protection for symmetric encryption ignore_mdc_error: false, // fail on decrypt if message is not integrity protected checksum_required: false, // do not throw error when armor is missing a checksum + verify_expired_keys: false, // allow signature verification with expired keys rsa_blinding: true, use_native: true, // use native node.js crypto and Web Crypto apis (if available) zero_copy: false, // use transferable objects between the Web Worker and main thread diff --git a/src/key.js b/src/key.js index 60a46be0..6f70b011 100644 --- a/src/key.js +++ b/src/key.js @@ -294,18 +294,21 @@ Key.prototype.armor = function() { /** * Returns first key packet or key packet by given keyId that is available for signing or signature verification * @param {module:type/keyid} keyId, optional + * @param {Boolean} allowExpired allows signature verification with expired keys * @return {(module:packet/secret_subkey|module:packet/secret_key|null)} key packet or null if no signing key has been found */ -Key.prototype.getSigningKeyPacket = function(keyId) { - var primaryUser = this.getPrimaryUser(); +Key.prototype.getSigningKeyPacket = function(keyId, allowExpired=false) { + var primaryUser = this.getPrimaryUser(allowExpired); + var verifyStatus = this.verifyPrimaryKey(allowExpired); if (primaryUser && isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate) && - (!keyId || this.primaryKey.getKeyId().equals(keyId))) { + (!keyId || this.primaryKey.getKeyId().equals(keyId)) && + verifyStatus === enums.keyStatus.valid) { return this.primaryKey; } if (this.subKeys) { for (var i = 0; i < this.subKeys.length; i++) { - if (this.subKeys[i].isValidSigningKey(this.primaryKey) && + if (this.subKeys[i].isValidSigningKey(this.primaryKey, allowExpired) && (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId))) { return this.subKeys[i].subKey; } @@ -430,9 +433,10 @@ Key.prototype.decryptKeyPacket = function(keyIds, passphrase) { /** * Verify primary key. Checks for revocation signatures, expiration time * and valid self signature + * @param {Boolean} allowExpired allows signature verification with expired keys * @return {module:enums.keyStatus} The status of the primary key */ -Key.prototype.verifyPrimaryKey = function() { +Key.prototype.verifyPrimaryKey = function(allowExpired=false) { // check revocation signature if (this.revocationSignature && !this.revocationSignature.isExpired() && (this.revocationSignature.verified || @@ -440,7 +444,7 @@ Key.prototype.verifyPrimaryKey = function() { return enums.keyStatus.revoked; } // check V3 expiration time - if (this.primaryKey.version === 3 && this.primaryKey.expirationTimeV3 !== 0 && + if (!allowExpired && this.primaryKey.version === 3 && this.primaryKey.expirationTimeV3 !== 0 && Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) { return enums.keyStatus.expired; } @@ -461,7 +465,7 @@ Key.prototype.verifyPrimaryKey = function() { return enums.keyStatus.invalid; } // check V4 expiration time - if (this.primaryKey.version === 4 && primaryUser.selfCertificate.keyNeverExpires === false && + if (!allowExpired && this.primaryKey.version === 4 && primaryUser.selfCertificate.keyNeverExpires === false && Date.now() > (this.primaryKey.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) { return enums.keyStatus.expired; } @@ -502,9 +506,10 @@ function getExpirationTime(keyPacket, selfCertificate) { * Returns primary user and most significant (latest valid) self signature * - if multiple users are marked as primary users returns the one with the latest self signature * - if no primary user is found returns the user with the latest self signature + * @param {Boolean} allowExpired allows signature verification with expired keys * @return {{user: Array, selfCertificate: Array}|null} The primary user and the self signature */ -Key.prototype.getPrimaryUser = function() { +Key.prototype.getPrimaryUser = function(allowExpired=false) { var primUser = []; for (var i = 0; i < this.users.length; i++) { if (!this.users[i].userId || !this.users[i].selfCertifications) { @@ -530,7 +535,7 @@ Key.prototype.getPrimaryUser = function() { }); // return first valid for (var k = 0; k < primUser.length; k++) { - if (primUser[k].user.isValidSelfCertificate(this.primaryKey, primUser[k].selfCertificate)) { + if (primUser[k].user.isValidSelfCertificate(this.primaryKey, primUser[k].selfCertificate, allowExpired)) { return primUser[k]; } } @@ -744,40 +749,18 @@ User.prototype.isRevoked = function(certificate, primaryKey) { } }; -/** - * Returns the most significant (latest valid) self signature of the user - * @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet - * @return {module:packet/signature} The self signature - */ -User.prototype.getValidSelfCertificate = function(primaryKey) { - if (!this.selfCertifications) { - return null; - } - // most recent first - var validCert = this.selfCertifications.sort(function(a, b) { - a = a.created; - b = b.created; - return a>b ? -1 : a (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) { return enums.keyStatus.expired; } @@ -977,7 +963,7 @@ SubKey.prototype.verify = function(primaryKey) { var isLast = (i === this.bindingSignatures.length - 1); var sig = this.bindingSignatures[i]; // check binding signature is not expired - if(sig.isExpired()) { + if(!allowExpired && sig.isExpired()) { if(isLast) { return enums.keyStatus.expired; // last expired binding signature } else { @@ -994,7 +980,7 @@ SubKey.prototype.verify = function(primaryKey) { } // check V4 expiration time if (this.subKey.version === 4) { - if(sig.keyNeverExpires === false && Date.now() > (this.subKey.created.getTime() + sig.keyExpirationTime*1000)) { + if(!allowExpired && sig.keyNeverExpires === false && Date.now() > (this.subKey.created.getTime() + sig.keyExpirationTime*1000)) { if(isLast) { return enums.keyStatus.expired; // last V4 expired binding signature } else { diff --git a/src/message.js b/src/message.js index 9d9a8b30..139ca4de 100644 --- a/src/message.js +++ b/src/message.js @@ -467,7 +467,7 @@ function createVerificationObjects(signatureList, literalDataList, keys) { for (var i = 0; i < signatureList.length; i++) { var keyPacket = null; for (var j = 0; j < keys.length; j++) { - keyPacket = keys[j].getSigningKeyPacket(signatureList[i].issuerKeyId); + keyPacket = keys[j].getSigningKeyPacket(signatureList[i].issuerKeyId, config.verify_expired_keys); if (keyPacket) { break; }