mirror of
https://github.com/PretendoNetwork/SSSL.git
synced 2026-04-22 00:27:33 -05:00
update: make script interactive
This commit is contained in:
parent
f0923ce5a3
commit
e02d2b5a8c
130
package-lock.json
generated
130
package-lock.json
generated
|
|
@ -9,9 +9,63 @@
|
|||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"node-forge": "^1.3.1"
|
||||
"@colors/colors": "^1.6.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"prompt": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
|
||||
"integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
|
||||
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g=="
|
||||
},
|
||||
"node_modules/colors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||
"integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==",
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/cycle": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
|
||||
"integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eyes": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
|
||||
"integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==",
|
||||
"engines": {
|
||||
"node": "> 0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/mute-stream": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
|
|
@ -19,6 +73,80 @@
|
|||
"engines": {
|
||||
"node": ">= 6.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prompt": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/prompt/-/prompt-1.3.0.tgz",
|
||||
"integrity": "sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg==",
|
||||
"dependencies": {
|
||||
"@colors/colors": "1.5.0",
|
||||
"async": "3.2.3",
|
||||
"read": "1.0.x",
|
||||
"revalidator": "0.1.x",
|
||||
"winston": "2.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prompt/node_modules/@colors/colors": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
||||
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/read": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
|
||||
"integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
|
||||
"dependencies": {
|
||||
"mute-stream": "~0.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/revalidator": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz",
|
||||
"integrity": "sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/winston": {
|
||||
"version": "2.4.7",
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz",
|
||||
"integrity": "sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==",
|
||||
"dependencies": {
|
||||
"async": "^2.6.4",
|
||||
"colors": "1.0.x",
|
||||
"cycle": "1.0.x",
|
||||
"eyes": "0.1.x",
|
||||
"isstream": "0.1.x",
|
||||
"stack-trace": "0.0.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/winston/node_modules/async": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.14"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"node-forge": "^1.3.1"
|
||||
"@colors/colors": "^1.6.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"prompt": "^1.3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
158
patch.js
158
patch.js
|
|
@ -1,52 +1,130 @@
|
|||
const fs = require('node:fs');
|
||||
const crypto = require('node:crypto');
|
||||
const path = require('node:path');
|
||||
const { pki, md } = require('node-forge');
|
||||
const prompt = require('prompt');
|
||||
const colors = require("@colors/colors/safe");
|
||||
|
||||
// * Parse Nintendo CA - G3
|
||||
const nintendoCAG3PEM = fs.readFileSync('./CACERT_NINTENDO_CA_G3.pem')
|
||||
const nintendoCAG3 = pki.certificateFromPem(nintendoCAG3PEM);
|
||||
async function showPrompt() {
|
||||
prompt.message = colors.magenta('SSSL');
|
||||
|
||||
// * Generate a new key pair for the patched CA for condition 1
|
||||
const newKeyPair = pki.rsa.generateKeyPair(2048);
|
||||
const newCaPrivateKey = newKeyPair.privateKey;
|
||||
const newCaPubliceKey = newKeyPair.publicKey;
|
||||
prompt.start();
|
||||
|
||||
// * Patch Nintendo CA - G3 with our new keys
|
||||
const newCaCertificate = pki.createCertificate();
|
||||
const options = await prompt.get({
|
||||
properties: {
|
||||
nintendo_ca_g3_path: {
|
||||
description: colors.blue('Path to Nintendo CA - G3 (default to this directory)'),
|
||||
default: './CACERT_NINTENDO_CA_G3.pem'
|
||||
},
|
||||
private_key_path: {
|
||||
description: colors.blue('Path to certificate private key (will generate if not set)')
|
||||
},
|
||||
common_name: {
|
||||
description: colors.blue('CN (default *)'),
|
||||
default: '*'
|
||||
},
|
||||
output_folder_path: {
|
||||
description: colors.blue('Output folder (default to this directory)'),
|
||||
default: './'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
newCaCertificate.publicKey = newCaPubliceKey; // * Modify the public key to our user-controlled key
|
||||
newCaCertificate.serialNumber = nintendoCAG3.serialNumber;
|
||||
newCaCertificate.validity.notBefore = nintendoCAG3.validity.notBefore;
|
||||
newCaCertificate.validity.notAfter = nintendoCAG3.validity.notAfter;
|
||||
newCaCertificate.setIssuer(nintendoCAG3.subject.attributes);
|
||||
newCaCertificate.setSubject(nintendoCAG3.subject.attributes);
|
||||
newCaCertificate.setSubject([
|
||||
...nintendoCAG3.subject.attributes.filter(({ name }) => name !== 'commonName'), // * Remove old one
|
||||
{
|
||||
name: 'commonName',
|
||||
value: '*' // * This wouldn't work in normal CAs, but the Wii U accepts it!
|
||||
if (!fs.existsSync(options.nintendo_ca_g3_path)) {
|
||||
console.log(colors.bgRed('Invalid Nintendo CA - G3 path'));
|
||||
|
||||
showPrompt();
|
||||
|
||||
return;
|
||||
}
|
||||
]);
|
||||
newCaCertificate.setExtensions([
|
||||
...nintendoCAG3.extensions.filter(({ name }) => name !== 'authorityKeyIdentifier'), // * Remove old one
|
||||
{
|
||||
// * Set a new authority key identifier extension for condition 2
|
||||
// * node-forge has no docs for this extension. Taken from
|
||||
// * https://github.com/digitalbazaar/forge/blob/2bb97afb5058285ef09bcf1d04d6bd6b87cffd58/tests/unit/x509.js#L324-L329
|
||||
// * https://github.com/digitalbazaar/forge/blob/2bb97afb5058285ef09bcf1d04d6bd6b87cffd58/lib/x509.js#L2204-L2233
|
||||
name: 'authorityKeyIdentifier',
|
||||
keyIdentifier: crypto.randomBytes(16).toString('ascii'),
|
||||
authorityCertIssuer: nintendoCAG3.issuer,
|
||||
serialNumber: nintendoCAG3.serialNumber
|
||||
|
||||
if (options.private_key_path && !fs.existsSync(options.private_key_path)) {
|
||||
console.log(colors.bgRed('Invalid certificate private key path'));
|
||||
|
||||
showPrompt();
|
||||
|
||||
return;
|
||||
}
|
||||
]);
|
||||
|
||||
// * Self-sign the CA patched with the new private key
|
||||
newCaCertificate.sign(newCaPrivateKey, md.sha256.create()); // * sha256WithRSAEncryption
|
||||
if (!fs.existsSync(options.output_folder_path)) {
|
||||
console.log(colors.bgRed('Invalid output folder path'));
|
||||
|
||||
// * Save the new private key and patched CA
|
||||
const newCaPrivateKeyPem = pki.privateKeyToPem(newCaPrivateKey);
|
||||
const newCaCertificatePem = pki.certificateToPem(newCaCertificate);
|
||||
showPrompt();
|
||||
|
||||
fs.writeFileSync('./private-key.pem', newCaPrivateKeyPem, 'utf8');
|
||||
fs.writeFileSync('./patched-ca.pem', newCaCertificatePem, 'utf8');
|
||||
return;
|
||||
}
|
||||
|
||||
options.output_folder_path = path.resolve(options.output_folder_path);
|
||||
|
||||
try {
|
||||
patchCA(options);
|
||||
|
||||
|
||||
console.log(colors.green(`Wrote patched CA to ${options.output_folder_path}/patched-ca.pem`));
|
||||
console.log(colors.green(`Wrote private key to ${options.output_folder_path}/private-key.pem`));
|
||||
} catch (error) {
|
||||
console.log(colors.bgRed(`Error patching CA: ${error}`));
|
||||
|
||||
showPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
function patchCA(options) {
|
||||
// * Parse Nintendo CA - G3
|
||||
const nintendoCAG3PEM = fs.readFileSync(options.nintendo_ca_g3_path);
|
||||
const nintendoCAG3 = pki.certificateFromPem(nintendoCAG3PEM);
|
||||
|
||||
let privateKey;
|
||||
let publicKey;
|
||||
|
||||
if (options.private_key_path) {
|
||||
const privateKeyPEM = fs.readFileSync(options.private_key_path);
|
||||
privateKey = pki.privateKeyFromPem(privateKeyPEM);
|
||||
publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e);
|
||||
} else {
|
||||
const keyPair = pki.rsa.generateKeyPair(2048);
|
||||
|
||||
privateKey = keyPair.privateKey;
|
||||
publicKey = keyPair.publicKey;
|
||||
}
|
||||
|
||||
// * Patch Nintendo CA - G3 with our new keys and identifer
|
||||
const patchedCA = pki.createCertificate();
|
||||
|
||||
patchedCA.publicKey = publicKey; // * Condition 1, set a new CA public key
|
||||
patchedCA.serialNumber = nintendoCAG3.serialNumber;
|
||||
patchedCA.validity.notBefore = nintendoCAG3.validity.notBefore; // TODO - Make this configurable?
|
||||
patchedCA.validity.notAfter = nintendoCAG3.validity.notAfter; // TODO - Make this configurable?
|
||||
patchedCA.setIssuer(nintendoCAG3.subject.attributes);
|
||||
patchedCA.setSubject(nintendoCAG3.subject.attributes);
|
||||
patchedCA.setSubject([
|
||||
...nintendoCAG3.subject.attributes.filter(({ name }) => name !== 'commonName'), // * Remove old one
|
||||
{
|
||||
name: 'commonName',
|
||||
value: options.common_name
|
||||
}
|
||||
]);
|
||||
patchedCA.setExtensions([
|
||||
...nintendoCAG3.extensions.filter(({ name }) => name !== 'authorityKeyIdentifier'), // * Remove old one
|
||||
{
|
||||
// * Condition 2, set a new authority key identifier extension
|
||||
// *
|
||||
// * node-forge has no docs for this extension. Taken from
|
||||
// * https://github.com/digitalbazaar/forge/blob/2bb97afb5058285ef09bcf1d04d6bd6b87cffd58/tests/unit/x509.js#L324-L329
|
||||
// * https://github.com/digitalbazaar/forge/blob/2bb97afb5058285ef09bcf1d04d6bd6b87cffd58/lib/x509.js#L2204-L2233
|
||||
name: 'authorityKeyIdentifier',
|
||||
keyIdentifier: crypto.randomBytes(16).toString('ascii'),
|
||||
authorityCertIssuer: nintendoCAG3.issuer,
|
||||
serialNumber: nintendoCAG3.serialNumber
|
||||
}
|
||||
]);
|
||||
|
||||
// * Self-sign the CA patched with the private key
|
||||
patchedCA.sign(privateKey, md.sha256.create()); // * sha256WithRSAEncryption
|
||||
|
||||
// * Save the private key and patched CA
|
||||
fs.writeFileSync(`${options.output_folder_path}/patched-ca.pem`, pki.certificateToPem(patchedCA), 'utf8');
|
||||
fs.writeFileSync(`${options.output_folder_path}/private-key.pem`, pki.privateKeyToPem(privateKey), 'utf8');
|
||||
}
|
||||
|
||||
showPrompt();
|
||||
Loading…
Reference in New Issue
Block a user