Skip to content

Commit 29d2b70

Browse files
martgiltwiss
andauthored
Add support for verifying User Attributes in verifyAllUsers (#1637)
Previously, `verifyAllUsers` would fail on keys with User Attributes. Now, it returns a list of objects that have a either a non-null `userID` property (in the case of User IDs) or a non-null `userAttribute` property that contains the User Attribute packet. Co-authored-by: Daniel Huigens <[email protected]>
1 parent 785d24d commit 29d2b70

2 files changed

Lines changed: 169 additions & 1 deletion

File tree

src/key/key.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,8 @@ class Key {
692692

693693
results.push(...signatures.map(
694694
signature => ({
695-
userID: user.userID.userID,
695+
userID: user.userID ? user.userID.userID : null,
696+
userAttribute: user.userAttribute,
696697
keyID: signature.keyID,
697698
valid: signature.valid
698699
}))

test/general/key.js

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,6 +2123,100 @@ Be4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ==
21232123
=ZeAz
21242124
-----END PGP PUBLIC KEY BLOCK-----`;
21252125

2126+
const keyWithImageData = `-----BEGIN PGP PUBLIC KEY BLOCK-----
2127+
2128+
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
2217+
=kUWS
2218+
-----END PGP PUBLIC KEY BLOCK-----`;
2219+
21262220
function versionSpecificTests() {
21272221
it('Preferences of generated key', function() {
21282222
const testPref = function(key) {
@@ -2553,6 +2647,79 @@ function versionSpecificTests() {
25532647
}
25542648
});
25552649

2650+
it('Sign and verify a key with user attribute - all users', async function () {
2651+
let publicKey = await openpgp.readKey({ armoredKey: keyWithImageData });
2652+
const privateKey = await openpgp.decryptKey({
2653+
privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
2654+
passphrase: 'hello world'
2655+
});
2656+
2657+
const { minRSABits } = openpgp.config;
2658+
openpgp.config.minRSABits = 1024;
2659+
try {
2660+
publicKey = await publicKey.signAllUsers([privateKey]);
2661+
const signatures = await publicKey.verifyAllUsers([privateKey]);
2662+
const publicSigningKey = await publicKey.getSigningKey();
2663+
const privateSigningKey = await privateKey.getSigningKey();
2664+
expect(signatures.length).to.equal(4);
2665+
expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID);
2666+
expect(signatures[0].userAttribute).to.be.null;
2667+
expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
2668+
expect(signatures[0].valid).to.be.null;
2669+
expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID);
2670+
expect(signatures[1].userAttribute).to.be.null;
2671+
expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
2672+
expect(signatures[1].valid).to.be.true;
2673+
expect(signatures[2].userID).to.be.null;
2674+
expect(signatures[2].userAttribute.attributes[0]).to.be.not.empty;
2675+
expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
2676+
expect(signatures[2].valid).to.be.null;
2677+
expect(signatures[3].userID).to.be.null;
2678+
expect(signatures[3].userAttribute.attributes[0]).to.be.not.empty;
2679+
expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
2680+
expect(signatures[3].valid).to.be.true;
2681+
} finally {
2682+
openpgp.config.minRSABits = minRSABits;
2683+
}
2684+
});
2685+
2686+
it('Sign and verify a key with user attribute using wrong key - all users', async function () {
2687+
let publicKey = await openpgp.readKey({ armoredKey: keyWithImageData });
2688+
const privateKey = await openpgp.decryptKey({
2689+
privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
2690+
passphrase: 'hello world'
2691+
});
2692+
const wrongKey = await openpgp.readKey({ armoredKey: wrong_key });
2693+
2694+
const { minRSABits } = openpgp.config;
2695+
openpgp.config.minRSABits = 1024;
2696+
try {
2697+
publicKey = await publicKey.signAllUsers([privateKey]);
2698+
const signatures = await publicKey.verifyAllUsers([wrongKey]);
2699+
const publicSigningKey = await publicKey.getSigningKey();
2700+
const privateSigningKey = await privateKey.getSigningKey();
2701+
expect(signatures.length).to.equal(4);
2702+
expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID);
2703+
expect(signatures[0].userAttribute).to.be.null;
2704+
expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
2705+
expect(signatures[0].valid).to.be.null;
2706+
expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID);
2707+
expect(signatures[1].userAttribute).to.be.null;
2708+
expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
2709+
expect(signatures[1].valid).to.be.null;
2710+
expect(signatures[2].userID).to.be.null;
2711+
expect(signatures[2].userAttribute.attributes[0]).to.be.not.empty;
2712+
expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
2713+
expect(signatures[2].valid).to.be.null;
2714+
expect(signatures[3].userID).to.be.null;
2715+
expect(signatures[3].userAttribute.attributes[0]).to.be.not.empty;
2716+
expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
2717+
expect(signatures[3].valid).to.be.null;
2718+
} finally {
2719+
openpgp.config.minRSABits = minRSABits;
2720+
}
2721+
});
2722+
25562723
it('Reformat and encrypt key with no subkey', async function() {
25572724
const userID = { name: 'test', email: '[email protected]' };
25582725
const key = await openpgp.readKey({ armoredKey: key_without_subkey });

0 commit comments

Comments
 (0)