mirror of
https://github.com/gchq/CyberChef
synced 2025-12-05 23:53:27 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c35557aea5 | ||
|
|
b5959c6f01 | ||
|
|
2000938040 | ||
|
|
c795271502 | ||
|
|
1d4c810554 | ||
|
|
ccd3839a9b | ||
|
|
fda77cf37a | ||
|
|
dc8c185c39 | ||
|
|
99efcb521d | ||
|
|
d2bd397e8c | ||
|
|
944810614a | ||
|
|
21e5641196 | ||
|
|
077b11e33b | ||
|
|
8d4ad6ae75 | ||
|
|
ab47b3557f | ||
|
|
c5e5ed2b4d | ||
|
|
dd2cfe8bac | ||
|
|
8a17abae45 | ||
|
|
dfedfa9f4c | ||
|
|
56f92afbf4 | ||
|
|
52709f0ecb | ||
|
|
df140b5098 | ||
|
|
6b95ba7dd6 | ||
|
|
61295a968e | ||
|
|
0717407bea | ||
|
|
c46660a0d9 | ||
|
|
4c6200f233 | ||
|
|
3983e1a8e2 | ||
|
|
a6b774da81 | ||
|
|
de8ed6962d | ||
|
|
98edef389c | ||
|
|
1b16c26699 | ||
|
|
d59ebdd0dc | ||
|
|
e85acee509 | ||
|
|
4e9567f539 | ||
|
|
a9c00a5856 | ||
|
|
6331c20306 | ||
|
|
4dc4c7edd2 | ||
|
|
d2ff03cea4 |
18
CHANGELOG.md
18
CHANGELOG.md
@@ -13,6 +13,14 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
## Details
|
||||
|
||||
### [10.15.0] - 2024-04-02
|
||||
- Fix Ciphersaber2 key concatenation [@zb3] | [#1765]
|
||||
- Fix DeriveEVPKey's array parsing [@zb3] | [#1767]
|
||||
- Fix JWT operations [@a3957273] | [#1769]
|
||||
- Added 'Parse Certificate Signing Request' operation [@jkataja] | [#1504]
|
||||
- Added 'Extract Hash Values' operation [@MShwed] | [#512]
|
||||
- Added 'DateTime Delta' operation [@tomgond] | [#1732]
|
||||
|
||||
### [10.14.0] - 2024-03-31
|
||||
- Added 'To Float' and 'From Float' operations [@tcode2k16] | [#1762]
|
||||
- Fix ChaCha raw export option [@joostrijneveld] | [#1606]
|
||||
@@ -410,6 +418,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||
## [4.0.0] - 2016-11-28
|
||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||
|
||||
[10.14.0]: https://github.com/gchq/CyberChef/releases/tag/v10.14.0
|
||||
[10.14.0]: https://github.com/gchq/CyberChef/releases/tag/v10.14.0
|
||||
[10.13.0]: https://github.com/gchq/CyberChef/releases/tag/v10.13.0
|
||||
[10.12.0]: https://github.com/gchq/CyberChef/releases/tag/v10.12.0
|
||||
@@ -586,6 +595,9 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@breakersall]: https://github.com/breakersall
|
||||
[@evanreichard]: https://github.com/evanreichard
|
||||
[@devcydo]: https://github.com/devcydo
|
||||
[@zb3]: https://github.com/zb3
|
||||
[@jkataja]: https://github.com/jkataja
|
||||
[@tomgond]: https://github.com/tomgond
|
||||
|
||||
|
||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||
@@ -725,3 +737,9 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[#1197]: https://github.com/gchq/CyberChef/issues/1197
|
||||
[#933]: https://github.com/gchq/CyberChef/issues/933
|
||||
[#1361]: https://github.com/gchq/CyberChef/issues/1361
|
||||
[#1765]: https://github.com/gchq/CyberChef/issues/1765
|
||||
[#1767]: https://github.com/gchq/CyberChef/issues/1767
|
||||
[#1769]: https://github.com/gchq/CyberChef/issues/1769
|
||||
[#1504]: https://github.com/gchq/CyberChef/issues/1504
|
||||
[#512]: https://github.com/gchq/CyberChef/issues/512
|
||||
[#1732]: https://github.com/gchq/CyberChef/issues/1732
|
||||
|
||||
48
package-lock.json
generated
48
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "10.14.0",
|
||||
"version": "10.15.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cyberchef",
|
||||
"version": "10.14.0",
|
||||
"version": "10.15.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -54,7 +54,7 @@
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.3",
|
||||
"jsonpath-plus": "^8.0.0",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"jsrsasign": "^11.1.0",
|
||||
"kbpgp": "2.1.15",
|
||||
@@ -9712,9 +9712,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
|
||||
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
@@ -9725,43 +9725,21 @@
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.5.4"
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=4",
|
||||
"npm": ">=1.4.28"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/jsqr": {
|
||||
"version": "1.4.0",
|
||||
"license": "Apache-2.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "10.14.0",
|
||||
"version": "10.15.0",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@@ -135,7 +135,7 @@
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.3",
|
||||
"jsonpath-plus": "^8.0.0",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"jsrsasign": "^11.1.0",
|
||||
"kbpgp": "2.1.15",
|
||||
|
||||
@@ -179,7 +179,8 @@
|
||||
"RSA Verify",
|
||||
"RSA Encrypt",
|
||||
"RSA Decrypt",
|
||||
"Parse SSH Host Key"
|
||||
"Parse SSH Host Key",
|
||||
"Parse CSR"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -321,6 +322,7 @@
|
||||
"To UNIX Timestamp",
|
||||
"Windows Filetime to UNIX Timestamp",
|
||||
"UNIX Timestamp to Windows Filetime",
|
||||
"DateTime Delta",
|
||||
"Extract dates",
|
||||
"Get Time",
|
||||
"Sleep"
|
||||
@@ -337,6 +339,7 @@
|
||||
"Extract domains",
|
||||
"Extract file paths",
|
||||
"Extract dates",
|
||||
"Extract hashes",
|
||||
"Regular expression",
|
||||
"XPath expression",
|
||||
"JPath expression",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
export function encode(tempIVP, key, rounds, input) {
|
||||
const ivp = new Uint8Array(key.concat(tempIVP));
|
||||
const ivp = new Uint8Array([...key, ...tempIVP]);
|
||||
const state = new Array(256).fill(0);
|
||||
let j = 0, i = 0;
|
||||
const result = [];
|
||||
|
||||
108
src/core/operations/DateTimeDelta.mjs
Normal file
108
src/core/operations/DateTimeDelta.mjs
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @author tomgond [tom.gonda@gmail.com]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import moment from "moment-timezone";
|
||||
import {DATETIME_FORMATS, FORMAT_EXAMPLES} from "../lib/DateTime.mjs";
|
||||
|
||||
/**
|
||||
* DateTime Delta operation
|
||||
*/
|
||||
class DateTimeDelta extends Operation {
|
||||
|
||||
/**
|
||||
* DateTimeDelta constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "DateTime Delta";
|
||||
this.module = "Default";
|
||||
this.description = "Calculates a new DateTime value given an input DateTime value and a time difference (delta) from the input DateTime value.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "string";
|
||||
this.outputType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Built in formats",
|
||||
"type": "populateOption",
|
||||
"value": DATETIME_FORMATS,
|
||||
"target": 1
|
||||
},
|
||||
{
|
||||
"name": "Input format string",
|
||||
"type": "binaryString",
|
||||
"value": "DD/MM/YYYY HH:mm:ss"
|
||||
},
|
||||
{
|
||||
"name": "Time Operation",
|
||||
"type": "option",
|
||||
"value": ["Add", "Subtract"]
|
||||
},
|
||||
{
|
||||
"name": "Days",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Hours",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Minutes",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Seconds",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
}
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const inputTimezone = "UTC";
|
||||
const inputFormat = args[1];
|
||||
const operationType = args[2];
|
||||
const daysDelta = args[3];
|
||||
const hoursDelta = args[4];
|
||||
const minutesDelta = args[5];
|
||||
const secondsDelta = args[6];
|
||||
let date = "";
|
||||
|
||||
try {
|
||||
date = moment.tz(input, inputFormat, inputTimezone);
|
||||
if (!date || date.format() === "Invalid date") throw Error;
|
||||
} catch (err) {
|
||||
return `Invalid format.\n\n${FORMAT_EXAMPLES}`;
|
||||
}
|
||||
let newDate;
|
||||
if (operationType === "Add") {
|
||||
newDate = date.add(daysDelta, "days")
|
||||
.add(hoursDelta, "hours")
|
||||
.add(minutesDelta, "minutes")
|
||||
.add(secondsDelta, "seconds");
|
||||
|
||||
} else {
|
||||
newDate = date.add(-daysDelta, "days")
|
||||
.add(-hoursDelta, "hours")
|
||||
.add(-minutesDelta, "minutes")
|
||||
.add(-secondsDelta, "seconds");
|
||||
}
|
||||
return newDate.tz(inputTimezone).format(inputFormat.replace(/[<>]/g, ""));
|
||||
}
|
||||
}
|
||||
|
||||
export default DateTimeDelta;
|
||||
@@ -62,11 +62,13 @@ class DeriveEVPKey extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const passphrase = Utils.convertToByteString(args[0].string, args[0].option),
|
||||
const passphrase = CryptoJS.enc.Latin1.parse(
|
||||
Utils.convertToByteString(args[0].string, args[0].option)),
|
||||
keySize = args[1] / 32,
|
||||
iterations = args[2],
|
||||
hasher = args[3],
|
||||
salt = Utils.convertToByteString(args[4].string, args[4].option),
|
||||
salt = CryptoJS.enc.Latin1.parse(
|
||||
Utils.convertToByteString(args[4].string, args[4].option)),
|
||||
key = CryptoJS.EvpKDF(passphrase, salt, { // lgtm [js/insufficient-password-hash]
|
||||
keySize: keySize,
|
||||
hasher: CryptoJS.algo[hasher],
|
||||
|
||||
84
src/core/operations/ExtractHashes.mjs
Normal file
84
src/core/operations/ExtractHashes.mjs
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @author mshwed [m@ttshwed.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract Hash Values operation
|
||||
*/
|
||||
class ExtractHashes extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractHashValues constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract hashes";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts potential hashes based on hash character length";
|
||||
this.infoURL = "https://en.wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Hash character length",
|
||||
type: "number",
|
||||
value: 40
|
||||
},
|
||||
{
|
||||
name: "All hashes",
|
||||
type: "boolean",
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "Display Total",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const results = [];
|
||||
let hashCount = 0;
|
||||
|
||||
const [hashLength, searchAllHashes, showDisplayTotal] = args;
|
||||
|
||||
// Convert character length to bit length
|
||||
let hashBitLengths = [(hashLength / 2) * 8];
|
||||
|
||||
if (searchAllHashes) hashBitLengths = [4, 8, 16, 32, 64, 128, 160, 192, 224, 256, 320, 384, 512, 1024];
|
||||
|
||||
for (const hashBitLength of hashBitLengths) {
|
||||
// Convert bit length to character length
|
||||
const hashCharacterLength = (hashBitLength / 8) * 2;
|
||||
|
||||
const regex = new RegExp(`(\\b|^)[a-f0-9]{${hashCharacterLength}}(\\b|$)`, "g");
|
||||
const searchResults = search(input, regex, null, false);
|
||||
|
||||
hashCount += searchResults.length;
|
||||
results.push(...searchResults);
|
||||
}
|
||||
|
||||
let output = "";
|
||||
if (showDisplayTotal) {
|
||||
output = `Total Results: ${hashCount}\n\n`;
|
||||
}
|
||||
|
||||
output = output + results.join("\n");
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractHashes;
|
||||
@@ -60,7 +60,7 @@ class FromBase58 extends Operation {
|
||||
run(input, args) {
|
||||
let alphabet = args[0] || ALPHABET_OPTIONS[0].value;
|
||||
const removeNonAlphaChars = args[1] === undefined ? true : args[1],
|
||||
result = [0];
|
||||
result = [];
|
||||
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
|
||||
@@ -87,11 +87,9 @@ class FromBase58 extends Operation {
|
||||
}
|
||||
}
|
||||
|
||||
let carry = result[0] * 58 + index;
|
||||
result[0] = carry & 0xFF;
|
||||
carry = carry >> 8;
|
||||
let carry = index;
|
||||
|
||||
for (let i = 1; i < result.length; i++) {
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
carry += result[i] * 58;
|
||||
result[i] = carry & 0xFF;
|
||||
carry = carry >> 8;
|
||||
|
||||
@@ -50,12 +50,7 @@ class JWTSign extends Operation {
|
||||
|
||||
try {
|
||||
return jwt.sign(input, key, {
|
||||
algorithm: algorithm === "None" ? "none" : algorithm,
|
||||
|
||||
// To utilize jsonwebtoken 9+ library and maintain backwards compatibility for regression tests
|
||||
// This could be turned into operation args in a future PR
|
||||
allowInsecureKeySizes: true,
|
||||
allowInvalidAsymmetricKeyTypes: true
|
||||
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.
|
||||
|
||||
273
src/core/operations/ParseCSR.mjs
Normal file
273
src/core/operations/ParseCSR.mjs
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* @author jkataja
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import forge from "node-forge";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Parse CSR operation
|
||||
*/
|
||||
class ParseCSR extends Operation {
|
||||
|
||||
/**
|
||||
* ParseCSR constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Parse CSR";
|
||||
this.module = "PublicKey";
|
||||
this.description = "Parse Certificate Signing Request (CSR) for an X.509 certificate";
|
||||
this.infoURL = "https://en.wikipedia.org/wiki/Certificate_signing_request";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": ["PEM"]
|
||||
},
|
||||
{
|
||||
"name": "Key type",
|
||||
"type": "option",
|
||||
"value": ["RSA"]
|
||||
},
|
||||
{
|
||||
"name": "Strict ASN.1 value lengths",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
"pattern": "^-+BEGIN CERTIFICATE REQUEST-+\\r?\\n[\\da-z+/\\n\\r]+-+END CERTIFICATE REQUEST-+\\r?\\n?$",
|
||||
"flags": "i",
|
||||
"args": ["PEM"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} Human-readable description of a Certificate Signing Request (CSR).
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input.length) {
|
||||
return "No input";
|
||||
}
|
||||
|
||||
const csr = forge.pki.certificationRequestFromPem(input, args[1]);
|
||||
|
||||
// RSA algorithm is the only one supported for CSR in node-forge as of 1.3.1
|
||||
return `Version: ${1 + csr.version} (0x${Utils.hex(csr.version)})
|
||||
Subject${formatSubject(csr.subject)}
|
||||
Subject Alternative Names${formatSubjectAlternativeNames(csr)}
|
||||
Public Key
|
||||
Algorithm: RSA
|
||||
Length: ${csr.publicKey.n.bitLength()} bits
|
||||
Modulus: ${formatMultiLine(chop(csr.publicKey.n.toString(16).replace(/(..)/g, "$&:")))}
|
||||
Exponent: ${csr.publicKey.e} (0x${Utils.hex(csr.publicKey.e)})
|
||||
Signature
|
||||
Algorithm: ${forge.pki.oids[csr.signatureOid]}
|
||||
Signature: ${formatMultiLine(Utils.strToByteArray(csr.signature).map(b => Utils.hex(b)).join(":"))}
|
||||
Extensions${formatExtensions(csr)}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Subject of the request as a multi-line string
|
||||
* @param {*} subject CSR Subject
|
||||
* @returns Multi-line string describing Subject
|
||||
*/
|
||||
function formatSubject(subject) {
|
||||
let out = "\n";
|
||||
|
||||
for (const attribute of subject.attributes) {
|
||||
out += ` ${attribute.shortName} = ${attribute.value}\n`;
|
||||
}
|
||||
|
||||
return chop(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format Subject Alternative Names from the name `subjectAltName` extension
|
||||
* @param {*} extension CSR object
|
||||
* @returns Multi-line string describing Subject Alternative Names
|
||||
*/
|
||||
function formatSubjectAlternativeNames(csr) {
|
||||
let out = "\n";
|
||||
|
||||
for (const attribute of csr.attributes) {
|
||||
for (const extension of attribute.extensions) {
|
||||
if (extension.name === "subjectAltName") {
|
||||
const names = [];
|
||||
for (const altName of extension.altNames) {
|
||||
switch (altName.type) {
|
||||
case 1:
|
||||
names.push(`EMAIL: ${altName.value}`);
|
||||
break;
|
||||
case 2:
|
||||
names.push(`DNS: ${altName.value}`);
|
||||
break;
|
||||
case 6:
|
||||
names.push(`URI: ${altName.value}`);
|
||||
break;
|
||||
case 7:
|
||||
names.push(`IP: ${altName.ip}`);
|
||||
break;
|
||||
default:
|
||||
names.push(`(unable to format type ${altName.type} name)\n`);
|
||||
}
|
||||
}
|
||||
out += indent(2, names);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chop(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format known extensions of a CSR
|
||||
* @param {*} csr CSR object
|
||||
* @returns Multi-line string describing attributes
|
||||
*/
|
||||
function formatExtensions(csr) {
|
||||
let out = "\n";
|
||||
|
||||
for (const attribute of csr.attributes) {
|
||||
for (const extension of attribute.extensions) {
|
||||
// formatted separately
|
||||
if (extension.name === "subjectAltName") {
|
||||
continue;
|
||||
}
|
||||
out += ` ${extension.name}${(extension.critical ? " CRITICAL" : "")}:\n`;
|
||||
let parts = [];
|
||||
switch (extension.name) {
|
||||
case "basicConstraints" :
|
||||
parts = describeBasicConstraints(extension);
|
||||
break;
|
||||
case "keyUsage" :
|
||||
parts = describeKeyUsage(extension);
|
||||
break;
|
||||
case "extKeyUsage" :
|
||||
parts = describeExtendedKeyUsage(extension);
|
||||
break;
|
||||
default :
|
||||
parts = ["(unable to format extension)"];
|
||||
}
|
||||
out += indent(4, parts);
|
||||
}
|
||||
}
|
||||
|
||||
return chop(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format hex string onto multiple lines
|
||||
* @param {*} longStr
|
||||
* @returns Hex string as a multi-line hex string
|
||||
*/
|
||||
function formatMultiLine(longStr) {
|
||||
const lines = [];
|
||||
|
||||
for (let remain = longStr ; remain !== "" ; remain = remain.substring(48)) {
|
||||
lines.push(remain.substring(0, 48));
|
||||
}
|
||||
|
||||
return lines.join("\n ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe Basic Constraints
|
||||
* @see RFC 5280 4.2.1.9. Basic Constraints https://www.ietf.org/rfc/rfc5280.txt
|
||||
* @param {*} extension CSR extension with the name `basicConstraints`
|
||||
* @returns Array of strings describing Basic Constraints
|
||||
*/
|
||||
function describeBasicConstraints(extension) {
|
||||
const constraints = [];
|
||||
|
||||
constraints.push(`CA = ${extension.cA}`);
|
||||
if (extension.pathLenConstraint !== undefined) constraints.push(`PathLenConstraint = ${extension.pathLenConstraint}`);
|
||||
|
||||
return constraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe Key Usage extension permitted use cases
|
||||
* @see RFC 5280 4.2.1.3. Key Usage https://www.ietf.org/rfc/rfc5280.txt
|
||||
* @param {*} extension CSR extension with the name `keyUsage`
|
||||
* @returns Array of strings describing Key Usage extension permitted use cases
|
||||
*/
|
||||
function describeKeyUsage(extension) {
|
||||
const usage = [];
|
||||
|
||||
if (extension.digitalSignature) usage.push("Digital signature");
|
||||
if (extension.nonRepudiation) usage.push("Non-repudiation");
|
||||
if (extension.keyEncipherment) usage.push("Key encipherment");
|
||||
if (extension.dataEncipherment) usage.push("Data encipherment");
|
||||
if (extension.keyAgreement) usage.push("Key agreement");
|
||||
if (extension.keyCertSign) usage.push("Key certificate signing");
|
||||
if (extension.cRLSign) usage.push("CRL signing");
|
||||
if (extension.encipherOnly) usage.push("Encipher only");
|
||||
if (extension.decipherOnly) usage.push("Decipher only");
|
||||
|
||||
if (usage.length === 0) usage.push("(none)");
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe Extended Key Usage extension permitted use cases
|
||||
* @see RFC 5280 4.2.1.12. Extended Key Usage https://www.ietf.org/rfc/rfc5280.txt
|
||||
* @param {*} extension CSR extension with the name `extendedKeyUsage`
|
||||
* @returns Array of strings describing Extended Key Usage extension permitted use cases
|
||||
*/
|
||||
function describeExtendedKeyUsage(extension) {
|
||||
const usage = [];
|
||||
|
||||
if (extension.serverAuth) usage.push("TLS Web Server Authentication");
|
||||
if (extension.clientAuth) usage.push("TLS Web Client Authentication");
|
||||
if (extension.codeSigning) usage.push("Code signing");
|
||||
if (extension.emailProtection) usage.push("E-mail Protection (S/MIME)");
|
||||
if (extension.timeStamping) usage.push("Trusted Timestamping");
|
||||
if (extension.msCodeInd) usage.push("Microsoft Individual Code Signing");
|
||||
if (extension.msCodeCom) usage.push("Microsoft Commercial Code Signing");
|
||||
if (extension.msCTLSign) usage.push("Microsoft Trust List Signing");
|
||||
if (extension.msSGC) usage.push("Microsoft Server Gated Crypto");
|
||||
if (extension.msEFS) usage.push("Microsoft Encrypted File System");
|
||||
if (extension.nsSGC) usage.push("Netscape Server Gated Crypto");
|
||||
|
||||
if (usage.length === 0) usage.push("(none)");
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join an array of strings and add leading spaces to each line.
|
||||
* @param {*} n How many leading spaces
|
||||
* @param {*} parts Array of strings
|
||||
* @returns Joined and indented string.
|
||||
*/
|
||||
function indent(n, parts) {
|
||||
const fluff = " ".repeat(n);
|
||||
return fluff + parts.join("\n" + fluff) + "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove last character from a string.
|
||||
* @param {*} s String
|
||||
* @returns Chopped string.
|
||||
*/
|
||||
function chop(s) {
|
||||
return s.substring(0, s.length - 1);
|
||||
}
|
||||
|
||||
export default ParseCSR;
|
||||
@@ -43,7 +43,7 @@ class ToBase58 extends Operation {
|
||||
run(input, args) {
|
||||
input = new Uint8Array(input);
|
||||
let alphabet = args[0] || ALPHABET_OPTIONS[0].value,
|
||||
result = [0];
|
||||
result = [];
|
||||
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
|
||||
@@ -60,11 +60,9 @@ class ToBase58 extends Operation {
|
||||
}
|
||||
|
||||
input.forEach(function(b) {
|
||||
let carry = (result[0] << 8) + b;
|
||||
result[0] = carry % 58;
|
||||
carry = (carry / 58) | 0;
|
||||
let carry = b;
|
||||
|
||||
for (let i = 1; i < result.length; i++) {
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
carry += result[i] << 8;
|
||||
result[i] = carry % 58;
|
||||
carry = (carry / 58) | 0;
|
||||
|
||||
@@ -126,8 +126,8 @@ module.exports = {
|
||||
// testOp(browser, "Extract email addresses", "test input", "test_output");
|
||||
// testOp(browser, "Extract file paths", "test input", "test_output");
|
||||
testOpFile(browser, "Extract Files", "files/Hitchhikers_Guide.jpeg", ".card:last-child .collapsed", "extracted_at_0x3d38.zlib");
|
||||
testOpFile(browser, "Extract ID3", "files/mp3example.mp3", "tr:last-child td:last-child", "Kevin MacLeod");
|
||||
// testOp(browser, "Extract IP addresses", "test input", "test_output");
|
||||
// This test seems unreliable on GitHub Actions, not reproducible locally.
|
||||
// testOpFile(browser, "Extract ID3", "files/mp3example.mp3", "tr:last-child td:last-child", "Kevin MacLeod"); // testOp(browser, "Extract IP addresses", "test input", "test_output");
|
||||
// testOp(browser, "Extract LSB", "test input", "test_output");
|
||||
// testOp(browser, "Extract MAC addresses", "test input", "test_output");
|
||||
// testOp(browser, "Extract RGBA", "test input", "test_output");
|
||||
|
||||
@@ -62,6 +62,7 @@ import "./tests/DefangIP.mjs";
|
||||
import "./tests/ELFInfo.mjs";
|
||||
import "./tests/Enigma.mjs";
|
||||
import "./tests/ExtractEmailAddresses.mjs";
|
||||
import "./tests/ExtractHashes.mjs";
|
||||
import "./tests/Float.mjs";
|
||||
import "./tests/FileTree.mjs";
|
||||
import "./tests/FletcherChecksum.mjs";
|
||||
@@ -147,6 +148,7 @@ import "./tests/Typex.mjs";
|
||||
import "./tests/UnescapeString.mjs";
|
||||
import "./tests/Unicode.mjs";
|
||||
import "./tests/YARA.mjs";
|
||||
import "./tests/ParseCSR.mjs";
|
||||
|
||||
const testStatus = {
|
||||
allTestsPassing: true,
|
||||
|
||||
@@ -53,6 +53,28 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base58 all null",
|
||||
input: "\0\0\0\0\0\0",
|
||||
expectedOutput: "111111",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base58",
|
||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base58 all null",
|
||||
input: "111111",
|
||||
expectedOutput: "\0\0\0\0\0\0",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base58",
|
||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base58 with null prefix and suffix",
|
||||
input: "\0\0\0Hello\0\0\0",
|
||||
|
||||
@@ -21,13 +21,16 @@ TestRegister.addTests([
|
||||
],
|
||||
},
|
||||
{
|
||||
// input taken from https://ciphersaber.gurus.org/
|
||||
name: "CipherSaber2 Decrypt",
|
||||
input: "\x5d\xd9\x7f\xeb\x77\x3c\x42\x9d\xfe\x9c\x3b\x21\x63\xbd\x53\x38\x18\x7c\x36\x37",
|
||||
expectedOutput: "helloworld",
|
||||
input: "\x6f\x6d\x0b\xab\xf3\xaa\x67\x19\x03\x15\x30\xed\xb6\x77" +
|
||||
"\xca\x74\xe0\x08\x9d\xd0\xe7\xb8\x85\x43\x56\xbb\x14\x48\xe3" +
|
||||
"\x7c\xdb\xef\xe7\xf3\xa8\x4f\x4f\x5f\xb3\xfd",
|
||||
expectedOutput: "This is a test of CipherSaber.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "CipherSaber2 Decrypt",
|
||||
args: [{ "option": "Latin1", "string": "test" }, 20],
|
||||
args: [{ "option": "Latin1", "string": "asdfg" }, 1],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -31,4 +31,26 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "DateTime Delta Positive",
|
||||
input: "20/02/2024 13:36:00",
|
||||
expectedOutput: "20/02/2024 13:37:00",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "DateTime Delta",
|
||||
args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "Add", 0, 0, 1, 0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "DateTime Delta Negative",
|
||||
input: "20/02/2024 14:37:00",
|
||||
expectedOutput: "20/02/2024 13:37:00",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "DateTime Delta",
|
||||
args: ["Standard date and time", "DD/MM/YYYY HH:mm:ss", "Subtract", 0, 1, 0, 0],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
77
tests/operations/tests/ExtractHashes.mjs
Normal file
77
tests/operations/tests/ExtractHashes.mjs
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* ExtractHashes tests.
|
||||
*
|
||||
* @author mshwed [m@ttshwed.com]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Extract MD5 hash",
|
||||
input: "The quick brown fox jumps over the lazy dog\n\nMD5: 9e107d9d372bb6826bd81d3542a419d6",
|
||||
expectedOutput: "9e107d9d372bb6826bd81d3542a419d6",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract hashes",
|
||||
"args": [32, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract SHA1 hash",
|
||||
input: "The quick brown fox jumps over the lazy dog\n\nSHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
|
||||
expectedOutput: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract hashes",
|
||||
"args": [40, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract SHA256 hash",
|
||||
input: "The quick brown fox jumps over the lazy dog\n\nSHA256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
expectedOutput: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract hashes",
|
||||
"args": [64, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract SHA512 hash",
|
||||
input: "The quick brown fox jumps over the lazy dog\n\nSHA512: 07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
|
||||
expectedOutput: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract hashes",
|
||||
"args": [128, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract all hashes",
|
||||
input: "The quick brown fox jumps over the lazy dog\n\nMD5: 9e107d9d372bb6826bd81d3542a419d6\nSHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nSHA256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
expectedOutput: "9e107d9d372bb6826bd81d3542a419d6\n2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract hashes",
|
||||
"args": [0, true, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract hashes with total count",
|
||||
input: "The quick brown fox jumps over the lazy dog\n\nMD5: 9e107d9d372bb6826bd81d3542a419d6\nSHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nSHA256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
expectedOutput: "Total Results: 3\n\n9e107d9d372bb6826bd81d3542a419d6\n2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\nd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract hashes",
|
||||
"args": [0, true, true]
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
215
tests/operations/tests/ParseCSR.mjs
Normal file
215
tests/operations/tests/ParseCSR.mjs
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Parse CSR tests.
|
||||
*
|
||||
* @author jkataja
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
// openssl req -newkey rsa:1024 -keyout test-rsa-1024.key -out test-rsa-1024.csr \
|
||||
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||
// -addext "extendedKeyUsage = serverAuth"
|
||||
const IN_EXAMPLE_COM_RSA_1024 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICHzCCAYgCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEF
|
||||
AAOBjQAwgYkCgYEArrTrLI6FkzjX8FZfclt2ox1Dz7KRwt5f6ffZic7twLAKJ4ao
|
||||
/H3APjwoFVUXGjiNj/XF2RlId4UxB1b6CgWjujBb9W51rTdvfWLyAHsrLcptpVz+
|
||||
V9Y8X9kEFCRGGDyG5+X+Nu6COzTpUPDj4bIIX/uPk3fDYDEqLClVy8/VS48CAwEA
|
||||
AaBtMGsGCSqGSIb3DQEJDjFeMFwwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3
|
||||
dy5leGFtcGxlLmNvbTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDATBgNV
|
||||
HSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOBgQB0mUlPgt6pt/kjD0pz
|
||||
OUNk5e9nBFQYQGuGIHGYbPX3mi4Wd9vUCdPixtPSTunHWs2cxX2nM8+MdcNTY+7Q
|
||||
NFgFNIvSXhbqMYoHAAApMHJOxiWpBFdYKp3tESnlgh2lUh7lQtmOjD4a1dzfU8PU
|
||||
oViyp+UJGasN2WRd+4VtaPw64w==
|
||||
-----END CERTIFICATE REQUEST-----`;
|
||||
|
||||
const OUT_EXAMPLE_COM_RSA_1024 = `Version: 1 (0x00)
|
||||
Subject
|
||||
C = CH
|
||||
ST = Zurich
|
||||
L = Zurich
|
||||
O = Example RE
|
||||
OU = IT Department
|
||||
CN = example.com
|
||||
Subject Alternative Names
|
||||
DNS: example.com
|
||||
DNS: www.example.com
|
||||
Public Key
|
||||
Algorithm: RSA
|
||||
Length: 1024 bits
|
||||
Modulus: ae:b4:eb:2c:8e:85:93:38:d7:f0:56:5f:72:5b:76:a3:
|
||||
1d:43:cf:b2:91:c2:de:5f:e9:f7:d9:89:ce:ed:c0:b0:
|
||||
0a:27:86:a8:fc:7d:c0:3e:3c:28:15:55:17:1a:38:8d:
|
||||
8f:f5:c5:d9:19:48:77:85:31:07:56:fa:0a:05:a3:ba:
|
||||
30:5b:f5:6e:75:ad:37:6f:7d:62:f2:00:7b:2b:2d:ca:
|
||||
6d:a5:5c:fe:57:d6:3c:5f:d9:04:14:24:46:18:3c:86:
|
||||
e7:e5:fe:36:ee:82:3b:34:e9:50:f0:e3:e1:b2:08:5f:
|
||||
fb:8f:93:77:c3:60:31:2a:2c:29:55:cb:cf:d5:4b:8f
|
||||
Exponent: 65537 (0x10001)
|
||||
Signature
|
||||
Algorithm: sha256WithRSAEncryption
|
||||
Signature: 74:99:49:4f:82:de:a9:b7:f9:23:0f:4a:73:39:43:64:
|
||||
e5:ef:67:04:54:18:40:6b:86:20:71:98:6c:f5:f7:9a:
|
||||
2e:16:77:db:d4:09:d3:e2:c6:d3:d2:4e:e9:c7:5a:cd:
|
||||
9c:c5:7d:a7:33:cf:8c:75:c3:53:63:ee:d0:34:58:05:
|
||||
34:8b:d2:5e:16:ea:31:8a:07:00:00:29:30:72:4e:c6:
|
||||
25:a9:04:57:58:2a:9d:ed:11:29:e5:82:1d:a5:52:1e:
|
||||
e5:42:d9:8e:8c:3e:1a:d5:dc:df:53:c3:d4:a1:58:b2:
|
||||
a7:e5:09:19:ab:0d:d9:64:5d:fb:85:6d:68:fc:3a:e3
|
||||
Extensions
|
||||
basicConstraints CRITICAL:
|
||||
CA = false
|
||||
keyUsage CRITICAL:
|
||||
Digital signature
|
||||
Key encipherment
|
||||
extKeyUsage:
|
||||
TLS Web Server Authentication`;
|
||||
|
||||
// openssl req -newkey rsa:2048 -keyout test-rsa-2048.key -out test-rsa-2048.csr \
|
||||
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||
// -addext "extendedKeyUsage = serverAuth"
|
||||
const IN_EXAMPLE_COM_RSA_2048 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDJDCCAgwCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
|
||||
BQADggEPADCCAQoCggEBAKPogLmWPuK/IGdct2v/3MFKVaVeKp2Hl5at/zDFLCAe
|
||||
51bwh7BqNVJEci4ApwlXA1WVmQPBFBJlYwQZVjz5UAN2CmNHxud5nV03YmZ2/Iml
|
||||
RzpKcZMPqU+liJCC04L+XIbOdx+Vz52dF++Cc+FuSFq803yW+qefK8JsJNO9KuPx
|
||||
RLYKSAADa9MIJisru1PzcBAOcimOmNnFWuo+LKsd4lU30OExDdKHwtyt62Mj1c3o
|
||||
lO1JjvkjtWWjwHI+0EgTjvkeXlcUYZvvLlysdKERMRozvMTGqqoHWCgWl+Rq9Z6P
|
||||
TgNsRO4CKug1Zwmh8y6acZ7sYb/dar8HOeqJnc0pCv8CAwEAAaBtMGsGCSqGSIb3
|
||||
DQEJDjFeMFwwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv
|
||||
bTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEF
|
||||
BQcDATANBgkqhkiG9w0BAQsFAAOCAQEAG0cjfRBY1pBzu+jf7yMQrK5mQrh72air
|
||||
VuXHmochmyUxyt0G7ovnNhKEr+X9snShJLi5qlyvnb2roiwlCmuwGIZxErN1svQL
|
||||
Z3kQNZgH+Vyu5IRL2DlPs5AAxVmzPpbnbXNhMHyAK/ziLcU031O1PoCpxwfvPsjW
|
||||
HWOCjbZUVaJnxdp8AHqImoGAiVhJwc37feFvb2UQlLedUypQkPg/poNWduaRDoj8
|
||||
m9cpVxuxGLtONBnohzohnFECytSXWEXPIj8L9SpYK97G02nJYYCAcb5BF11Alfux
|
||||
sNxtsr6zgPaLRrvOBT11WxJVKerbhfezAJ3naem1eM3VLxCGWwMwxg==
|
||||
-----END CERTIFICATE REQUEST-----`;
|
||||
|
||||
const OUT_EXAMPLE_COM_RSA_2048 = `Version: 1 (0x00)
|
||||
Subject
|
||||
C = CH
|
||||
ST = Zurich
|
||||
L = Zurich
|
||||
O = Example RE
|
||||
OU = IT Department
|
||||
CN = example.com
|
||||
Subject Alternative Names
|
||||
DNS: example.com
|
||||
DNS: www.example.com
|
||||
Public Key
|
||||
Algorithm: RSA
|
||||
Length: 2048 bits
|
||||
Modulus: a3:e8:80:b9:96:3e:e2:bf:20:67:5c:b7:6b:ff:dc:c1:
|
||||
4a:55:a5:5e:2a:9d:87:97:96:ad:ff:30:c5:2c:20:1e:
|
||||
e7:56:f0:87:b0:6a:35:52:44:72:2e:00:a7:09:57:03:
|
||||
55:95:99:03:c1:14:12:65:63:04:19:56:3c:f9:50:03:
|
||||
76:0a:63:47:c6:e7:79:9d:5d:37:62:66:76:fc:89:a5:
|
||||
47:3a:4a:71:93:0f:a9:4f:a5:88:90:82:d3:82:fe:5c:
|
||||
86:ce:77:1f:95:cf:9d:9d:17:ef:82:73:e1:6e:48:5a:
|
||||
bc:d3:7c:96:fa:a7:9f:2b:c2:6c:24:d3:bd:2a:e3:f1:
|
||||
44:b6:0a:48:00:03:6b:d3:08:26:2b:2b:bb:53:f3:70:
|
||||
10:0e:72:29:8e:98:d9:c5:5a:ea:3e:2c:ab:1d:e2:55:
|
||||
37:d0:e1:31:0d:d2:87:c2:dc:ad:eb:63:23:d5:cd:e8:
|
||||
94:ed:49:8e:f9:23:b5:65:a3:c0:72:3e:d0:48:13:8e:
|
||||
f9:1e:5e:57:14:61:9b:ef:2e:5c:ac:74:a1:11:31:1a:
|
||||
33:bc:c4:c6:aa:aa:07:58:28:16:97:e4:6a:f5:9e:8f:
|
||||
4e:03:6c:44:ee:02:2a:e8:35:67:09:a1:f3:2e:9a:71:
|
||||
9e:ec:61:bf:dd:6a:bf:07:39:ea:89:9d:cd:29:0a:ff
|
||||
Exponent: 65537 (0x10001)
|
||||
Signature
|
||||
Algorithm: sha256WithRSAEncryption
|
||||
Signature: 1b:47:23:7d:10:58:d6:90:73:bb:e8:df:ef:23:10:ac:
|
||||
ae:66:42:b8:7b:d9:a8:ab:56:e5:c7:9a:87:21:9b:25:
|
||||
31:ca:dd:06:ee:8b:e7:36:12:84:af:e5:fd:b2:74:a1:
|
||||
24:b8:b9:aa:5c:af:9d:bd:ab:a2:2c:25:0a:6b:b0:18:
|
||||
86:71:12:b3:75:b2:f4:0b:67:79:10:35:98:07:f9:5c:
|
||||
ae:e4:84:4b:d8:39:4f:b3:90:00:c5:59:b3:3e:96:e7:
|
||||
6d:73:61:30:7c:80:2b:fc:e2:2d:c5:34:df:53:b5:3e:
|
||||
80:a9:c7:07:ef:3e:c8:d6:1d:63:82:8d:b6:54:55:a2:
|
||||
67:c5:da:7c:00:7a:88:9a:81:80:89:58:49:c1:cd:fb:
|
||||
7d:e1:6f:6f:65:10:94:b7:9d:53:2a:50:90:f8:3f:a6:
|
||||
83:56:76:e6:91:0e:88:fc:9b:d7:29:57:1b:b1:18:bb:
|
||||
4e:34:19:e8:87:3a:21:9c:51:02:ca:d4:97:58:45:cf:
|
||||
22:3f:0b:f5:2a:58:2b:de:c6:d3:69:c9:61:80:80:71:
|
||||
be:41:17:5d:40:95:fb:b1:b0:dc:6d:b2:be:b3:80:f6:
|
||||
8b:46:bb:ce:05:3d:75:5b:12:55:29:ea:db:85:f7:b3:
|
||||
00:9d:e7:69:e9:b5:78:cd:d5:2f:10:86:5b:03:30:c6
|
||||
Extensions
|
||||
basicConstraints CRITICAL:
|
||||
CA = false
|
||||
keyUsage CRITICAL:
|
||||
Digital signature
|
||||
Key encipherment
|
||||
extKeyUsage:
|
||||
TLS Web Server Authentication`;
|
||||
|
||||
// openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out test-ec-param.pem
|
||||
// openssl req -newkey ec:test-ec-param.pem -keyout test-ec.key -out test-ec.csr \
|
||||
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||
// -addext "extendedKeyUsage = serverAuth"
|
||||
const IN_EXAMPLE_COM_EC = `-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBmzCCAUECAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG
|
||||
SM49AwEHA0IABAmpYXNh+L9E0Q3sLhrO+MF1XgKCfqJntrOyIkrGwoiQftHbJWTA
|
||||
6duxQhU/3d9B+SN/ibeKY+xeiNBrs2eTYZ6gbTBrBgkqhkiG9w0BCQ4xXjBcMCcG
|
||||
A1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb20wDAYDVR0TAQH/
|
||||
BAIwADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCgYIKoZI
|
||||
zj0EAwIDSAAwRQIgQkum/qaLzE3QZ3WD00uLpalUn113FObd7rM5Mr3HQwQCIQCr
|
||||
7OjzYI9v7qIJp/E9N16XfJN87G2ZVIZ4FuPXVjokCQ==
|
||||
-----END CERTIFICATE REQUEST-----`;
|
||||
|
||||
const OUT_EXAMPLE_COM_EC = `Parse CSR - Cannot read public key. OID is not RSA.`;
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Parse CSR: Example Certificate Signing Request (CSR) with RSA 1024",
|
||||
input: IN_EXAMPLE_COM_RSA_1024,
|
||||
expectedOutput: OUT_EXAMPLE_COM_RSA_1024,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse CSR",
|
||||
"args": ["PEM", true]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Parse CSR: Example Certificate Signing Request (CSR) with RSA 2048",
|
||||
input: IN_EXAMPLE_COM_RSA_2048,
|
||||
expectedOutput: OUT_EXAMPLE_COM_RSA_2048,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse CSR",
|
||||
"args": ["PEM", true]
|
||||
}
|
||||
]
|
||||
},
|
||||
// RSA algorithm is the only one supported for CSR in node-forge as of 1.3.1
|
||||
{
|
||||
name: "Parse CSR: Example Certificate Signing Request (CSR) with EC 256",
|
||||
input: IN_EXAMPLE_COM_EC,
|
||||
expectedError: true,
|
||||
expectedOutput: OUT_EXAMPLE_COM_EC,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse CSR",
|
||||
"args": ["PEM", true]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
Reference in New Issue
Block a user