浏览代码

Merge branch 'GCHQ77703-jwt'

n1474335 6 年之前
父节点
当前提交
5dde1c1c04

+ 3 - 3
Gruntfile.js

@@ -382,13 +382,13 @@ module.exports = function (grunt) {
                     "mkdir -p src/core/config/modules",
                     "echo 'export default {};\n' > src/core/config/modules/OpModules.mjs",
                     "echo '[]\n' > src/core/config/OperationConfig.json",
-                    "node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs",
-                    "node --experimental-modules src/core/config/scripts/generateConfig.mjs",
+                    "node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
+                    "node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
                     "echo '--- Config scripts finished. ---\n'"
                 ].join(";")
             },
             tests: {
-                command: "node --experimental-modules test/index.mjs"
+                command: "node --experimental-modules --no-warnings --no-deprecation test/index.mjs"
             }
         },
     });

+ 83 - 6
package-lock.json

@@ -1811,6 +1811,11 @@
         "isarray": "^1.0.0"
       }
     },
+    "buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+      "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+    },
     "buffer-from": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -2994,6 +2999,14 @@
         }
       }
     },
+    "ecdsa-sig-formatter": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz",
+      "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=",
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -6493,6 +6506,29 @@
         }
       }
     },
+    "jsonwebtoken": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz",
+      "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==",
+      "requires": {
+        "jws": "^3.1.5",
+        "lodash.includes": "^4.3.0",
+        "lodash.isboolean": "^3.0.3",
+        "lodash.isinteger": "^4.0.4",
+        "lodash.isnumber": "^3.0.3",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.isstring": "^4.0.1",
+        "lodash.once": "^4.0.0",
+        "ms": "^2.1.1"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+        }
+      }
+    },
     "jsprim": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -6510,6 +6546,25 @@
       "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-8.0.12.tgz",
       "integrity": "sha1-Iqu5ZW00owuVMENnIINeicLlwxY="
     },
+    "jwa": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz",
+      "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==",
+      "requires": {
+        "buffer-equal-constant-time": "1.0.1",
+        "ecdsa-sig-formatter": "1.0.10",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "jws": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz",
+      "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==",
+      "requires": {
+        "jwa": "^1.1.5",
+        "safe-buffer": "^5.0.1"
+      }
+    },
     "kbpgp": {
       "version": "2.0.77",
       "resolved": "https://registry.npmjs.org/kbpgp/-/kbpgp-2.0.77.tgz",
@@ -6724,17 +6779,35 @@
       "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=",
       "dev": true
     },
+    "lodash.includes": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+      "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+    },
+    "lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+    },
+    "lodash.isinteger": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+      "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+    },
+    "lodash.isnumber": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+      "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+    },
     "lodash.isplainobject": {
       "version": "4.0.6",
       "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
-      "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
-      "dev": true
+      "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
     },
     "lodash.isstring": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
-      "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
-      "dev": true
+      "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
     },
     "lodash.mergewith": {
       "version": "4.6.1",
@@ -6742,6 +6815,11 @@
       "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==",
       "dev": true
     },
+    "lodash.once": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+      "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+    },
     "lodash.sortby": {
       "version": "4.7.0",
       "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -9118,8 +9196,7 @@
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "dev": true
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
     },
     "safe-json-parse": {
       "version": "1.0.1",

+ 1 - 0
package.json

@@ -99,6 +99,7 @@
     "jsbn": "^1.1.0",
     "jsesc": "^2.5.1",
     "jsonpath": "^1.0.0",
+    "jsonwebtoken": "^8.3.0",
     "jsrsasign": "8.0.12",
     "kbpgp": "^2.0.77",
     "lodash": "^4.17.10",

+ 3 - 0
src/core/config/Categories.json

@@ -89,6 +89,9 @@
             "Derive EVP key",
             "Bcrypt",
             "Scrypt",
+            "JWT Sign",
+            "JWT Verify",
+            "JWT Decode",
             "Pseudo-Random Number Generator"
         ]
     },

