Merge pull request #1 from Fra3zz/dev
Add Public Key from CSR operation. Build and tests complete: https://github.com/Fra3zz/CyberChef/actions/runs/23409667910/job/68094573307?pr=1
This commit is contained in:
commit
460ebe0186
@ -204,6 +204,7 @@
|
|||||||
"Parse CSR",
|
"Parse CSR",
|
||||||
"Public Key from Certificate",
|
"Public Key from Certificate",
|
||||||
"Public Key from Private Key",
|
"Public Key from Private Key",
|
||||||
|
"Public Key from CSR",
|
||||||
"SM2 Encrypt",
|
"SM2 Encrypt",
|
||||||
"SM2 Decrypt"
|
"SM2 Decrypt"
|
||||||
]
|
]
|
||||||
|
|||||||
79
src/core/operations/PubKeyFromCSR.mjs
Normal file
79
src/core/operations/PubKeyFromCSR.mjs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import forge from "node-forge";
|
||||||
|
|
||||||
|
const { asn1, pki, util } = forge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public Key from CSR operation
|
||||||
|
*/
|
||||||
|
class PubKeyFromCSR extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PubKeyFromCSR constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.name = "Public Key from CSR";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Extracts the Public Key from a Certificate Signing Request. Currently only supports ECDSA and RSA.";
|
||||||
|
this.infoURL = "https://en.wikipedia.org/wiki/Certificate_signing_request";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
this.checks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
let output = "";
|
||||||
|
let match;
|
||||||
|
const regex = /-----BEGIN (CERTIFICATE REQUEST)-----/g;
|
||||||
|
while ((match = regex.exec(input)) !== null) {
|
||||||
|
const indexBase64 = match.index + match[0].length;
|
||||||
|
const footer = `-----END ${match[1]}-----`;
|
||||||
|
const indexFooter = input.indexOf(footer, indexBase64);
|
||||||
|
if (indexFooter === -1) {
|
||||||
|
throw new OperationError(`CSR footer '${footer}' not found`);
|
||||||
|
}
|
||||||
|
const csrString = input.substring(match.index, indexFooter + footer.length);
|
||||||
|
|
||||||
|
let pubKeyPem;
|
||||||
|
try {
|
||||||
|
// RSA
|
||||||
|
const csr = pki.certificationRequestFromPem(csrString);
|
||||||
|
pubKeyPem = pki.publicKeyToPem(csr.publicKey);
|
||||||
|
} catch (e) {
|
||||||
|
if (!e.message.includes("OID is not RSA")) {
|
||||||
|
throw new OperationError(`Failed to parse CSR or extract public key: ${e}`);
|
||||||
|
}
|
||||||
|
// EC
|
||||||
|
try {
|
||||||
|
const csrDer = util.decode64(
|
||||||
|
csrString
|
||||||
|
.replace("-----BEGIN CERTIFICATE REQUEST-----", "")
|
||||||
|
.replace("-----END CERTIFICATE REQUEST-----", "")
|
||||||
|
.replace(/\s+/g, "")
|
||||||
|
);
|
||||||
|
const csrAsn1 = asn1.fromDer(csrDer);
|
||||||
|
const certReqInfo = csrAsn1.value[0];
|
||||||
|
const spki = certReqInfo.value[2];
|
||||||
|
const spkiDer = asn1.toDer(spki).getBytes();
|
||||||
|
const spkiB64 = util.encode64(spkiDer);
|
||||||
|
pubKeyPem = `-----BEGIN PUBLIC KEY-----\n${spkiB64.match(/.{1,64}/g).join("\n")}\n-----END PUBLIC KEY-----\n`;
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Failed to parse CSR or extract public key: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output += pubKeyPem;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PubKeyFromCSR;
|
||||||
167
tests/operations/tests/PubKeyFromCSR.mjs
Normal file
167
tests/operations/tests/PubKeyFromCSR.mjs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
const RSA_2048_CSR = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIICyzCCAbMCAQAwTzELMAkGA1UEBhMCTkExCzAJBgNVBAgMAm5hMQswCQYDVQQH
|
||||||
|
DAJuYTESMBAGA1UECgwJY3liZXJjaGVmMRIwEAYDVQQDDAlnaXRodWIuaW8wggEi
|
||||||
|
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCSFAA8f3IrypTeFiLyGIk/JyYG
|
||||||
|
VxSfyouNIppgV3QaUr3SuUyCIa8U5BVgzrrLc9NeeYaKXI5TFOq3IrhjLZqrKvcZ
|
||||||
|
jo6uxLwjwSC8qI5V3f147qF6E8/P18IaZtJn0XJHEWY8zZ1u9wMHURB4iC6juszg
|
||||||
|
4UhYwAgqKWzRl9ON8aqpXSxp01eUtVX+Ve4+GixKWCZfxMjLWZ8T1rzYUfC/W0wl
|
||||||
|
1PFJPVGBQKBeBTQaKERgLIjNX5Qk/GvFwt3bUBd34GgH/CybhagP3GBQF/+ZJ7Fc
|
||||||
|
Wu4N4tF7Gxn6IavjPEIJ86DexgrR9WugzcqBwmdNMA6bK9A4XagekY9ao4RFAgMB
|
||||||
|
AAGgNzA1BgkqhkiG9w0BCQ4xKDAmMCQGA1UdEQQdMBuCCWdpdGh1Yi5pb4IOZ2No
|
||||||
|
cS5naXRodWIuaW8wDQYJKoZIhvcNAQELBQADggEBADe+eaTZBg+JOcMYecO+Mf5e
|
||||||
|
4DbJd1r4bg39UMfRBa3hEq2EZZk2IfLfmU2YDGvzt/ZUQF4QFnW0ih4bBLkXuSxw
|
||||||
|
alA3BzMeB9Br/j5fAAo+4xm6F4qquzozznFWNMqsnuv4j9NdAU5WqqEkWnVTfQqh
|
||||||
|
myh7wbLev8yPjAL+WSKoN45MuOlOrLBJp+lr3LlEWconRAfHpHPPhYcLbieaUZgx
|
||||||
|
/YJEHm4iiaJpPxBOxXAenVovncTCH6XRZsdsria8wuyTZH4hlg3so7gc8C6nmHvl
|
||||||
|
ia/tkQICn+jPRTFtN1Bkn+SdUKVx1W5HTKy4yTE3Km1yh0nPUS5MGBBFgWnKANo=
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const RSA_2048_CSR_PUB_KEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhQAPH9yK8qU3hYi8hiJ
|
||||||
|
PycmBlcUn8qLjSKaYFd0GlK90rlMgiGvFOQVYM66y3PTXnmGilyOUxTqtyK4Yy2a
|
||||||
|
qyr3GY6OrsS8I8EgvKiOVd39eO6hehPPz9fCGmbSZ9FyRxFmPM2dbvcDB1EQeIgu
|
||||||
|
o7rM4OFIWMAIKils0ZfTjfGqqV0sadNXlLVV/lXuPhosSlgmX8TIy1mfE9a82FHw
|
||||||
|
v1tMJdTxST1RgUCgXgU0GihEYCyIzV+UJPxrxcLd21AXd+BoB/wsm4WoD9xgUBf/
|
||||||
|
mSexXFruDeLRexsZ+iGr4zxCCfOg3sYK0fVroM3KgcJnTTAOmyvQOF2oHpGPWqOE
|
||||||
|
RQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
/* RSA 2048 Private Key
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCSFAA8f3IrypTe
|
||||||
|
FiLyGIk/JyYGVxSfyouNIppgV3QaUr3SuUyCIa8U5BVgzrrLc9NeeYaKXI5TFOq3
|
||||||
|
IrhjLZqrKvcZjo6uxLwjwSC8qI5V3f147qF6E8/P18IaZtJn0XJHEWY8zZ1u9wMH
|
||||||
|
URB4iC6juszg4UhYwAgqKWzRl9ON8aqpXSxp01eUtVX+Ve4+GixKWCZfxMjLWZ8T
|
||||||
|
1rzYUfC/W0wl1PFJPVGBQKBeBTQaKERgLIjNX5Qk/GvFwt3bUBd34GgH/CybhagP
|
||||||
|
3GBQF/+ZJ7FcWu4N4tF7Gxn6IavjPEIJ86DexgrR9WugzcqBwmdNMA6bK9A4Xage
|
||||||
|
kY9ao4RFAgMBAAECggEAA96TwwZ9N7u+BcQAWPldaVbYIwLbgQAUgkCQZkzqvmfC
|
||||||
|
r3pJFIlf4eXIyy+uswT2bGI7th6NhpXfQcqhp77lgfM5aGvmS6racPgErfqpCo0+
|
||||||
|
0Z1AmcM8lfzZH2np2OYraMaFNscbjHzuj5sOHKM+2QdxteNBz1gG31cJkuO6rt/V
|
||||||
|
qr3Fy4twJ+htTTbmX4ArVpUaY5F+eZu2qw4kOVDrNnPpz6LKx5UVBFszvW8/8trr
|
||||||
|
B03ppkloJUUda5aKkKKiyYpC/xOoCBSc9mbQtptiWo/8tMm7E/AfNy1oUeNp3+M/
|
||||||
|
+vO7sj5dA2Xr1g/76j/tp43cxvzv89dYdmq/sf6MYQKBgQDMXD9mfQf8FJqL09HH
|
||||||
|
le6N2xD0K8V2RCbdp5YOPZY6jkw3howddvSzcpQI3qsjGLLc7CrdhfsuheSebPhe
|
||||||
|
D5SKYejtPNNIcSA8xitjZPtzsi3ELhOyVkUeHaIa7itq35jnSOnc8haZMhhuzkWS
|
||||||
|
68iHk9ijBwOKvK1fTfXK232LMwKBgQC2/ZFOlCIce0y/5XkBJEGdcGSLw1ncGSlG
|
||||||
|
6cYY3AoV14dfmeMD1wXf6OQGTC7Nc3gTXXP2KXLI6dHNPkC+cU6DCD7GGThb8kOk
|
||||||
|
plUZnKVAs+copHspL3nYCjXTgDQ5cvTGX8DSYSyap7BFYLcdTXI4R5HEhb9uqJ8i
|
||||||
|
NsVWFTtypwKBgQCJus47+55LBXPXM04aDnF1h6QYe/ucJnhvQMhAFr/N/SNe9L4w
|
||||||
|
CYEIA/vDMpbyk23QuRZ2sBrGkxSutVB6zFNXJH/AjBL1qtCIRSLu3RsfMYHoywkZ
|
||||||
|
U01H677aGZSHdeTuU9TRxRL38qxG2ZxIVcKTpVAHJ+36LglGxxsVufIVwwKBgBsP
|
||||||
|
zNluFs1XfrYyXX7JudpqsLPqo/Nk1THjiKRMhkFMqnx86ZG7zuaaLn6v7Yv8s5lJ
|
||||||
|
jMiuwIbt7VUJC9IeN5oxMfdh62/NmCtVXeh3vgifkmP0TzJ8DuzgNa2dnBuS4Jgl
|
||||||
|
uQJj1JDak7ru3qW6ulWQYAJMNU9MKJyKtQxR/4SpAoGAOHsyTmptmLO85l39dTBV
|
||||||
|
RJsYfp24fp/qM9QiB9y4VOauuokqrxHijEi5ZhPIIgsyuk45b31lGARj+SXBdWOf
|
||||||
|
oKSfwh7rHd7vFqKumRiZydfszbXxtHvLDFi0oukYDI16afOb3y5tmuSdyv8Y6ZsT
|
||||||
|
H2zqBm8koIaSdtBUYfsJM08=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
*/
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
|
const EC_PUB_KEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtV2tWhuWHVvaZGpAfdbz6XK7YS8b
|
||||||
|
qUx6D7VWiQkYidpzXWCTlnprARCO/2OK5t3EhUwZyPZueFr7lgIAFRFDkw==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const EC_CSR = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIBADCBpwIBADBFMQswCQYDVQQGEwJOQTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
|
||||||
|
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFkwEwYHKoZIzj0CAQYI
|
||||||
|
KoZIzj0DAQcDQgAEtV2tWhuWHVvaZGpAfdbz6XK7YS8bqUx6D7VWiQkYidpzXWCT
|
||||||
|
lnprARCO/2OK5t3EhUwZyPZueFr7lgIAFRFDk6AAMAoGCCqGSM49BAMCA0gAMEUC
|
||||||
|
IQCEswjMY+jmBXtUogwoZ9GjOb9g72ZAiiL3fbUIKKOuigIgK10fc/M2QSgfv9x6
|
||||||
|
r18dKfOku2+q1Sa9M08iee6hGUI=
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
/* EC Private Key
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIA42NtMH8T9dPpbKlptxNcUmAIcv112fwJkn9XRYxbdMoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEtV2tWhuWHVvaZGpAfdbz6XK7YS8bqUx6D7VWiQkYidpzXWCTlnpr
|
||||||
|
ARCO/2OK5t3EhUwZyPZueFr7lgIAFRFDkw==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
*/
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: RSA 2048 returns correct public key",
|
||||||
|
input: RSA_2048_CSR,
|
||||||
|
expectedOutput: RSA_2048_CSR_PUB_KEY,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: two CSRs returns public key twice",
|
||||||
|
input: `${RSA_2048_CSR}\n${RSA_2048_CSR}`,
|
||||||
|
expectedOutput: RSA_2048_CSR_PUB_KEY + RSA_2048_CSR_PUB_KEY,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: missing footer throws",
|
||||||
|
input: RSA_2048_CSR.substring(0, RSA_2048_CSR.lastIndexOf("-----END")),
|
||||||
|
expectedOutput: "CSR footer '-----END CERTIFICATE REQUEST-----' not found",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: empty input returns empty output",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: no PEM block returns empty output",
|
||||||
|
input: "this is not a CSR",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: wrong PEM type is ignored",
|
||||||
|
input: `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEA
|
||||||
|
-----END PRIVATE KEY-----`,
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from CSR: EC P-256 returns correct public key",
|
||||||
|
input: EC_CSR,
|
||||||
|
expectedOutput: EC_PUB_KEY,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from CSR",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
Loading…
x
Reference in New Issue
Block a user