Skip to content

Commit fae80ef

Browse files
committed
JBDS-4330 PGP ASCII armored clearsighn signature verification
1 parent 27efa49 commit fae80ef

2 files changed

Lines changed: 149 additions & 0 deletions

File tree

browser/services/openpgp.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const openpgp = require('openpgp'); // use as CommonJS, AMD, ES6 module or via window.openpgp
2+
3+
openpgp.config.aead_protect = true; // activate fast AES-GCM mode (not yet OpenPGP standard)
4+
5+
/**
6+
* Gets ASCII armored clearsign message and returns object
7+
* {
8+
* text - text from the message
9+
* valid - verification status
10+
* error - error occured during verification
11+
* }
12+
*/
13+
function loadSignedText(keyText, armoredText) {
14+
return Promise.resolve().then(()=>{
15+
let options = {
16+
message: openpgp.cleartext.readArmored(armoredText), // parse armored message
17+
publicKeys: openpgp.key.readArmored(keyText).keys // for verification
18+
};
19+
return openpgp.verify(options).then((verified)=>{
20+
return {options, verified};
21+
});
22+
}).catch((error)=>{
23+
return Promise.resolve({
24+
options: {
25+
message: {
26+
text: armoredText
27+
},
28+
},
29+
verified: {
30+
signatures: [{
31+
valid: undefined
32+
}]
33+
},
34+
error
35+
});
36+
}).then(function({options, verified, error}) {
37+
return {
38+
text: options.message.text,
39+
valid: verified.signatures[0].valid,
40+
error
41+
};
42+
});
43+
}
44+
45+
module.exports = loadSignedText;

