From 2bda12731b50223d6515a516688a655e33d30bd9 Mon Sep 17 00:00:00 2001 From: Tom James Holub Date: Fri, 21 Jul 2017 21:38:33 -0700 Subject: [PATCH] subKey.bindingSignature -> subKey.bindingSignatures[] - process all | #527 --- src/key.js | 104 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/src/key.js b/src/key.js index e9c694a3..b99fd6db 100644 --- a/src/key.js +++ b/src/key.js @@ -130,7 +130,7 @@ Key.prototype.packetlist2structure = function(packetlist) { util.print_debug('Dropping subkey binding signature without preceding subkey packet'); continue; } - subKey.bindingSignature = packetlist[i]; + subKey.bindingSignatures.push(packetlist[i]); break; case enums.signature.key_revocation: this.revocationSignature = packetlist[i]; @@ -903,7 +903,7 @@ function SubKey(subKeyPacket) { return new SubKey(subKeyPacket); } this.subKey = subKeyPacket; - this.bindingSignature = null; + this.bindingSignatures = []; this.revocationSignature = null; } @@ -915,7 +915,9 @@ SubKey.prototype.toPacketlist = function() { var packetlist = new packet.List(); packetlist.push(this.subKey); packetlist.push(this.revocationSignature); - packetlist.push(this.bindingSignature); + for(var i = 0; i < this.bindingSignatures.length; i++) { + packetlist.push(this.bindingSignatures[i]); + } return packetlist; }; @@ -925,8 +927,15 @@ SubKey.prototype.toPacketlist = function() { * @return {Boolean} */ SubKey.prototype.isValidEncryptionKey = function(primaryKey) { - return this.verify(primaryKey) === enums.keyStatus.valid && - isValidEncryptionKeyPacket(this.subKey, this.bindingSignature); + if(this.verify(primaryKey) !== enums.keyStatus.valid) { + return false; + } + for(var i = 0; i < this.bindingSignatures.length; i++) { + if(isValidEncryptionKeyPacket(this.subKey, this.bindingSignatures[i])) { + return true; + } + } + return false; }; /** @@ -935,8 +944,15 @@ SubKey.prototype.isValidEncryptionKey = function(primaryKey) { * @return {Boolean} */ SubKey.prototype.isValidSigningKey = function(primaryKey) { - return this.verify(primaryKey) === enums.keyStatus.valid && - isValidSigningKeyPacket(this.subKey, this.bindingSignature); + if(this.verify(primaryKey) !== enums.keyStatus.valid) { + return false; + } + for(var i = 0; i < this.bindingSignatures.length; i++) { + if(isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i])) { + return true; + } + } + return false; }; /** @@ -956,24 +972,39 @@ SubKey.prototype.verify = function(primaryKey) { Date.now() > (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) { return enums.keyStatus.expired; } - // check subkey binding signature - if (!this.bindingSignature) { - return enums.keyStatus.invalid; + // check subkey binding signatures (at least one valid binding sig needed) + for(var i = 0; i < this.bindingSignatures.length; i++) { + var isLast = (i === this.bindingSignatures.length - 1); + var sig = this.bindingSignatures[i]; + // check binding signature is not expired + if(sig.isExpired()) { + if(isLast) { + return enums.keyStatus.expired; // last expired binding signature + } else { + continue; + } + } + // check binding signature can verify + if (!(sig.verified || sig.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) { + if(isLast) { + return enums.keyStatus.invalid; // last invalid binding signature + } else { + continue; + } + } + // check V4 expiration time + if (this.subKey.version === 4) { + if(sig.keyNeverExpires === false && Date.now() > (this.subKey.created.getTime() + sig.keyExpirationTime*1000)) { + if(isLast) { + return enums.keyStatus.expired; // last V4 expired binding signature + } else { + continue; + } + } + } + return enums.keyStatus.valid; // found a binding signature that passed all checks } - if (this.bindingSignature.isExpired()) { - return enums.keyStatus.expired; - } - if (!(this.bindingSignature.verified || - this.bindingSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) { - return enums.keyStatus.invalid; - } - // check V4 expiration time - if (this.subKey.version === 4 && - this.bindingSignature.keyNeverExpires === false && - Date.now() > (this.subKey.created.getTime() + this.bindingSignature.keyExpirationTime*1000)) { - return enums.keyStatus.expired; - } - return enums.keyStatus.valid; + return enums.keyStatus.invalid; // no binding signatures to check }; /** @@ -981,7 +1012,17 @@ SubKey.prototype.verify = function(primaryKey) { * @return {Date|null} */ SubKey.prototype.getExpirationTime = function() { - return getExpirationTime(this.subKey, this.bindingSignature); + var highest; + for(var i = 0; i < this.bindingSignatures.length; i++) { + var current = getExpirationTime(this.subKey, this.bindingSignatures[i]); + if(current === null) { + return null; + } + if(!highest || current > highest) { + highest = current; + } + } + return highest; }; /** @@ -1001,11 +1042,14 @@ SubKey.prototype.update = function(subKey, primaryKey) { subKey.subKey.tag === enums.packet.secretSubkey) { this.subKey = subKey.subKey; } - // binding signature - if (!this.bindingSignature && subKey.bindingSignature && - (subKey.bindingSignature.verified || - subKey.bindingSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) { - this.bindingSignature = subKey.bindingSignature; + // update missing binding signatures + if(this.bindingSignatures.length < subKey.bindingSignatures.length) { + for(var i = this.bindingSignatures.length; i < subKey.bindingSignatures.length; i++) { + var newSig = subKey.bindingSignatures[i]; + if (newSig.verified || newSig.verify(primaryKey, {key: primaryKey, bind: this.subKey})) { + this.bindingSignatures.push(newSig); + } + } } // revocation signature if (!this.revocationSignature && subKey.revocationSignature && !subKey.revocationSignature.isExpired() &&