mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-21 15:26:16 -04:00
JWK conversion from/to PEM
This commit is contained in:
parent
cc28c6af1a
commit
cbf990fab9
5 changed files with 530 additions and 0 deletions
80
src/core/operations/JWKToPem.mjs
Normal file
80
src/core/operations/JWKToPem.mjs
Normal file
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* @author cplussharp
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import r from "jsrsasign";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* PEM to JWK operation
|
||||
*/
|
||||
class PEMToJWK extends Operation {
|
||||
|
||||
/**
|
||||
* PEMToJWK constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "JWK to PEM";
|
||||
this.module = "PublicKey";
|
||||
this.description = "Converts Keys in JSON Web Key format to PEM format (PKCS#8).";
|
||||
this.infoURL = "https://datatracker.ietf.org/doc/html/rfc7517";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.checks = [
|
||||
{
|
||||
"pattern": "\"kty\":\\s*\"(EC|RSA)\"",
|
||||
"flags": "gm",
|
||||
"args": []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const inputJson = JSON.parse(input);
|
||||
|
||||
let keys = [];
|
||||
if (Array.isArray(inputJson)) {
|
||||
// list of keys => transform all keys
|
||||
keys = inputJson;
|
||||
} else if (Array.isArray(inputJson.keys)) {
|
||||
// JSON Web Key Set => transform all keys
|
||||
keys = inputJson.keys;
|
||||
} else if (typeof inputJson === "object") {
|
||||
// single key
|
||||
keys.push(inputJson);
|
||||
} else {
|
||||
throw new OperationError("Input is not a JSON Web Key");
|
||||
}
|
||||
|
||||
let output = "";
|
||||
for (let i=0; i<keys.length; i++) {
|
||||
const jwk = keys[i];
|
||||
if (typeof jwk.kty !== "string") {
|
||||
throw new OperationError("Invalid JWK format");
|
||||
} else if ("|RSA|EC|".indexOf(jwk.kty) === -1) {
|
||||
throw new OperationError(`Unsupported JWK key type '${inputJson.kty}'`);
|
||||
}
|
||||
|
||||
const key = r.KEYUTIL.getKey(jwk);
|
||||
const pem = key.isPrivate ? r.KEYUTIL.getPEM(key, "PKCS8PRV") : r.KEYUTIL.getPEM(key);
|
||||
|
||||
// PEM ends with '\n', so a new key always starts on a new line
|
||||
output += pem;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
export default PEMToJWK;
|
88
src/core/operations/PEMToJWK.mjs
Normal file
88
src/core/operations/PEMToJWK.mjs
Normal file
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* @author cplussharp
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import r from "jsrsasign";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* PEM to JWK operation
|
||||
*/
|
||||
class PEMToJWK extends Operation {
|
||||
|
||||
/**
|
||||
* PEMToJWK constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "PEM to JWK";
|
||||
this.module = "PublicKey";
|
||||
this.description = "Converts Keys in PEM format to a JSON Web Key format.";
|
||||
this.infoURL = "https://datatracker.ietf.org/doc/html/rfc7517";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.checks = [
|
||||
{
|
||||
"pattern": "-----BEGIN ((RSA |EC )?(PRIVATE|PUBLIC) KEY|CERTIFICATE)-----",
|
||||
"args": []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let output = "";
|
||||
let match;
|
||||
const regex = /-----BEGIN ([A-Z][A-Z ]+[A-Z])-----/g;
|
||||
while ((match = regex.exec(input)) !== null) {
|
||||
// find corresponding end tag
|
||||
const indexBase64 = match.index + match[0].length;
|
||||
const header = input.substring(match.index, indexBase64);
|
||||
const footer = `-----END ${match[1]}-----`;
|
||||
const indexFooter = input.indexOf(footer, indexBase64);
|
||||
if (indexFooter === -1) {
|
||||
throw new OperationError(`PEM footer '${footer}' not found`);
|
||||
}
|
||||
|
||||
const pem = input.substring(match.index, indexFooter + footer.length);
|
||||
if (match[1].indexOf("KEY") !== -1) {
|
||||
if (header === "-----BEGIN RSA PUBLIC KEY-----") {
|
||||
throw new OperationError("Unsupported RSA public key format. Only PKCS#8 is supported.");
|
||||
}
|
||||
|
||||
const key = r.KEYUTIL.getKey(pem);
|
||||
if (key.type === "DSA") {
|
||||
throw new OperationError("DSA keys are not supported for JWK");
|
||||
}
|
||||
const jwk = r.KEYUTIL.getJWKFromKey(key);
|
||||
if (output.length > 0) {
|
||||
output += "\n";
|
||||
}
|
||||
output += JSON.stringify(jwk);
|
||||
} else if (match[1] === "CERTIFICATE") {
|
||||
const cert = new r.X509();
|
||||
cert.readCertPEM(pem);
|
||||
const key = cert.getPublicKey();
|
||||
const jwk = r.KEYUTIL.getJWKFromKey(key);
|
||||
if (output.length > 0) {
|
||||
output += "\n";
|
||||
}
|
||||
output += JSON.stringify(jwk);
|
||||
} else {
|
||||
throw new OperationError(`Unsupported PEM type '${match[1]}'`);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
export default PEMToJWK;
|
Loading…
Add table
Add a link
Reference in a new issue