test/unit/services/openpgp-test.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict';
2+
3+
import chai, { expect } from 'chai';
4+
import 'sinon';
5+
import { default as sinonChai } from 'sinon-chai';
6+
chai.use(sinonChai);
7+
import loadSignedText from 'browser/services/openpgp';
8+
9+
let publicKey =
10+
`-----BEGIN PGP PUBLIC KEY BLOCK-----
11+
12+
mQENBFl45PABCADa3JMtyxLpEvxiqFsqM0D7p+R5bG4WDUW2Gf3A4olL3Ba1dMbY
13+
XuVKN2VVWF0eaX/kkPFWFQQ/zUbBR5A8BcCzWrVNm7NvbSxkwqS8U8imc+0QYz6f
14+
RQfYvzGaN3rg2EJ4XiGy5M7nVoPmwk9xqbhJxxv3d507oPDN1FOnoTY68Y+GbiUM
15+
HF3mFlBtQwxhGxlFhwPABmHypfeBCk36s0TzzvAekNcT8ROuWM+68KjtZEbizQ4J
16+
0ZYeLixdTyN3em4ve+hFFjiQOZbh5PKzrSP8nw1EFoAdHnefO/2vUe6pp3G8y8CB
17+
zlT2ZU2kuFsP7I5HeZoGi4DbbXgJyqhp4jGrABEBAAG0S0RlbmlzIEdvbG92aW4g
18+
KFRlc3Qgc2lnbmluZyBhbmQgdmVyaWZ5aW5nIHRleHQgZmlsZXMpIDxkZ29sb3Zp
19+
bkByZWRoYXQuY29tPokBOAQTAQIAIgUCWXjk8AIbAwYLCQgHAwIGFQgCCQoLBBYC
20+
AwECHgECF4AACgkQHrpirkCkMkpT6gf+LwCUJRHpL/V2z8A2ZDbf8nT/9AIOmpdq
21+
z/mUj3kJUbrPTel7jel2qAqCDC7/BySPVjToqfX/Ww8yiq48j9xtWOenPb52QO0S
22+
zBdxnFUK/zS4Iij60aBamWOSkCw/cYmze93bttvaAiqgArnPD32rWTHDF9ruosAm
23+
N7/ymBYbyoBwcGklnShl4lahW7OBuDCFejn+8Wz5NZAzG05OXdwjMGnslCsjyRLb
24+
i7VfgRBgHbGCMIcrwn7VrMbYgIx/yEoyr8jwGLiK0ucdEqAH8GdBQJStEL58TReE
25+
/StWaVC81U5dgZaedSdGlNLQacXltmuJpg2Lcpj8v22aneLFBkThYLkBDQRZeOTw
26+
AQgA7DuKmKOOJ8iSAl+cI4OcS6kwowxMZKnR4eS/QVJYUMCw+WxdQprhakGUcoo2
27+
9EiyxwvXrp/RNFIzPYJ8frRYKrfPMY0ginpvKKNFnU7/INjHn7EnQkpJjAK15A+f
28+
QdKhvetBvU1I3CB4xHGjmYdMOySGnaNHZQu1dmkdBiDT4o66H4bu0H3J956QhQr8
29+
7r9fYf2Qd9Lfw+a3or5O0Dcag1bHtUOx8B/cw3dXK/TFa+/ECQbeqA3pn4WQfsoH
30+
ZvBUAvE+nCABJg9lXDrtyhzIlha9fvk/vUguo0tZ1XW5YCkeNVWqig/Ju8eydUHc
31+
7FClF1rJ9TTZBoZoNO9O51FtxwARAQABiQEfBBgBAgAJBQJZeOTwAhsMAAoJEB66
32+
Yq5ApDJKnJIH/3ldHeikhjDIJOno+DMKBs9iGpSl3PZI9qXBXxb13KTGAwCkcIja
33+
fc4Bn6w/dKoa5CumYHr4Uf5VrGxvRFyCkiA3YZ6/EarYpWaEAO179qYeGuwiCMuV
34+
ihUuCGhXKsl8sig4j1YMyGg058HgZov81yLnPHBeLpTsFRj/7SPT0eJjWyZmK3dS
35+
zMlxS8jFPEeBPA7EI4bDQCdg/kBK9C89s2xmZOxz3PtCzoMtj9KICvLzCf0OX1hR
36+
Y8WRZUzrkAkouuli0sfWGIsHSEPFCrNdKdoIud0Klrc/ATMD0tDjz7MEl7brEC08
37+
vRYoPDOBq3YXZ0LdaZwVObM7KV0Ncw2YWg4=
38+
=uZLc
39+
-----END PGP PUBLIC KEY BLOCK-----
40+
`;
41+
42+
let validText = 'message';
43+
44+
let validClearsignMessage = `-----BEGIN PGP SIGNED MESSAGE-----
45+
Hash: SHA1
46+
47+
${validText}
48+
-----BEGIN PGP SIGNATURE-----
49+
50+
iQEcBAEBAgAGBQJZepDRAAoJEB66Yq5ApDJKuq0H/0+VsT3mHuFTh+FKyt41HyiK
51+
Q33ILdJYT4TtTu7M0teWR6TJtl0K6bHbSP7Z9wQcMmkgnHJzpZPxIwUgvKczQeXZ
52+
q8+D7t0k/G8X+LgLOY/69zjILIU3NGAV0bVYE77hI45uJCYZCdja5OVsbU7i17Hn
53+
jeqX+3shBCBtdo1lOPPSPagkbxEq6T86SKhMdY47UUJhIQ6tDYg3W+Kb1aVjjwlN
54+
LO3H861OaD3fHWTg2azY6woFr0mu0Fq68a/rpsEUGuXagtdoZaE+VP1SrsIpuPZM
55+
9lrN/Ml1q4GNhtoiggefuxXwKLhgXwkDYM3wSwtmKxqh4Z4fAkO17Gk+CeU71x8=
56+
=w6uW
57+
-----END PGP SIGNATURE-----
58+
`;
59+
60+
let invalidText = `altered message`;
61+
62+
let invalidClearsignMessage = `-----BEGIN PGP SIGNED MESSAGE-----
63+
Hash: SHA1
64+
65+
${invalidText}
66+
-----BEGIN PGP SIGNATURE-----
67+
68+
iQEcBAEBAgAGBQJZeoQxAAoJEB66Yq5ApDJK5usH/2qkKG5XTj/T9wWsGu/v0MHH
69+
12+2gANlC1EQ32CoL9uXCysD7inERvm57jmLkQ0ZXvxFUGU6WUKrWUHoX5NC+r6Z
70+
evXS46e+naO+tEAh+lX7ySf/1gzjql6VXIJyvT48nHoRHqaBnI1hpqJNdwB+QwKT
71+
Sj0xTdgQGZc/yw986wo/g6ZQpmkXU65nWAT7zW5scA5BCwr4+18pjPQngWmEQO3T
72+
FVxwE4bk/i7FxdlK6wRCYqiIw/Li5r6SaFKJQQC4nIpI3oOqkE/KVrgtmHAWTPvg
73+
8kPyXpmtuQuLWUmXCJEsjujdIK6OT2aOpB7Ishw6GnVHgdyPklb7TlpuBo3gGYs=
74+
=H66B
75+
-----END PGP SIGNATURE-----
76+
`;
77+
78+
let messageWithoutSignature = 'messsage without signature';
79+
80+
describe('OpenPGP', function() {
81+
describe('loadSignedText', function() {
82+
it('for valid signed file returns text without signature, valid equals true and no errors', function() {
83+
return loadSignedText(publicKey, validClearsignMessage).then(({text, valid, error})=>{
84+
expect(text.trim()).equals(validText);
85+
expect(valid).to.be.true;
86+
expect(error).to.be.undefined;
87+
});
88+
});
89+
it('for altered signed file returns text without signature, valid equals false and no errors', function() {
90+
return loadSignedText(publicKey, invalidClearsignMessage).then(({text, valid, error})=>{
91+
expect(text.trim()).equals(invalidText);
92+
expect(valid).to.be.false;
93+
expect(error).to.be.undefined;
94+
});
95+
});
96+
it('for unsigned text returns text itself, valid equals undefined and error is not undefined', function() {
97+
return loadSignedText(publicKey, messageWithoutSignature).then(({text, valid, error})=>{
98+
expect(text.trim()).equals(messageWithoutSignature);
99+
expect(valid).to.be.undefined;
100+
expect(error).not.to.be.undefined;
101+
});
102+
});
103+
});
104+
});

0 commit comments

Comments
 (0)