Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added PGP verify operation #585

Merged
merged 2 commits into from
Jul 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/core/operations/PGPDecryptAndVerify.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,17 @@ class PGPDecryptAndVerify extends Operation {
text += `${signer.username} `;
}
if (signer.comment) {
text += `${signer.comment} `;
text += `(${signer.comment}) `;
}
if (signer.email) {
text += `<${signer.email}>`;
}
text += "\n";
}
text += [
`PGP key ID: ${km.get_pgp_short_key_id()}`,
`PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`,
`Signed on ${new Date(ds.sig.hashed_subpackets[0].time * 1000).toUTCString()}`,
`Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`,
"----------------------------------\n"
].join("\n");
text += unboxedLiterals.toString();
Expand Down
111 changes: 111 additions & 0 deletions src/core/operations/PGPVerify.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/

import Operation from "../Operation";
import OperationError from "../errors/OperationError";

import kbpgp from "kbpgp";
import { ASP, importPublicKey } from "../lib/PGP";
import * as es6promisify from "es6-promisify";
const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;

/**
* PGP Verify operation
*/
class PGPVerify extends Operation {

/**
* PGPVerify constructor
*/
constructor() {
super();

this.name = "PGP Verify";
this.module = "PGP";
this.description = [
"Input: the ASCII-armoured encrypted PGP message you want to verify.",
"<br><br>",
"Argument: the ASCII-armoured PGP public key of the signer",
"<br><br>",
"This operation uses PGP to decrypt a clearsigned message.",
"<br><br>",
"Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
"<br><br>",
"This function uses the Keybase implementation of PGP.",
].join("\n");
this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Public key of signer",
"type": "text",
"value": ""
}
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const signedMessage = input,
[publicKey] = args,
keyring = new kbpgp.keyring.KeyRing();
let unboxedLiterals;

if (!publicKey) throw new OperationError("Enter the public key of the signer.");
const pubKey = await importPublicKey(publicKey);
keyring.add_key_manager(pubKey);

try {
unboxedLiterals = await promisify(kbpgp.unbox)({
armored: signedMessage,
keyfetch: keyring,
asp: ASP
});
const ds = unboxedLiterals[0].get_data_signer();
if (ds) {
const km = ds.get_key_manager();
if (km) {
const signer = km.get_userids_mark_primary()[0].components;
let text = "Signed by ";
if (signer.email || signer.username || signer.comment) {
if (signer.username) {
text += `${signer.username} `;
}
if (signer.comment) {
text += `(${signer.comment}) `;
}
if (signer.email) {
text += `<${signer.email}>`;
}
text += "\n";
}
text += [
`PGP key ID: ${km.get_pgp_short_key_id()}`,
`PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`,
`Signed on ${new Date(ds.sig.when_generated() * 1000).toUTCString()}`,
"----------------------------------\n"
].join("\n");
text += unboxedLiterals.toString();
return text.trim();
} else {
throw new OperationError("Could not identify a key manager.");
}
} else {
throw new OperationError("The data does not appear to be signed.");
}
} catch (err) {
throw new OperationError(`Couldn't verify message: ${err}`);
}
}

}

export default PGPVerify;
29 changes: 28 additions & 1 deletion tests/operations/tests/PGP.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ IOE1W/Zqmqzq+4frwnzWwYv9/U1RwIs/qlFVnzliREOzW+om8EncSSd7fQ==
=fEAT
-----END PGP MESSAGE-----
`,
expectedOutput: `Signed by PGP fingerprint: e94e06dd0b3744a0e970de9d84246548df98e485
expectedOutput: `Signed by PGP key ID: DF98E485
PGP fingerprint: e94e06dd0b3744a0e970de9d84246548df98e485
Signed on Tue, 29 May 2018 15:44:52 GMT
----------------------------------
${UTF8_TEXT}`,
Expand Down Expand Up @@ -282,4 +283,30 @@ H2qMY1O7hezH3fp+EZzCAccJMtK7VPk13WAgMRH22HirG4aK1i75IVOtjBgObzDh
}
]
},
{
name: "PGP Verify: ASCII, Alice",
input: `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.
-----BEGIN PGP SIGNATURE-----
iLMEAQEIAB0WIQRLbJy6MLpYOr9qojE+2VNAUiMLOgUCXRTsvwAKCRA+2VNAUiML
OuaHBADMMNtsuN92Fb+UrDimsv6TDQpbJhDkwp9kZdKYP5HAmSYAhXBG7N+YCMw+
v2FSpUu9jJiPBm1K1SEwLufQVexoRv6RsBNolRFB07sArau0s0DnIXUchCZWvyTP
1KsjBnDr84U2b11H58g4DlTT4gQrz30rFuHz9AGmPAtDHbSXIA==
=vnk/
-----END PGP SIGNATURE-----`,
expectedOutput: `Signed by PGP key ID: DF98E485
PGP fingerprint: e94e06dd0b3744a0e970de9d84246548df98e485
Signed on Thu, 27 Jun 2019 16:20:15 GMT
----------------------------------
A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools.`,
recipeConfig: [
{
"op": "PGP Verify",
"args": [ALICE_PUBLIC]
}
]
}
]);