Fixes problems with user certificate verification.

TODO: if using lower level functions, key.verifyPrimaryUser() MUST be
called and resolved before calling key.getSigning/EncryptionKeyPacket(),
key.getPrimaryUser(), etc.

Also: adds a flag to allow verification with expired keys from:
(cherry picked from commit b9d175d998)
(cherry picked from commit 50940b2a1e)
This commit is contained in:
Mahrud Sayrafi 2018-01-23 05:16:19 -08:00 committed by Sanjana Rajan
parent fa5805eaf7
commit d02b9c7bf0
4 changed files with 113 additions and 57 deletions

View File

@ -86,10 +86,15 @@ CleartextMessage.prototype.signDetached = async function(privateKeys) {
if (privateKey.isPublic()) {
throw new Error('Need private key for signing');
}
await privateKey.verifyPrimaryUser();
var signingKeyPacket = privateKey.getSigningKeyPacket();
if (!signingKeyPacket) {
throw new Error('Could not find valid key packet for signing in key ' +
privateKey.primaryKey.getKeyId().toHex());
}
var signaturePacket = new packet.Signature();
signaturePacket.signatureType = enums.signature.text;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
var signingKeyPacket = privateKey.getSigningKeyPacket();
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
if (!signingKeyPacket.isDecrypted) {
throw new Error('Private key is not decrypted.');
@ -124,12 +129,13 @@ CleartextMessage.prototype.verifyDetached = function(signature, keys) {
literalDataPacket.setText(this.text);
return Promise.all(signatureList.map(async function(signature) {
var keyPacket = null;
for (var j = 0; j < keys.length; j++) {
keyPacket = keys[j].getSigningKeyPacket(signature.issuerKeyId);
if (keyPacket) {
break;
await Promise.all(keys.map(async function(key) {
await key.verifyPrimaryUser();
var result = key.getSigningKeyPacket(signature.issuerKeyId, config.verify_expired_keys);
if (result) {
keyPacket = result;
}
}
}));
var verifiedSig = {};
if (keyPacket) {

View File

@ -742,7 +742,9 @@ describe('Key', function() {
var pubKey = openpgp.key.readArmored(twoKeys).keys[1];
expect(pubKey).to.exist;
expect(pubKey).to.be.an.instanceof(openpgp.key.Key);
expect(pubKey.getExpirationTime().toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
return pubKey.verifyPrimaryUser().then(() => {
expect(pubKey.getExpirationTime().toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
});
});
it('Method getExpirationTime V4 SubKey', function() {
@ -890,26 +892,32 @@ describe('Key', function() {
it('getPreferredSymAlgo() - one key - AES256', function() {
var key1 = openpgp.key.readArmored(twoKeys).keys[0];
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
return key1.verifyPrimaryUser().then(() => {
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
});
});
it('getPreferredSymAlgo() - two key - AES128', function() {
var keys = openpgp.key.readArmored(twoKeys).keys;
var key1 = keys[0];
var key2 = keys[1];
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = [6,7,3];
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128);
return Promise.all([key1.verifyPrimaryUser(), key2.verifyPrimaryUser()]).then(() => {
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = [6,7,3];
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128);
});
});
it('getPreferredSymAlgo() - two key - one without pref', function() {
var keys = openpgp.key.readArmored(twoKeys).keys;
var key1 = keys[0];
var key2 = keys[1];
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = null;
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.encryption_cipher);
return Promise.all([key1.verifyPrimaryUser(), key2.verifyPrimaryUser()]).then(() => {
key2.getPrimaryUser().selfCertificate.preferredSymmetricAlgorithms = null;
var prefAlgo = openpgp.key.getPreferredSymAlgo([key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.encryption_cipher);
});
});
it('Preferences of generated key', function() {
@ -944,10 +952,12 @@ describe('Key', function() {
it('getPrimaryUser()', function() {
var key = openpgp.key.readArmored(pub_sig_test).keys[0];
var primUser = key.getPrimaryUser();
expect(primUser).to.exist;
expect(primUser.user.userId.userid).to.equal('Signature Test <signature@test.com>');
expect(primUser.selfCertificate).to.be.an.instanceof(openpgp.packet.Signature);
return key.verifyPrimaryUser().then(() => {
var primUser = key.getPrimaryUser();
expect(primUser).to.exist;
expect(primUser.user.userId.userid).to.equal('Signature Test <signature@test.com>');
expect(primUser.selfCertificate).to.be.an.instanceof(openpgp.packet.Signature);
});
});
it('Generated key is not unlocked by default', function() {
@ -1020,59 +1030,68 @@ describe('Key', function() {
return openpgp.generateKey(opt).then(function(key) {
key = key.key;
var expiration = key.getExpirationTime();
expect(expiration).to.exist;
return key.verifyPrimaryUser().then(() => {
var expiration = key.getExpirationTime();
expect(expiration).to.exist;
var actual_delta = (new Date(expiration) - new Date()) / 1000;
expect(Math.abs(actual_delta - expect_delta)).to.be.below(60);
var actual_delta = (new Date(expiration) - new Date()) / 1000;
expect(Math.abs(actual_delta - expect_delta)).to.be.below(60);
var subKeyExpiration = key.subKeys[0].getExpirationTime();
expect(subKeyExpiration).to.exist;
var subKeyExpiration = key.subKeys[0].getExpirationTime();
expect(subKeyExpiration).to.exist;
var actual_subKeyDelta = (new Date(subKeyExpiration) - new Date()) / 1000;
expect(Math.abs(actual_subKeyDelta - expect_delta)).to.be.below(60);
var actual_subKeyDelta = (new Date(subKeyExpiration) - new Date()) / 1000;
expect(Math.abs(actual_subKeyDelta - expect_delta)).to.be.below(60);
});
});
});
it('Sign and verify key - primary user', function(done) {
it('Sign and verify key - primary user', function() {
var key = openpgp.key.readArmored(pub_sig_test).keys[0];
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
privateKey.decrypt('hello world');
key.signPrimaryUser([privateKey]).then(key => {
key.verifyPrimaryUser([privateKey]).then(signatures => {
return key.signPrimaryUser([privateKey]).then(key => {
return Promise.all(
[key.verifyPrimaryUser([privateKey]), privateKey.verifyPrimaryUser()]
).then(results => {
var signatures = results[0];
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
done();
});
});
});
it('Sign key and verify with wrong key - primary user', function(done) {
it('Sign key and verify with wrong key - primary user', function() {
var key = openpgp.key.readArmored(pub_sig_test).keys[0];
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
var wrongKey = openpgp.key.readArmored(wrong_key).keys[0];
privateKey.decrypt('hello world');
key.signPrimaryUser([privateKey]).then(key => {
key.verifyPrimaryUser([wrongKey]).then(signatures => {
return key.signPrimaryUser([privateKey]).then(key => {
return Promise.all(
[key.verifyPrimaryUser([wrongKey]), privateKey.verifyPrimaryUser()]
).then(results => {
var signatures = results[0];
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.null;
done();
});
});
});
it('Sign and verify key - all users', function(done) {
it('Sign and verify key - all users', function() {
var key = openpgp.key.readArmored(multi_uid_key).keys[0];
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
privateKey.decrypt('hello world');
key.signAllUsers([privateKey]).then(key => {
key.verifyAllUsers([privateKey]).then(signatures => {
return key.signAllUsers([privateKey]).then(key => {
return Promise.all(
[key.verifyAllUsers([privateKey]), key.verifyPrimaryUser(), privateKey.verifyPrimaryUser()]
).then(results => {
var signatures = results[0];
expect(signatures.length).to.equal(4);
expect(signatures[0].userid).to.equal(key.users[0].userId.userid);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
@ -1086,18 +1105,20 @@ describe('Key', function() {
expect(signatures[3].userid).to.equal(key.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[3].valid).to.be.true;
done();
});
});
});
it('Sign key and verify with wrong key - all users', function(done) {
it('Sign key and verify with wrong key - all users', function() {
var key = openpgp.key.readArmored(multi_uid_key).keys[0];
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
var wrongKey = openpgp.key.readArmored(wrong_key).keys[0];
privateKey.decrypt('hello world');
key.signAllUsers([privateKey]).then(key => {
key.verifyAllUsers([wrongKey]).then(signatures => {
return key.signAllUsers([privateKey]).then(key => {
return Promise.all(
[key.verifyAllUsers([wrongKey]), key.verifyPrimaryUser(), privateKey.verifyPrimaryUser()]
).then(results => {
var signatures = results[0];
expect(signatures.length).to.equal(4);
expect(signatures[0].userid).to.equal(key.users[0].userId.userid);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
@ -1111,7 +1132,6 @@ describe('Key', function() {
expect(signatures[3].userid).to.equal(key.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[3].valid).to.be.null;
done();
});
});
});

View File

@ -405,7 +405,7 @@ describe('OpenPGP.js public api tests', function() {
describe('encrypt, decrypt, sign, verify - integration tests', function() {
var privateKey, publicKey, zero_copyVal, use_nativeVal, aead_protectVal;
beforeEach(function() {
beforeEach(function(done) {
publicKey = openpgp.key.readArmored(pub_key);
expect(publicKey.keys).to.have.length(1);
expect(publicKey.err).to.not.exist;
@ -415,6 +415,7 @@ describe('OpenPGP.js public api tests', function() {
zero_copyVal = openpgp.config.zero_copy;
use_nativeVal = openpgp.config.use_native;
aead_protectVal = openpgp.config.aead_protect;
privateKey.keys[0].verifyPrimaryUser().then(() => done());
});
afterEach(function() {
@ -515,8 +516,9 @@ describe('OpenPGP.js public api tests', function() {
describe('encryptSessionKey, decryptSessionKey', function() {
var sk = new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]);
beforeEach(function() {
beforeEach(function(done) {
expect(privateKey.keys[0].decrypt(passphrase)).to.be.true;
privateKey.keys[0].verifyPrimaryUser().then(() => done());
});
it('should encrypt with public key', function() {
@ -609,8 +611,9 @@ describe('OpenPGP.js public api tests', function() {
'=6XMW\r\n' +
'-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n';
beforeEach(function() {
beforeEach(function(done) {
expect(privateKey.keys[0].decrypt(passphrase)).to.be.true;
privateKey.keys[0].verifyPrimaryUser().then(() => done());
});
it('should encrypt then decrypt', function() {
@ -830,8 +833,10 @@ describe('OpenPGP.js public api tests', function() {
expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
expect(decrypted.signatures[1].valid).to.be.true;
expect(decrypted.signatures[1].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[1].signature.packets.length).to.equal(1);
return privKeyDE.verifyPrimaryUser().then(() => {
expect(decrypted.signatures[1].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[1].signature.packets.length).to.equal(1);
});
});
});
@ -1127,8 +1132,10 @@ describe('OpenPGP.js public api tests', function() {
expect(encrypted.data).to.exist;
expect(encrypted.data).to.equal(plaintext);
expect(encrypted.signatures[0].valid).to.be.true;
expect(encrypted.signatures[0].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex());
expect(encrypted.signatures[0].signature.packets.length).to.equal(1);
return privKeyDE.verifyPrimaryUser().then(() => {
expect(encrypted.signatures[0].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex());
expect(encrypted.signatures[0].signature.packets.length).to.equal(1);
});
});
});
});

View File

@ -432,7 +432,7 @@ describe("Signature", function() {
var sMsg = openpgp.message.readArmored(signedArmor);
var pub_key = openpgp.key.readArmored(pub_key_arm2).keys[0];
sMsg.verify([pub_key]).then(verified => {
return sMsg.verify([pub_key]).then(verified => {
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.be.true;
@ -544,7 +544,7 @@ describe("Signature", function() {
expect(sMsg.getText()).to.equal(plaintext);
sMsg.verify([pubKey2, pubKey3]).then(verifiedSig => {
return sMsg.verify([pubKey2, pubKey3]).then(verifiedSig => {
expect(verifiedSig).to.exist;
expect(verifiedSig).to.have.length(2);
expect(verifiedSig[0].valid).to.be.true;
@ -604,7 +604,7 @@ describe("Signature", function() {
var plaintext = 'short message\nnext line\n한국어/조선말';
var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0];
var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0];
privKey.getSigningKeyPacket().decrypt('hello world');
privKey.primaryKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], data:plaintext }).then(function(signed) {
@ -618,14 +618,13 @@ describe("Signature", function() {
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
});
});
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same bytes cleartext and valid signatures - armored', function() {
var plaintext = openpgp.util.str2Uint8Array('short message\nnext line\n한국어/조선말');
var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0];
var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0];
privKey.getSigningKeyPacket().decrypt('hello world');
privKey.primaryKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], data:plaintext }).then(function(signed) {
@ -639,14 +638,13 @@ describe("Signature", function() {
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
});
});
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same bytes cleartext and valid signatures - not armored', function() {
var plaintext = openpgp.util.str2Uint8Array('short message\nnext line\n한국어/조선말');
var pubKey = openpgp.key.readArmored(pub_key_arm2).keys[0];
var privKey = openpgp.key.readArmored(priv_key_arm2).keys[0];
privKey.getSigningKeyPacket().decrypt('hello world');
privKey.primaryKey.decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], data:plaintext, armor:false }).then(function(signed) {
@ -660,6 +658,31 @@ describe("Signature", function() {
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
});
});
it('Verify test with expired verification public key and verify_expired_keys set to false', function() {
openpgp.config.verify_expired_keys = false;
var pubKey = openpgp.key.readArmored(pub_expired).keys[0];
var message = openpgp.message.readArmored(msg_sig_expired);
return openpgp.verify({ publicKeys:[pubKey], message:message }).then(function(verified) {
expect(verified).to.exist;
expect(verified.signatures).to.have.length(1);
expect(verified.signatures[0].valid).to.not.be.true;
expect(verified.signatures[0].signature.packets.length).to.equal(1);
});
});
it('Verify test with expired verification public key and verify_expired_keys set to true', function() {
openpgp.config.verify_expired_keys = true;
var pubKey = openpgp.key.readArmored(pub_expired).keys[0];
var message = openpgp.message.readArmored(msg_sig_expired);
return openpgp.verify({ publicKeys:[pubKey], message:message }).then(function(verified) {
expect(verified).to.exist;
expect(verified.signatures).to.have.length(1);
expect(verified.signatures[0].valid).to.be.true;
expect(verified.signatures[0].signature.packets.length).to.equal(1);
});
});