+ 51 - 0
src/core/operations/JWTDecode.mjs

@@ -0,0 +1,51 @@
+/**
+ * @author gchq77703 []
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import jwt from "jsonwebtoken";
+import OperationError from "../errors/OperationError";
+
+/**
+ * JWT Decode operation
+ */
+class JWTDecode extends Operation {
+
+    /**
+     * JWTDecode constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "JWT Decode";
+        this.module = "Crypto";
+        this.description = "Decodes a JSON Web Token <b>without</b> checking whether the provided secret / private key is valid. Use 'JWT Verify' to check if the signature is valid as well.";
+        this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
+        this.inputType = "string";
+        this.outputType = "JSON";
+        this.args = [];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {JSON}
+     */
+    run(input, args) {
+        try {
+            const decoded = jwt.decode(input, {
+                json: true,
+                complete: true
+            });
+
+            return decoded.payload;
+        } catch (err) {
+            throw new OperationError(err);
+        }
+    }
+
+}
+
+export default JWTDecode;

+ 74 - 0
src/core/operations/JWTSign.mjs

@@ -0,0 +1,74 @@
+/**
+ * @author gchq77703 []
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import jwt from "jsonwebtoken";
+import OperationError from "../errors/OperationError";
+
+/**
+ * JWT Sign operation
+ */
+class JWTSign extends Operation {
+
+    /**
+     * JWTSign constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "JWT Sign";
+        this.module = "Crypto";
+        this.description = "Signs a JSON object as a JSON Web Token using a provided secret / private key.<br><br>The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.";
+        this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
+        this.inputType = "JSON";
+        this.outputType = "string";
+        this.args = [
+            {
+                name: "Private/Secret Key",
+                type: "text",
+                value: "secret"
+            },
+            {
+                name: "Signing algorithm",
+                type: "option",
+                value: [
+                    "HS256",
+                    "HS384",
+                    "HS512",
+                    "RS256",
+                    "RS384",
+                    "RS512",
+                    "ES256",
+                    "ES384",
+                    "ES512",
+                    "None"
+                ]
+            }
+        ];
+    }
+
+    /**
+     * @param {JSON} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [key, algorithm] = args;
+
+        try {
+            return jwt.sign(input, key, {
+                algorithm: algorithm === "None" ? "none" : algorithm
+            });
+        } catch (err) {
+            throw new OperationError(`Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.
+
+${err}`);
+        }
+    }
+
+}
+
+export default JWTSign;

+ 65 - 0
src/core/operations/JWTVerify.mjs

@@ -0,0 +1,65 @@
+/**
+ * @author gchq77703 []
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import jwt from "jsonwebtoken";
+import OperationError from "../errors/OperationError";
+
+/**
+ * JWT Verify operation
+ */
+class JWTVerify extends Operation {
+
+    /**
+     * JWTVerify constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "JWT Verify";
+        this.module = "Crypto";
+        this.description = "Verifies that a JSON Web Token is valid and has been signed with the provided secret / private key.<br><br>The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.";
+        this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
+        this.inputType = "string";
+        this.outputType = "JSON";
+        this.args = [
+            {
+                name: "Private/Secret Key",
+                type: "text",
+                value: "secret"
+            },
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [key] = args;
+
+        try {
+            const verified = jwt.verify(input, key, { algorithms: [
+                "HS256",
+                "HS384",
+                "HS512",
+                "none"
+            ]});
+
+            if (verified.hasOwnProperty("name") && verified.name === "JsonWebTokenError") {
+                throw new OperationError(verified.message);
+            }
+
+            return verified;
+        } catch (err) {
+            throw new OperationError(err);
+        }
+    }
+
+}
+
+export default JWTVerify;

+ 4 - 0
test/index.mjs

@@ -47,6 +47,9 @@ import "./tests/operations/HaversineDistance";
 import "./tests/operations/Hexdump";
 import "./tests/operations/Image";
 import "./tests/operations/Jump";
+import "./tests/operations/JWTDecode";
+import "./tests/operations/JWTSign";
+import "./tests/operations/JWTVerify";
 import "./tests/operations/MS";
 import "./tests/operations/Magic";
 import "./tests/operations/MorseCode";
@@ -67,6 +70,7 @@ import "./tests/operations/StrUtils";
 import "./tests/operations/SymmetricDifference";
 import "./tests/operations/ToGeohash.mjs";
 import "./tests/operations/TranslateDateTimeFormat";
+import "./tests/operations/Magic";
 
 let allTestsPassing = true;
 const testStatusCounts = {

+ 51 - 0
test/tests/operations/JWTDecode.mjs

@@ -0,0 +1,51 @@
+/**
+ * JWT Decode tests
+ *
+ * @author gchq77703 []
+ *
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister";
+
+const outputObject = JSON.stringify({
+    String: "SomeString",
+    Number: 42,
+    iat: 1
+}, null, 4);
+
+TestRegister.addTests([
+    {
+        name: "JWT Decode: HS",
+        input: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.0ha6-j4FwvEIKPVZ-hf3S_R9Hy_UtXzq4dnedXcUrXk",
+        expectedOutput: outputObject,
+        recipeConfig: [
+            {
+                op: "JWT Decode",
+                args: [],
+            }
+        ],
+    },
+    {
+        name: "JWT Decode: RS",
+        input: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.MjEJhtZk2nXzigi24piMzANmrj3mILHJcDl0xOjl5a8EgdKVL1oaMEjTkMQp5RA8YrqeRBFaX-BGGCKOXn5zPY1DJwWsBUyN9C-wGR2Qye0eogH_3b4M9EW00TPCUPXm2rx8URFj7Wg9VlsmrGzLV2oKkPgkVxuFSxnpO3yjn1Y",
+        expectedOutput: outputObject,
+        recipeConfig: [
+            {
+                op: "JWT Decode",
+                args: [],
+            }
+        ],
+    },
+    {
+        name: "JWT Decode: ES",
+        input: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.WkECT51jSfpRkcpQ4x0h5Dwe7CFBI6u6Et2gWp91HC7mpN_qCFadRpsvJLtKubm6cJTLa68xtei0YrDD8fxIUA",
+        expectedOutput: outputObject,
+        recipeConfig: [
+            {
+                op: "JWT Decode",
+                args: [],
+            }
+        ],
+    }
+]);

+ 163 - 0
test/tests/operations/JWTSign.mjs

@@ -0,0 +1,163 @@
+/**
+ * JWT Sign tests
+ *
+ * @author gchq77703 []
+ *
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister";
+
+const inputObject = JSON.stringify({
+    String: "SomeString",
+    Number: 42,
+    iat: 1
+}, null, 4);
+
+const hsKey = "secret_cat";
+const rsKey = `-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
+33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
++jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
+AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS
+3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp
+uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE
+2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0
+GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K
+Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY
+6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5
+fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
+Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
+FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
+-----END RSA PRIVATE KEY-----`;
+const esKey = `-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2
+OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r
+1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G
+-----END PRIVATE KEY-----`;
+
+TestRegister.addTests([
+    {
+        name: "JWT Sign: HS256",
+        input: inputObject,
+        expectedOutput: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.0ha6-j4FwvEIKPVZ-hf3S_R9Hy_UtXzq4dnedXcUrXk",
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [hsKey, "HS256"],
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: HS384",
+        input: inputObject,
+        expectedOutput: "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ._bPK-Y3mIACConbJqkGFMQ_L3vbxgKXy9gSxtL9hA5XTganozTSXxD0vX0N1yT5s",
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [hsKey, "HS384"],
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: HS512",
+        input: inputObject,
+        expectedOutput: "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.vZIJU4XYMFt3FLE1V_RZOxEetmV4RvxtPZQGzJthK_d47pjwlEb6pQE23YxHFmOj8H5RLEdqqLPw4jNsOyHRzA",
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [hsKey, "HS512"],
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: ES256",
+        input: inputObject,
+        expectedOutput: inputObject,
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [esKey, "ES256"],
+            },
+            {
+                op: "JWT Decode",
+                args: []
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: ES384",
+        input: inputObject,
+        expectedOutput: inputObject,
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [esKey, "ES384"],
+            },
+            {
+                op: "JWT Decode",
+                args: []
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: ES512",
+        input: inputObject,
+        expectedOutput: inputObject,
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [esKey, "ES512"],
+            },
+            {
+                op: "JWT Decode",
+                args: []
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: RS256",
+        input: inputObject,
+        expectedOutput: inputObject,
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [rsKey, "RS256"],
+            },
+            {
+                op: "JWT Decode",
+                args: []
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: RS384",
+        input: inputObject,
+        expectedOutput: inputObject,
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [rsKey, "RS384"],
+            },
+            {
+                op: "JWT Decode",
+                args: []
+            }
+        ],
+    },
+    {
+        name: "JWT Sign: RS512",
+        input: inputObject,
+        expectedOutput: inputObject,
+        recipeConfig: [
+            {
+                op: "JWT Sign",
+                args: [esKey, "RS512"],
+            },
+            {
+                op: "JWT Decode",
+                args: []
+            }
+        ],
+    }
+]);

+ 75 - 0
test/tests/operations/JWTVerify.mjs

@@ -0,0 +1,75 @@
+/**
+ * JWT Verify tests
+ *
+ * @author gchq77703 []
+ *
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister";
+
+const outputObject = JSON.stringify({
+    String: "SomeString",
+    Number: 42,
+    iat: 1
+}, null, 4);
+
+const invalidAlgorithm = "JsonWebTokenError: invalid algorithm";
+
+const hsKey = "secret_cat";
+const rsKey = `-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
+33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
++jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
+AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS
+3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp
+uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE
+2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0
+GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K
+Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY
+6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5
+fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
+Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
+FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
+-----END RSA PRIVATE KEY-----`;
+const esKey = `-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2
+OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r
+1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G
+-----END PRIVATE KEY-----`;
+
+TestRegister.addTests([
+    {
+        name: "JWT Verify: HS",
+        input: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.0ha6-j4FwvEIKPVZ-hf3S_R9Hy_UtXzq4dnedXcUrXk",
+        expectedOutput: outputObject,
+        recipeConfig: [
+            {
+                op: "JWT Verify",
+                args: [hsKey],
+            }
+        ],
+    },
+    {
+        name: "JWT Verify: RS",
+        input: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.MjEJhtZk2nXzigi24piMzANmrj3mILHJcDl0xOjl5a8EgdKVL1oaMEjTkMQp5RA8YrqeRBFaX-BGGCKOXn5zPY1DJwWsBUyN9C-wGR2Qye0eogH_3b4M9EW00TPCUPXm2rx8URFj7Wg9VlsmrGzLV2oKkPgkVxuFSxnpO3yjn1Y",
+        expectedOutput: invalidAlgorithm,
+        recipeConfig: [
+            {
+                op: "JWT Verify",
+                args: [rsKey],
+            }
+        ],
+    },
+    {
+        name: "JWT Verify: ES",
+        input: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.WkECT51jSfpRkcpQ4x0h5Dwe7CFBI6u6Et2gWp91HC7mpN_qCFadRpsvJLtKubm6cJTLa68xtei0YrDD8fxIUA",
+        expectedOutput: invalidAlgorithm,
+        recipeConfig: [
+            {
+                op: "JWT Verify",
+                args: [esKey],
+            }
+        ],
+    }
+]);