mirror of
https://github.com/gchq/CyberChef
synced 2025-01-11 20:18:57 +00:00
Add X.509 output formats
This commit is contained in:
parent
2efd075803
commit
daef663727
1 changed files with 142 additions and 96 deletions
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import r from "jsrsasign";
|
||||
import { fromBase64 } from "../lib/Base64.mjs";
|
||||
import { toHex } from "../lib/Hex.mjs";
|
||||
import { fromBase64, toBase64 } from "../lib/Base64.mjs";
|
||||
import { fromHex, toHex } from "../lib/Hex.mjs";
|
||||
import { formatByteStr, formatDnObj } from "../lib/PublicKey.mjs";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
@ -33,6 +33,11 @@ class ParseX509Certificate extends Operation {
|
|||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": ["PEM", "DER Hex", "Base64", "Raw"]
|
||||
},
|
||||
{
|
||||
"name": "Output format",
|
||||
"type": "option",
|
||||
"value": ["Text", "JSON", "PEM", "DER Hex", "Base64", "Raw"]
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
|
@ -55,9 +60,13 @@ class ParseX509Certificate extends Operation {
|
|||
}
|
||||
|
||||
const cert = new r.X509(),
|
||||
inputFormat = args[0];
|
||||
inputFormat = args[0],
|
||||
outputFormat = args[1];
|
||||
|
||||
let undefinedInputFormat = false,
|
||||
undefinedOuputFormat = false,
|
||||
output = "";
|
||||
|
||||
let undefinedInputFormat = false;
|
||||
try {
|
||||
switch (inputFormat) {
|
||||
case "DER Hex":
|
||||
|
@ -81,107 +90,146 @@ class ParseX509Certificate extends Operation {
|
|||
}
|
||||
if (undefinedInputFormat) throw "Undefined input format";
|
||||
|
||||
const sn = cert.getSerialNumberHex(),
|
||||
issuer = cert.getIssuer(),
|
||||
subject = cert.getSubject(),
|
||||
pk = cert.getPublicKey(),
|
||||
pkFields = [],
|
||||
sig = cert.getSignatureValueHex();
|
||||
try {
|
||||
switch (outputFormat) {
|
||||
case "Text":
|
||||
output = formatText(cert);
|
||||
break;
|
||||
case "JSON":
|
||||
output = JSON.stringify(cert.getParam());
|
||||
break;
|
||||
case "DER Hex":
|
||||
output = cert.hex;
|
||||
break;
|
||||
case "PEM":
|
||||
output = r.hextopem(cert.hex, "CERTIFICATE");
|
||||
break;
|
||||
case "Base64":
|
||||
output = toBase64(fromHex(cert.hex));
|
||||
break;
|
||||
case "Raw":
|
||||
output = Utils.byteArrayToChars(fromHex(cert.hex));
|
||||
break;
|
||||
default:
|
||||
undefinedOuputFormat = true;
|
||||
}
|
||||
} catch (e) {
|
||||
throw "Certificate encoding error (what even hapened?)";
|
||||
}
|
||||
if (undefinedOuputFormat) throw "Undefined output format";
|
||||
|
||||
let pkStr = "",
|
||||
sigStr = "",
|
||||
extensions = "";
|
||||
return output;
|
||||
}
|
||||
|
||||
// Public Key fields
|
||||
}
|
||||
/**
|
||||
* Format X.509 certificate.
|
||||
*
|
||||
* @param {r.X509} cert
|
||||
* @returns {string}
|
||||
*/
|
||||
function formatText(cert) {
|
||||
const sn = cert.getSerialNumberHex(),
|
||||
issuer = cert.getIssuer(),
|
||||
subject = cert.getSubject(),
|
||||
pk = cert.getPublicKey(),
|
||||
pkFields = [],
|
||||
sig = cert.getSignatureValueHex();
|
||||
|
||||
let pkStr = "",
|
||||
sigStr = "",
|
||||
extensions = "";
|
||||
|
||||
// Public Key fields
|
||||
pkFields.push({
|
||||
key: "Algorithm",
|
||||
value: pk.type
|
||||
});
|
||||
|
||||
if (pk.type === "EC") { // ECDSA
|
||||
pkFields.push({
|
||||
key: "Algorithm",
|
||||
value: pk.type
|
||||
key: "Curve Name",
|
||||
value: pk.curveName
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Length",
|
||||
value: (((new r.BigInteger(pk.pubKeyHex, 16)).bitLength() - 3) / 2) + " bits"
|
||||
});
|
||||
pkFields.push({
|
||||
key: "pub",
|
||||
value: formatByteStr(pk.pubKeyHex, 16, 18)
|
||||
});
|
||||
} else if (pk.type === "DSA") { // DSA
|
||||
pkFields.push({
|
||||
key: "pub",
|
||||
value: formatByteStr(pk.y.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "P",
|
||||
value: formatByteStr(pk.p.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Q",
|
||||
value: formatByteStr(pk.q.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "G",
|
||||
value: formatByteStr(pk.g.toString(16), 16, 18)
|
||||
});
|
||||
} else if (pk.e) { // RSA
|
||||
pkFields.push({
|
||||
key: "Length",
|
||||
value: pk.n.bitLength() + " bits"
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Modulus",
|
||||
value: formatByteStr(pk.n.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Exponent",
|
||||
value: pk.e + " (0x" + pk.e.toString(16) + ")"
|
||||
});
|
||||
} else {
|
||||
pkFields.push({
|
||||
key: "Error",
|
||||
value: "Unknown Public Key type"
|
||||
});
|
||||
}
|
||||
|
||||
if (pk.type === "EC") { // ECDSA
|
||||
pkFields.push({
|
||||
key: "Curve Name",
|
||||
value: pk.curveName
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Length",
|
||||
value: (((new r.BigInteger(pk.pubKeyHex, 16)).bitLength()-3) /2) + " bits"
|
||||
});
|
||||
pkFields.push({
|
||||
key: "pub",
|
||||
value: formatByteStr(pk.pubKeyHex, 16, 18)
|
||||
});
|
||||
} else if (pk.type === "DSA") { // DSA
|
||||
pkFields.push({
|
||||
key: "pub",
|
||||
value: formatByteStr(pk.y.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "P",
|
||||
value: formatByteStr(pk.p.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Q",
|
||||
value: formatByteStr(pk.q.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "G",
|
||||
value: formatByteStr(pk.g.toString(16), 16, 18)
|
||||
});
|
||||
} else if (pk.e) { // RSA
|
||||
pkFields.push({
|
||||
key: "Length",
|
||||
value: pk.n.bitLength() + " bits"
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Modulus",
|
||||
value: formatByteStr(pk.n.toString(16), 16, 18)
|
||||
});
|
||||
pkFields.push({
|
||||
key: "Exponent",
|
||||
value: pk.e + " (0x" + pk.e.toString(16) + ")"
|
||||
});
|
||||
} else {
|
||||
pkFields.push({
|
||||
key: "Error",
|
||||
value: "Unknown Public Key type"
|
||||
});
|
||||
}
|
||||
// Format Public Key fields
|
||||
for (let i = 0; i < pkFields.length; i++) {
|
||||
pkStr += ` ${pkFields[i].key}:${(pkFields[i].value + "\n").padStart(
|
||||
18 - (pkFields[i].key.length + 3) + pkFields[i].value.length + 1,
|
||||
" "
|
||||
)}`;
|
||||
}
|
||||
|
||||
// Format Public Key fields
|
||||
for (let i = 0; i < pkFields.length; i++) {
|
||||
pkStr += ` ${pkFields[i].key}:${(pkFields[i].value + "\n").padStart(
|
||||
18 - (pkFields[i].key.length + 3) + pkFields[i].value.length + 1,
|
||||
" "
|
||||
)}`;
|
||||
}
|
||||
// Signature fields
|
||||
let breakoutSig = false;
|
||||
try {
|
||||
breakoutSig = r.ASN1HEX.dump(sig).indexOf("SEQUENCE") === 0;
|
||||
} catch (err) {
|
||||
// Error processing signature, output without further breakout
|
||||
}
|
||||
|
||||
// Signature fields
|
||||
let breakoutSig = false;
|
||||
try {
|
||||
breakoutSig = r.ASN1HEX.dump(sig).indexOf("SEQUENCE") === 0;
|
||||
} catch (err) {
|
||||
// Error processing signature, output without further breakout
|
||||
}
|
||||
|
||||
if (breakoutSig) { // DSA or ECDSA
|
||||
sigStr = ` r: ${formatByteStr(r.ASN1HEX.getV(sig, 4), 16, 18)}
|
||||
if (breakoutSig) { // DSA or ECDSA
|
||||
sigStr = ` r: ${formatByteStr(r.ASN1HEX.getV(sig, 4), 16, 18)}
|
||||
s: ${formatByteStr(r.ASN1HEX.getV(sig, 48), 16, 18)}`;
|
||||
} else { // RSA or unknown
|
||||
sigStr = ` Signature: ${formatByteStr(sig, 16, 18)}`;
|
||||
}
|
||||
} else { // RSA or unknown
|
||||
sigStr = ` Signature: ${formatByteStr(sig, 16, 18)}`;
|
||||
}
|
||||
|
||||
// Extensions
|
||||
try {
|
||||
extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0];
|
||||
} catch (err) {}
|
||||
// Extensions
|
||||
try {
|
||||
extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0];
|
||||
} catch (err) { }
|
||||
|
||||
const issuerStr = formatDnObj(issuer, 2),
|
||||
nbDate = formatDate(cert.getNotBefore()),
|
||||
naDate = formatDate(cert.getNotAfter()),
|
||||
subjectStr = formatDnObj(subject, 2);
|
||||
const issuerStr = formatDnObj(issuer, 2),
|
||||
nbDate = formatDate(cert.getNotBefore()),
|
||||
naDate = formatDate(cert.getNotAfter()),
|
||||
subjectStr = formatDnObj(subject, 2);
|
||||
|
||||
return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)})
|
||||
return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)})
|
||||
Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn})
|
||||
Algorithm ID: ${cert.getSignatureAlgorithmField()}
|
||||
Validity
|
||||
|
@ -199,8 +247,6 @@ ${sigStr}
|
|||
|
||||
Extensions
|
||||
${extensions}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue